userns: Kill task_user_ns
The task_user_ns function hides the fact that it is getting the user namespace from struct cred on the task. struct cred may go away as soon as the rcu lock is released. This leads to a race where we can dereference a stale user namespace pointer. To make it obvious a struct cred is involved kill task_user_ns. To kill the race modify the users of task_user_ns to only reference the user namespace while the rcu lock is held. Cc: Kees Cook <keescook@chromium.org> Cc: James Morris <james.l.morris@oracle.com> Acked-by: Kees Cook <keescook@chromium.org> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
parent
bcf58e725d
commit
4c44aaafa8
|
@ -357,10 +357,8 @@ static inline void put_cred(const struct cred *_cred)
|
|||
extern struct user_namespace init_user_ns;
|
||||
#ifdef CONFIG_USER_NS
|
||||
#define current_user_ns() (current_cred_xxx(user_ns))
|
||||
#define task_user_ns(task) (task_cred_xxx((task), user_ns))
|
||||
#else
|
||||
#define current_user_ns() (&init_user_ns)
|
||||
#define task_user_ns(task) (&init_user_ns)
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -215,8 +215,12 @@ ok:
|
|||
smp_rmb();
|
||||
if (task->mm)
|
||||
dumpable = get_dumpable(task->mm);
|
||||
if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode))
|
||||
rcu_read_lock();
|
||||
if (!dumpable && !ptrace_has_cap(__task_cred(task)->user_ns, mode)) {
|
||||
rcu_read_unlock();
|
||||
return -EPERM;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return security_ptrace_access_check(task, mode);
|
||||
}
|
||||
|
@ -280,8 +284,10 @@ static int ptrace_attach(struct task_struct *task, long request,
|
|||
|
||||
if (seize)
|
||||
flags |= PT_SEIZED;
|
||||
if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE))
|
||||
rcu_read_lock();
|
||||
if (ns_capable(__task_cred(task)->user_ns, CAP_SYS_PTRACE))
|
||||
flags |= PT_PTRACE_CAP;
|
||||
rcu_read_unlock();
|
||||
task->ptrace = flags;
|
||||
|
||||
__ptrace_link(task, current);
|
||||
|
|
|
@ -4029,8 +4029,14 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
|
|||
goto out_free_cpus_allowed;
|
||||
}
|
||||
retval = -EPERM;
|
||||
if (!check_same_owner(p) && !ns_capable(task_user_ns(p), CAP_SYS_NICE))
|
||||
goto out_unlock;
|
||||
if (!check_same_owner(p)) {
|
||||
rcu_read_lock();
|
||||
if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) {
|
||||
rcu_read_unlock();
|
||||
goto out_unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
retval = security_task_setscheduler(p);
|
||||
if (retval)
|
||||
|
|
|
@ -262,14 +262,18 @@ int yama_ptrace_access_check(struct task_struct *child,
|
|||
/* No additional restrictions. */
|
||||
break;
|
||||
case YAMA_SCOPE_RELATIONAL:
|
||||
rcu_read_lock();
|
||||
if (!task_is_descendant(current, child) &&
|
||||
!ptracer_exception_found(current, child) &&
|
||||
!ns_capable(task_user_ns(child), CAP_SYS_PTRACE))
|
||||
!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
|
||||
rc = -EPERM;
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case YAMA_SCOPE_CAPABILITY:
|
||||
if (!ns_capable(task_user_ns(child), CAP_SYS_PTRACE))
|
||||
rcu_read_lock();
|
||||
if (!ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE))
|
||||
rc = -EPERM;
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case YAMA_SCOPE_NO_ATTACH:
|
||||
default:
|
||||
|
@ -307,8 +311,10 @@ int yama_ptrace_traceme(struct task_struct *parent)
|
|||
/* Only disallow PTRACE_TRACEME on more aggressive settings. */
|
||||
switch (ptrace_scope) {
|
||||
case YAMA_SCOPE_CAPABILITY:
|
||||
if (!ns_capable(task_user_ns(parent), CAP_SYS_PTRACE))
|
||||
rcu_read_lock();
|
||||
if (!ns_capable(__task_cred(parent)->user_ns, CAP_SYS_PTRACE))
|
||||
rc = -EPERM;
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case YAMA_SCOPE_NO_ATTACH:
|
||||
rc = -EPERM;
|
||||
|
|
Loading…
Reference in New Issue