Merge branch 'work.sane_pwd' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / kernel / exit.c
index 580da79e38ee89992a93e6cb61f2c16232d580a6..516acdb0e0ec9bd48e3006a8ede165437b3e121f 100644 (file)
@@ -6,6 +6,12 @@
 
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/sched/autogroup.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/stat.h>
+#include <linux/sched/task.h>
+#include <linux/sched/task_stack.h>
+#include <linux/sched/cputime.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/capability.h>
@@ -45,6 +51,7 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/tracehook.h>
 #include <linux/fs_struct.h>
+#include <linux/userfaultfd_k.h>
 #include <linux/init_task.h>
 #include <linux/perf_event.h>
 #include <trace/events/sched.h>
@@ -538,7 +545,7 @@ static void exit_mm(void)
                __set_current_state(TASK_RUNNING);
                down_read(&mm->mmap_sem);
        }
-       atomic_inc(&mm->mm_count);
+       mmgrab(mm);
        BUG_ON(mm != current->active_mm);
        /* more a memory barrier than a real lock */
        task_lock(current);
@@ -607,15 +614,18 @@ static struct task_struct *find_new_reaper(struct task_struct *father,
                return thread;
 
        if (father->signal->has_child_subreaper) {
+               unsigned int ns_level = task_pid(father)->level;
                /*
                 * Find the first ->is_child_subreaper ancestor in our pid_ns.
-                * We start from father to ensure we can not look into another
-                * namespace, this is safe because all its threads are dead.
+                * We can't check reaper != child_reaper to ensure we do not
+                * cross the namespaces, the exiting parent could be injected
+                * by setns() + fork().
+                * We check pid->level, this is slightly more efficient than
+                * task_active_pid_ns(reaper) != task_active_pid_ns(father).
                 */
-               for (reaper = father;
-                    !same_thread_group(reaper, child_reaper);
+               for (reaper = father->real_parent;
+                    task_pid(reaper)->level == ns_level;
                     reaper = reaper->real_parent) {
-                       /* call_usermodehelper() descendants need this check */
                        if (reaper == &init_task)
                                break;
                        if (!reaper->signal->is_child_subreaper)