提交 a8f76409 编写于 作者: T Tetsuo Handa 提交者: James Morris

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: NTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: NJames Morris <jmorris@namei.org>
上级 731d37aa
...@@ -664,9 +664,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -664,9 +664,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
struct tomoyo_domain_info *domain = NULL; struct tomoyo_domain_info *domain = NULL;
const char *original_name = bprm->filename; const char *original_name = bprm->filename;
int retval = -ENOMEM; int retval = -ENOMEM;
bool need_kfree = false;
bool reject_on_transition_failure = false; bool reject_on_transition_failure = false;
struct tomoyo_path_info rn = { }; /* real name */ const struct tomoyo_path_info *candidate;
struct tomoyo_path_info exename;
struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS); struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
if (!ee) if (!ee)
...@@ -682,40 +682,33 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -682,40 +682,33 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
ee->bprm = bprm; ee->bprm = bprm;
ee->r.obj = &ee->obj; ee->r.obj = &ee->obj;
ee->obj.path1 = bprm->file->f_path; ee->obj.path1 = bprm->file->f_path;
retry:
if (need_kfree) {
kfree(rn.name);
need_kfree = false;
}
/* Get symlink's pathname of program. */ /* Get symlink's pathname of program. */
retval = -ENOENT; retval = -ENOENT;
rn.name = tomoyo_realpath_nofollow(original_name); exename.name = tomoyo_realpath_nofollow(original_name);
if (!rn.name) if (!exename.name)
goto out; goto out;
tomoyo_fill_path_info(&rn); tomoyo_fill_path_info(&exename);
need_kfree = true; retry:
/* Check 'aggregator' directive. */ /* Check 'aggregator' directive. */
{ {
struct tomoyo_aggregator *ptr; struct tomoyo_aggregator *ptr;
struct list_head *list = struct list_head *list =
&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR]; &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
/* Check 'aggregator' directive. */ /* Check 'aggregator' directive. */
candidate = &exename;
list_for_each_entry_rcu(ptr, list, head.list) { list_for_each_entry_rcu(ptr, list, head.list) {
if (ptr->head.is_deleted || if (ptr->head.is_deleted ||
!tomoyo_path_matches_pattern(&rn, !tomoyo_path_matches_pattern(&exename,
ptr->original_name)) ptr->original_name))
continue; continue;
kfree(rn.name); candidate = ptr->aggregated_name;
need_kfree = false;
/* This is OK because it is read only. */
rn = *ptr->aggregated_name;
break; break;
} }
} }
/* Check execute permission. */ /* Check execute permission. */
retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn); retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE,
candidate);
if (retval == TOMOYO_RETRY_REQUEST) if (retval == TOMOYO_RETRY_REQUEST)
goto retry; goto retry;
if (retval < 0) if (retval < 0)
...@@ -726,20 +719,16 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -726,20 +719,16 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* wildcard) rather than the pathname passed to execve() * wildcard) rather than the pathname passed to execve()
* (which never contains wildcard). * (which never contains wildcard).
*/ */
if (ee->r.param.path.matched_path) { if (ee->r.param.path.matched_path)
if (need_kfree) candidate = ee->r.param.path.matched_path;
kfree(rn.name);
need_kfree = false;
/* This is OK because it is read only. */
rn = *ee->r.param.path.matched_path;
}
/* Calculate domain to transit to. */ /* Calculate domain to transit to. */
switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname, switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
&rn)) { candidate)) {
case TOMOYO_TRANSITION_CONTROL_RESET: case TOMOYO_TRANSITION_CONTROL_RESET:
/* Transit to the root of specified namespace. */ /* Transit to the root of specified namespace. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name); snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
candidate->name);
/* /*
* Make do_execve() fail if domain transition across namespaces * Make do_execve() fail if domain transition across namespaces
* has failed. * has failed.
...@@ -749,7 +738,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -749,7 +738,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
case TOMOYO_TRANSITION_CONTROL_INITIALIZE: case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
/* Transit to the child of current namespace's root. */ /* Transit to the child of current namespace's root. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->ns->name, rn.name); old_domain->ns->name, candidate->name);
break; break;
case TOMOYO_TRANSITION_CONTROL_KEEP: case TOMOYO_TRANSITION_CONTROL_KEEP:
/* Keep current domain. */ /* Keep current domain. */
...@@ -765,11 +754,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -765,11 +754,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* before /sbin/init. * before /sbin/init.
*/ */
domain = old_domain; domain = old_domain;
} else { break;
/* Normal domain transition. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->domainname->name, rn.name);
} }
/* Normal domain transition. */
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
old_domain->domainname->name, candidate->name);
break; break;
} }
if (!domain) if (!domain)
...@@ -799,8 +788,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -799,8 +788,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
/* Update reference count on "struct tomoyo_domain_info". */ /* Update reference count on "struct tomoyo_domain_info". */
atomic_inc(&domain->users); atomic_inc(&domain->users);
bprm->cred->security = domain; bprm->cred->security = domain;
if (need_kfree) kfree(exename.name);
kfree(rn.name);
if (!retval) { if (!retval) {
ee->r.domain = domain; ee->r.domain = domain;
retval = tomoyo_environ(ee); retval = tomoyo_environ(ee);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册