aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2017-01-30 13:17:35 -0500
committerEric W. Biederman <ebiederm@xmission.com>2017-02-01 00:20:48 -0500
commitc6c70f4455d1eda91065e93cc4f7eddf4499b105 (patch)
treebf2f38330bc30a13329ae275172deffe863b36a8
parent1328c727004d432bbdfba0ffa02a166df04c7305 (diff)
exit: fix the setns() && PR_SET_CHILD_SUBREAPER interaction
find_new_reaper() checks same_thread_group(reaper, child_reaper) to prevent the cross-namespace reparenting but this is not enough if the exiting parent was injected by setns() + fork(). Suppose we have a process P in the root namespace and some namespace X. P does setns() to enter the X namespace, and forks the child C. C forks a grandchild G and exits. The grandchild G should be re-parented to X->child_reaper, but in this case the ->real_parent chain does not lead to ->child_reaper, so it will be wrongly reparanted to P's sub-reaper or a global init. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--kernel/exit.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 8f14b866f9f6..5cfbd595f918 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -578,15 +578,18 @@ static struct task_struct *find_new_reaper(struct task_struct *father,
578 return thread; 578 return thread;
579 579
580 if (father->signal->has_child_subreaper) { 580 if (father->signal->has_child_subreaper) {
581 unsigned int ns_level = task_pid(father)->level;
581 /* 582 /*
582 * Find the first ->is_child_subreaper ancestor in our pid_ns. 583 * Find the first ->is_child_subreaper ancestor in our pid_ns.
583 * We start from father to ensure we can not look into another 584 * We can't check reaper != child_reaper to ensure we do not
584 * namespace, this is safe because all its threads are dead. 585 * cross the namespaces, the exiting parent could be injected
586 * by setns() + fork().
587 * We check pid->level, this is slightly more efficient than
588 * task_active_pid_ns(reaper) != task_active_pid_ns(father).
585 */ 589 */
586 for (reaper = father; 590 for (reaper = father->real_parent;
587 !same_thread_group(reaper, child_reaper); 591 task_pid(reaper)->level == ns_level;
588 reaper = reaper->real_parent) { 592 reaper = reaper->real_parent) {
589 /* call_usermodehelper() descendants need this check */
590 if (reaper == &init_task) 593 if (reaper == &init_task)
591 break; 594 break;
592 if (!reaper->signal->is_child_subreaper) 595 if (!reaper->signal->is_child_subreaper)