summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Vagin <avagin@gmail.com>2019-02-01 14:20:24 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-02-06 17:31:36 +0100
commit3d98fc4d190f4e02f71ac4a52413fee028acaa8c (patch)
tree18cd95bf3ac8b3513b9d43d13014a70734e01169
parent28f4952ab7ff4f9494eae1fa4ee72a98ecd384b2 (diff)
downloadlinux-rpi3-3d98fc4d190f4e02f71ac4a52413fee028acaa8c.tar.gz
linux-rpi3-3d98fc4d190f4e02f71ac4a52413fee028acaa8c.tar.bz2
linux-rpi3-3d98fc4d190f4e02f71ac4a52413fee028acaa8c.zip
kernel/exit.c: release ptraced tasks before zap_pid_ns_processes
commit 8fb335e078378c8426fabeed1ebee1fbf915690c upstream. 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: 7c8bd2322c7f ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/exit.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index e3a08761eb40..3aa01b74c1e3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -557,12 +557,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;
@@ -578,6 +580,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);
@@ -667,7 +675,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;