[3.8.y.z extended stable] Patch "wait: fix reparent_leader() vs EXIT_DEAD->EXIT_ZOMBIE race" has been added to staging queue
Kamal Mostafa
kamal at canonical.com
Thu Apr 17 23:31:10 UTC 2014
This is a note to let you know that I have just added a patch titled
wait: fix reparent_leader() vs EXIT_DEAD->EXIT_ZOMBIE race
to the linux-3.8.y-queue branch of the 3.8.y.z extended stable tree
which can be found at:
http://kernel.ubuntu.com/git?p=ubuntu/linux.git;a=shortlog;h=refs/heads/linux-3.8.y-queue
This patch is scheduled to be released in version 3.8.13.22.
If you, or anyone else, feels it should not be added to this tree, please
reply to this email.
For more information about the 3.8.y.z tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable
Thanks.
-Kamal
------
>From 1b282e3cb0d99bf3d6f7c2110e0cdc3c8c45448b Mon Sep 17 00:00:00 2001
From: Oleg Nesterov <oleg at redhat.com>
Date: Mon, 7 Apr 2014 15:38:41 -0700
Subject: wait: fix reparent_leader() vs EXIT_DEAD->EXIT_ZOMBIE race
commit dfccbb5e49a621c1b21a62527d61fc4305617aca upstream.
wait_task_zombie() first does EXIT_ZOMBIE->EXIT_DEAD transition and
drops tasklist_lock. If this task is not the natural child and it is
traced, we change its state back to EXIT_ZOMBIE for ->real_parent.
The last transition is racy, this is even documented in 50b8d257486a
"ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE
race". wait_consider_task() tries to detect this transition and clear
->notask_error but we can't rely on ptrace_reparented(), debugger can
exit and do ptrace_unlink() before its sub-thread sets EXIT_ZOMBIE.
And there is another problem which were missed before: this transition
can also race with reparent_leader() which doesn't reset >exit_signal if
EXIT_DEAD, assuming that this task must be reaped by someone else. So
the tracee can be re-parented with ->exit_signal != SIGCHLD, and if
/sbin/init doesn't use __WALL it becomes unreapable.
Change reparent_leader() to update ->exit_signal even if EXIT_DEAD.
Note: this is the simple temporary hack for -stable, it doesn't try to
solve all problems, it will be reverted by the next changes.
Signed-off-by: Oleg Nesterov <oleg at redhat.com>
Reported-by: Jan Kratochvil <jan.kratochvil at redhat.com>
Reported-by: Michal Schmidt <mschmidt at redhat.com>
Tested-by: Michal Schmidt <mschmidt at redhat.com>
Cc: Al Viro <viro at ZenIV.linux.org.uk>
Cc: Lennart Poettering <lpoetter at redhat.com>
Cc: Roland McGrath <roland at hack.frob.com>
Cc: Tejun Heo <tj at kernel.org>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
---
kernel/exit.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/kernel/exit.c b/kernel/exit.c
index b4df219..0842373 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -568,9 +568,6 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
struct list_head *dead)
{
list_move_tail(&p->sibling, &p->real_parent->children);
-
- if (p->exit_state == EXIT_DEAD)
- return;
/*
* If this is a threaded reparent there is no need to
* notify anyone anything has happened.
@@ -578,9 +575,19 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
if (same_thread_group(p->real_parent, father))
return;
- /* We don't want people slaying init. */
+ /*
+ * We don't want people slaying init.
+ *
+ * Note: we do this even if it is EXIT_DEAD, wait_task_zombie()
+ * can change ->exit_state to EXIT_ZOMBIE. If this is the final
+ * state, do_notify_parent() was already called and ->exit_signal
+ * doesn't matter.
+ */
p->exit_signal = SIGCHLD;
+ if (p->exit_state == EXIT_DEAD)
+ return;
+
/* If it has exited notify the new parent about this child's death. */
if (!p->ptrace &&
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
--
1.9.1
More information about the kernel-team
mailing list