Patch "mm: Add a user_ns owner to mm_struct and fix ptrace permission checks" has been added to the 4.8-stable tree
Subsystems (6)
This is a note to let you know that I've just added the patch titled
mm: Add a user_ns owner to mm_struct and fix ptrace permission checks
to the 4.8-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
mm-add-a-user_ns-owner-to-mm_struct-and-fix-ptrace-permission-checks.patch
and it can be found in the queue-4.8 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
bfedb589252c01fa505ac9f6f2a3d5d68d707ef4Mon Sep 17 00:00:00 2001
From: "Eric W. Biederman" <[email protected]>
Date: Thu, 13 Oct 2016 21:23:16 -0500
Subject: mm: Add a user_ns owner to mm_struct and fix ptrace permission checks
From: Eric W. Biederman <[email protected]>
commit bfedb589252c01fa505ac9f6f2a3d5d68d707ef4 upstream.
During exec dumpable is cleared if the file that is being executed is not readable by the user executing the file. A bug in ptrace_may_access allows reading the file if the executable happens to enter into a subordinate user namespace (aka clone(CLONE_NEWUSER), unshare(CLONE_NEWUSER), or setns(fd, CLONE_NEWUSER).
This problem is fixed with only necessary userspace breakage by adding a user namespace owner to mm_struct, captured at the time of exec, so it is clear in which user namespace CAP_SYS_PTRACE must be present in to be able to safely give read permission to the executable.
The function ptrace_may_access is modified to verify that the ptracer has CAP_SYS_ADMIN in task->mm->user_ns instead of task->cred->user_ns. This ensures that if the task changes it's cred into a subordinate user namespace it does not become ptraceable.
The function ptrace_attach is modified to only set PT_PTRACE_CAP when CAP_SYS_PTRACE is held over task->mm->user_ns. The intent of PT_PTRACE_CAP is to be a flag to note that whatever permission changes the task might go through the tracer has sufficient permissions for it not to be an issue. task->cred->user_ns is always the same as or descendent of mm->user_ns. Which guarantees that having CAP_SYS_PTRACE over mm->user_ns is the worst case for the tasks credentials.
To prevent regressions mm->dumpable and mm->user_ns are not considered when a task has no mm. As simply failing ptrace_may_attach causes regressions in privileged applications attempting to read things such as /proc/<pid>/stat
--- include/linux/mm_types.h | 1 + kernel/fork.c | 9 ++++++--- kernel/ptrace.c | 26 +++++++++++--------------- mm/init-mm.c | 2 ++ 4 files changed, 20 insertions(+), 18 deletions(-)
include/linux/mm_types.h +1 -0
@@ -473,6 +473,7 @@ struct mm_struct {*/ struct task_struct __rcu *owner;#endif +struct user_namespace *user_ns;/* store ref to file /proc/<pid>/exe symlink points to */ struct file __rcu *exe_file;
kernel/fork.c +6 -3
@@ -598,7 +598,8 @@ static void mm_init_owner(struct mm_stru#endif } -static struct mm_struct *mm_init (struct mm_struct *mm,struct task_struct *p) +static struct mm_struct *mm_init (struct mm_struct *mm,struct task_struct *p, +struct user_namespace *user_ns) { mm->mmap =NULL ; mm->mm_rb =RB_ROOT ;
@@ -638,6 +639,7 @@ static struct mm_struct *mm_init(structif (init_new_context (p, mm)) goto fail_nocontext; + mm->user_ns =get_user_ns (user_ns);return mm; fail_nocontext:
@@ -683,7 +685,7 @@ struct mm_struct *mm_alloc(void)return NULL ;memset (mm,0 ,sizeof (*mm)); -return mm_init (mm, current); +return mm_init (mm, current,current_user_ns ()); }/*
@@ -698,6 +700,7 @@ void __mmdrop(struct mm_struct *mm)destroy_context (mm);mmu_notifier_mm_destroy (mm);check_mm (mm); +put_user_ns (mm->user_ns);free_mm (mm); }EXPORT_SYMBOL_GPL (__mmdrop);
@@ -977,7 +980,7 @@ static struct mm_struct *dup_mm(struct tmemcpy (mm, oldmm,sizeof (*mm)); -if (!mm_init (mm, tsk)) +if (!mm_init (mm, tsk, mm->user_ns)) goto fail_nomem; err =dup_mmap (mm, oldmm);
kernel/ptrace.c +11 -15
@@ -218,7 +218,7 @@ static int ptrace_has_cap(struct user_nastatic int __ptrace_may_access (struct task_struct *task,unsigned int mode) {const struct cred *cred =current_cred (), *tcred; -int dumpable =0 ; +struct mm_struct *mm;kuid_t caller_uid;kgid_t caller_gid;
@@ -269,16 +269,11 @@ static int __ptrace_may_access(struct tareturn -EPERM ; ok:rcu_read_unlock (); -smp_rmb (); -if (task->mm) - dumpable =get_dumpable (task->mm); -rcu_read_lock (); -if (dumpable !=SUID_DUMP_USER && - !ptrace_has_cap (__task_cred (task)->user_ns, mode)) { -rcu_read_unlock (); -return -EPERM ; - } -rcu_read_unlock (); + mm = task->mm; +if (mm && + ((get_dumpable (mm) !=SUID_DUMP_USER ) && + !ptrace_has_cap (mm->user_ns, mode))) +return -EPERM ;return security_ptrace_access_check (task, mode); }
@@ -329,6 +324,11 @@ static int ptrace_attach(struct task_strtask_lock (task); retval =__ptrace_may_access (task,PTRACE_MODE_ATTACH_REALCREDS ); +if (!retval) { +struct mm_struct *mm = task->mm; +if (mm &&ns_capable (mm->user_ns,CAP_SYS_PTRACE )) + flags |=PT_PTRACE_CAP ; + }task_unlock (task);if (retval) goto unlock_creds;
@@ -342,10 +342,6 @@ static int ptrace_attach(struct task_strif (seize) flags |=PT_SEIZED ; -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);
mm/init-mm.c +2 -0
@@ -6,6 +6,7 @@#include <linux/cpumask.h> #include <linux/atomic.h> +#include <linux/user_namespace.h> #include <asm/pgtable.h> #include <asm/mmu.h>
@@ -21,5 +22,6 @@ struct mm_struct init_mm = { .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem), .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(init_mm.mmlist), + .user_ns = &init_user_ns, INIT_MM_CONTEXT(init_mm) };
Patches currently in stable-queue which might be from [email protected] are
queue-4.8/mm-add-a-user_ns-owner-to-mm_struct-and-fix-ptrace-permission-checks.patch queue-4.8/exec-ensure-mm-user_ns-contains-the-execed-files.patch queue-4.8/ptrace-capture-the-ptracer-s-creds-not-pt_ptrace_cap.patch