diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2011-09-10 02:22:48 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-09-13 18:27:05 -0400 |
commit | d58e0da854376841ac99defeb117a83f086715c6 (patch) | |
tree | b6e37d1030180680a7801ecb295d8d3990930375 /security/tomoyo/domain.c | |
parent | 5dbe3040c74eef18e66951347eda05b153e69328 (diff) |
TOMOYO: Add environment variable name restriction support.
This patch adds support for checking environment variable's names.
Although TOMOYO already provides ability to check argv[]/envp[] passed to
execve() requests,
file execute /bin/sh exec.envp["LD_LIBRARY_PATH"]="bar"
will reject execution of /bin/sh if environment variable LD_LIBRARY_PATH is not
defined. To grant execution of /bin/sh if LD_LIBRARY_PATH is not defined,
administrators have to specify like
file execute /bin/sh exec.envp["LD_LIBRARY_PATH"]="/system/lib"
file execute /bin/sh exec.envp["LD_LIBRARY_PATH"]=NULL
. Since there are many environment variables whereas conditional checks are
applied as "&&", it is difficult to cover all combinations. Therefore, this
patch supports conditional checks that are applied as "||", by specifying like
file execute /bin/sh
misc env LD_LIBRARY_PATH exec.envp["LD_LIBRARY_PATH"]="/system/lib"
which means "grant execution of /bin/sh if environment variable is not defined
or is defined and its value is /system/lib".
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/domain.c')
-rw-r--r-- | security/tomoyo/domain.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index cd0f92d88bb4..5931fb1c04d5 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -563,6 +563,92 @@ out: | |||
563 | } | 563 | } |
564 | 564 | ||
565 | /** | 565 | /** |
566 | * tomoyo_environ - Check permission for environment variable names. | ||
567 | * | ||
568 | * @ee: Pointer to "struct tomoyo_execve". | ||
569 | * | ||
570 | * Returns 0 on success, negative value otherwise. | ||
571 | */ | ||
572 | static int tomoyo_environ(struct tomoyo_execve *ee) | ||
573 | { | ||
574 | struct tomoyo_request_info *r = &ee->r; | ||
575 | struct linux_binprm *bprm = ee->bprm; | ||
576 | /* env_page.data is allocated by tomoyo_dump_page(). */ | ||
577 | struct tomoyo_page_dump env_page = { }; | ||
578 | char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */ | ||
579 | int arg_len = 0; | ||
580 | unsigned long pos = bprm->p; | ||
581 | int offset = pos % PAGE_SIZE; | ||
582 | int argv_count = bprm->argc; | ||
583 | int envp_count = bprm->envc; | ||
584 | int error = -ENOMEM; | ||
585 | |||
586 | ee->r.type = TOMOYO_MAC_ENVIRON; | ||
587 | ee->r.profile = r->domain->profile; | ||
588 | ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile, | ||
589 | TOMOYO_MAC_ENVIRON); | ||
590 | if (!r->mode || !envp_count) | ||
591 | return 0; | ||
592 | arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | ||
593 | if (!arg_ptr) | ||
594 | goto out; | ||
595 | while (error == -ENOMEM) { | ||
596 | if (!tomoyo_dump_page(bprm, pos, &env_page)) | ||
597 | goto out; | ||
598 | pos += PAGE_SIZE - offset; | ||
599 | /* Read. */ | ||
600 | while (argv_count && offset < PAGE_SIZE) { | ||
601 | if (!env_page.data[offset++]) | ||
602 | argv_count--; | ||
603 | } | ||
604 | if (argv_count) { | ||
605 | offset = 0; | ||
606 | continue; | ||
607 | } | ||
608 | while (offset < PAGE_SIZE) { | ||
609 | const unsigned char c = env_page.data[offset++]; | ||
610 | |||
611 | if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { | ||
612 | if (c == '=') { | ||
613 | arg_ptr[arg_len++] = '\0'; | ||
614 | } else if (c == '\\') { | ||
615 | arg_ptr[arg_len++] = '\\'; | ||
616 | arg_ptr[arg_len++] = '\\'; | ||
617 | } else if (c > ' ' && c < 127) { | ||
618 | arg_ptr[arg_len++] = c; | ||
619 | } else { | ||
620 | arg_ptr[arg_len++] = '\\'; | ||
621 | arg_ptr[arg_len++] = (c >> 6) + '0'; | ||
622 | arg_ptr[arg_len++] | ||
623 | = ((c >> 3) & 7) + '0'; | ||
624 | arg_ptr[arg_len++] = (c & 7) + '0'; | ||
625 | } | ||
626 | } else { | ||
627 | arg_ptr[arg_len] = '\0'; | ||
628 | } | ||
629 | if (c) | ||
630 | continue; | ||
631 | if (tomoyo_env_perm(r, arg_ptr)) { | ||
632 | error = -EPERM; | ||
633 | break; | ||
634 | } | ||
635 | if (!--envp_count) { | ||
636 | error = 0; | ||
637 | break; | ||
638 | } | ||
639 | arg_len = 0; | ||
640 | } | ||
641 | offset = 0; | ||
642 | } | ||
643 | out: | ||
644 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
645 | error = 0; | ||
646 | kfree(env_page.data); | ||
647 | kfree(arg_ptr); | ||
648 | return error; | ||
649 | } | ||
650 | |||
651 | /** | ||
566 | * tomoyo_find_next_domain - Find a domain. | 652 | * tomoyo_find_next_domain - Find a domain. |
567 | * | 653 | * |
568 | * @bprm: Pointer to "struct linux_binprm". | 654 | * @bprm: Pointer to "struct linux_binprm". |
@@ -581,6 +667,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
581 | bool reject_on_transition_failure = false; | 667 | bool reject_on_transition_failure = false; |
582 | struct tomoyo_path_info rn = { }; /* real name */ | 668 | struct tomoyo_path_info rn = { }; /* real name */ |
583 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); | 669 | struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); |
670 | |||
584 | if (!ee) | 671 | if (!ee) |
585 | return -ENOMEM; | 672 | return -ENOMEM; |
586 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | 673 | ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
@@ -713,6 +800,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
713 | bprm->cred->security = domain; | 800 | bprm->cred->security = domain; |
714 | if (need_kfree) | 801 | if (need_kfree) |
715 | kfree(rn.name); | 802 | kfree(rn.name); |
803 | if (!retval) { | ||
804 | ee->r.domain = domain; | ||
805 | retval = tomoyo_environ(ee); | ||
806 | } | ||
716 | kfree(ee->tmp); | 807 | kfree(ee->tmp); |
717 | kfree(ee->dump.data); | 808 | kfree(ee->dump.data); |
718 | kfree(ee); | 809 | kfree(ee); |
@@ -732,7 +823,8 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, | |||
732 | struct tomoyo_page_dump *dump) | 823 | struct tomoyo_page_dump *dump) |
733 | { | 824 | { |
734 | struct page *page; | 825 | struct page *page; |
735 | /* dump->data is released by tomoyo_finish_execve(). */ | 826 | |
827 | /* dump->data is released by tomoyo_find_next_domain(). */ | ||
736 | if (!dump->data) { | 828 | if (!dump->data) { |
737 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); | 829 | dump->data = kzalloc(PAGE_SIZE, GFP_NOFS); |
738 | if (!dump->data) | 830 | if (!dump->data) |
@@ -753,6 +845,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, | |||
753 | * So do I. | 845 | * So do I. |
754 | */ | 846 | */ |
755 | char *kaddr = kmap_atomic(page, KM_USER0); | 847 | char *kaddr = kmap_atomic(page, KM_USER0); |
848 | |||
756 | dump->page = page; | 849 | dump->page = page; |
757 | memcpy(dump->data + offset, kaddr + offset, | 850 | memcpy(dump->data + offset, kaddr + offset, |
758 | PAGE_SIZE - offset); | 851 | PAGE_SIZE - offset); |