aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-09-10 02:27:12 -0400
committerJames Morris <jmorris@namei.org>2011-09-13 18:27:07 -0400
commita8f7640963ada66c412314c3559c11ff6946c1a5 (patch)
tree23d9fb5fe64bb431b610deb6c1b696356106f94d /security/tomoyo
parent731d37aa70c7b9de3be6bf2c8287366223bf5ce5 (diff)
TOMOYO: Avoid race when retrying "file execute" permission check.
There was a race window that the pathname which is subjected to "file execute" permission check when retrying via supervisor's decision because the pathname was recalculated upon retry. Though, there is an inevitable race window even without supervisor, for we have to calculate the symbolic link's pathname from "struct linux_binprm"->filename rather than from "struct linux_binprm"->file because we cannot back calculate the symbolic link's pathname from the dereferenced pathname. 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')
-rw-r--r--security/tomoyo/domain.c56
1 files changed, 22 insertions, 34 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 498fea732f48..a1fc6b5f6125 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -664,9 +664,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
664 struct tomoyo_domain_info *domain = NULL; 664 struct tomoyo_domain_info *domain = NULL;
665 const char *original_name = bprm->filename; 665 const char *original_name = bprm->filename;
666 int retval = -ENOMEM; 666 int retval = -ENOMEM;
667 bool need_kfree = false;
668 bool reject_on_transition_failure = false; 667 bool reject_on_transition_failure = false;
669 struct tomoyo_path_info rn = { }; /* real name */ 668 const struct tomoyo_path_info *candidate;
669 struct tomoyo_path_info exename;
670 struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); 670 struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
671 671
672 if (!ee) 672 if (!ee)
@@ -682,40 +682,33 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
682 ee->bprm = bprm; 682 ee->bprm = bprm;
683 ee->r.obj = &ee->obj; 683 ee->r.obj = &ee->obj;
684 ee->obj.path1 = bprm->file->f_path; 684 ee->obj.path1 = bprm->file->f_path;
685 retry:
686 if (need_kfree) {
687 kfree(rn.name);
688 need_kfree = false;
689 }
690 /* Get symlink's pathname of program. */ 685 /* Get symlink's pathname of program. */
691 retval = -ENOENT; 686 retval = -ENOENT;
692 rn.name = tomoyo_realpath_nofollow(original_name); 687 exename.name = tomoyo_realpath_nofollow(original_name);
693 if (!rn.name) 688 if (!exename.name)
694 goto out; 689 goto out;
695 tomoyo_fill_path_info(&rn); 690 tomoyo_fill_path_info(&exename);
696 need_kfree = true; 691retry:
697
698 /* Check 'aggregator' directive. */ 692 /* Check 'aggregator' directive. */
699 { 693 {
700 struct tomoyo_aggregator *ptr; 694 struct tomoyo_aggregator *ptr;
701 struct list_head *list = 695 struct list_head *list =
702 &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; 696 &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
703 /* Check 'aggregator' directive. */ 697 /* Check 'aggregator' directive. */
698 candidate = &exename;
704 list_for_each_entry_rcu(ptr, list, head.list) { 699 list_for_each_entry_rcu(ptr, list, head.list) {
705 if (ptr->head.is_deleted || 700 if (ptr->head.is_deleted ||
706 !tomoyo_path_matches_pattern(&rn, 701 !tomoyo_path_matches_pattern(&exename,
707 ptr->original_name)) 702 ptr->original_name))
708 continue; 703 continue;
709 kfree(rn.name); 704 candidate = ptr->aggregated_name;
710 need_kfree = false;
711 /* This is OK because it is read only. */
712 rn = *ptr->aggregated_name;
713 break; 705 break;
714 } 706 }
715 } 707 }
716 708
717 /* Check execute permission. */ 709 /* Check execute permission. */
718 retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); 710 retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE,
711 candidate);
719 if (retval == TOMOYO_RETRY_REQUEST) 712 if (retval == TOMOYO_RETRY_REQUEST)
720 goto retry; 713 goto retry;
721 if (retval < 0) 714 if (retval < 0)
@@ -726,20 +719,16 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
726 * wildcard) rather than the pathname passed to execve() 719 * wildcard) rather than the pathname passed to execve()
727 * (which never contains wildcard). 720 * (which never contains wildcard).
728 */ 721 */
729 if (ee->r.param.path.matched_path) { 722 if (ee->r.param.path.matched_path)
730 if (need_kfree) 723 candidate = ee->r.param.path.matched_path;
731 kfree(rn.name);
732 need_kfree = false;
733 /* This is OK because it is read only. */
734 rn = *ee->r.param.path.matched_path;
735 }
736 724
737 /* Calculate domain to transit to. */ 725 /* Calculate domain to transit to. */
738 switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, 726 switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
739 &rn)) { 727 candidate)) {
740 case TOMOYO_TRANSITION_CONTROL_RESET: 728 case TOMOYO_TRANSITION_CONTROL_RESET:
741 /* Transit to the root of specified namespace. */ 729 /* Transit to the root of specified namespace. */
742 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); 730 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
731 candidate->name);
743 /* 732 /*
744 * Make do_execve() fail if domain transition across namespaces 733 * Make do_execve() fail if domain transition across namespaces
745 * has failed. 734 * has failed.
@@ -749,7 +738,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
749 case TOMOYO_TRANSITION_CONTROL_INITIALIZE: 738 case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
750 /* Transit to the child of current namespace's root. */ 739 /* Transit to the child of current namespace's root. */
751 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", 740 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
752 old_domain->ns->name, rn.name); 741 old_domain->ns->name, candidate->name);
753 break; 742 break;
754 case TOMOYO_TRANSITION_CONTROL_KEEP: 743 case TOMOYO_TRANSITION_CONTROL_KEEP:
755 /* Keep current domain. */ 744 /* Keep current domain. */
@@ -765,11 +754,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
765 * before /sbin/init. 754 * before /sbin/init.
766 */ 755 */
767 domain = old_domain; 756 domain = old_domain;
768 } else { 757 break;
769 /* Normal domain transition. */
770 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
771 old_domain->domainname->name, rn.name);
772 } 758 }
759 /* Normal domain transition. */
760 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
761 old_domain->domainname->name, candidate->name);
773 break; 762 break;
774 } 763 }
775 if (!domain) 764 if (!domain)
@@ -799,8 +788,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
799 /* Update reference count on "struct tomoyo_domain_info". */ 788 /* Update reference count on "struct tomoyo_domain_info". */
800 atomic_inc(&domain->users); 789 atomic_inc(&domain->users);
801 bprm->cred->security = domain; 790 bprm->cred->security = domain;
802 if (need_kfree) 791 kfree(exename.name);
803 kfree(rn.name);
804 if (!retval) { 792 if (!retval) {
805 ee->r.domain = domain; 793 ee->r.domain = domain;
806 retval = tomoyo_environ(ee); 794 retval = tomoyo_environ(ee);