Skip to content

Commit

Permalink
kernel/exit.c: release ptraced tasks before zap_pid_ns_processes
Browse files Browse the repository at this point in the history
Currently, exit_ptrace() adds all ptraced tasks in a dead list, then
zap_pid_ns_processes() waits on all tasks in a current pidns, and only
then are tasks from the dead list released.

zap_pid_ns_processes() can get stuck on waiting tasks from the dead
list.  In this case, we will have one unkillable process with one or
more dead children.

Thanks to Oleg for the advice to release tasks in find_child_reaper().

Link: http://lkml.kernel.org/r/20190110175200.12442-1-avagin@gmail.com
Fixes: 7c8bd23 ("exit: ptrace: shift "reap dead" code from exit_ptrace() to forget_original_parent()")
Signed-off-by: Andrei Vagin <avagin@gmail.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
avagin authored and torvalds committed Feb 1, 2019
1 parent a8e911d commit 8fb335e
Showing 1 changed file with 10 additions and 2 deletions.
12 changes: 10 additions & 2 deletions kernel/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,12 +558,14 @@ static struct task_struct *find_alive_thread(struct task_struct *p)
return NULL;
}

static struct task_struct *find_child_reaper(struct task_struct *father)
static struct task_struct *find_child_reaper(struct task_struct *father,
struct list_head *dead)
__releases(&tasklist_lock)
__acquires(&tasklist_lock)
{
struct pid_namespace *pid_ns = task_active_pid_ns(father);
struct task_struct *reaper = pid_ns->child_reaper;
struct task_struct *p, *n;

if (likely(reaper != father))
return reaper;
Expand All @@ -579,6 +581,12 @@ static struct task_struct *find_child_reaper(struct task_struct *father)
panic("Attempted to kill init! exitcode=0x%08x\n",
father->signal->group_exit_code ?: father->exit_code);
}

list_for_each_entry_safe(p, n, dead, ptrace_entry) {
list_del_init(&p->ptrace_entry);
release_task(p);
}

zap_pid_ns_processes(pid_ns);
write_lock_irq(&tasklist_lock);

Expand Down Expand Up @@ -668,7 +676,7 @@ static void forget_original_parent(struct task_struct *father,
exit_ptrace(father, dead);

/* Can drop and reacquire tasklist_lock */
reaper = find_child_reaper(father);
reaper = find_child_reaper(father, dead);
if (list_empty(&father->children))
return;

Expand Down

0 comments on commit 8fb335e

Please sign in to comment.