Commit c6c70f44 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Eric W. Biederman

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: default avatarOleg Nesterov <oleg@redhat.com>
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
parent 1328c727
...@@ -578,15 +578,18 @@ static struct task_struct *find_new_reaper(struct task_struct *father, ...@@ -578,15 +578,18 @@ static struct task_struct *find_new_reaper(struct task_struct *father,
return thread; return thread;
if (father->signal->has_child_subreaper) { 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. * Find the first ->is_child_subreaper ancestor in our pid_ns.
* We start from father to ensure we can not look into another * We can't check reaper != child_reaper to ensure we do not
* namespace, this is safe because all its threads are dead. * 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; for (reaper = father->real_parent;
!same_thread_group(reaper, child_reaper); task_pid(reaper)->level == ns_level;
reaper = reaper->real_parent) { reaper = reaper->real_parent) {
/* call_usermodehelper() descendants need this check */
if (reaper == &init_task) if (reaper == &init_task)
break; break;
if (!reaper->signal->is_child_subreaper) if (!reaper->signal->is_child_subreaper)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment