diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-06-22 23:08:53 +0200 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2011-06-27 20:30:08 +0200 |
commit | 9843a1e977977986d0a4c1000f2229b032572534 (patch) | |
tree | 8c3d8a77ed8b2a021451a493aa47162977c8001b /kernel/ptrace.c | |
parent | 45cdf5cc0703c537194588c63d53bad1f2539d36 (diff) | |
download | lwn-9843a1e977977986d0a4c1000f2229b032572534.tar.gz lwn-9843a1e977977986d0a4c1000f2229b032572534.zip |
__ptrace_detach: avoid task_detached(), check do_notify_parent()
__ptrace_detach() relies on the current obscure behaviour of
do_notify_parent(tsk) which changes tsk->exit_signal if this child
should be silently reaped. That is why we check task_detached(), it
is true if the task is sub-thread, or it is the group_leader but
its exit_signal was changed by do_notify_parent().
This is confusing, change the code to rely on !thread_group_leader()
or the value returned by do_notify_parent().
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e18966c1c0da..66a28bd71ef6 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -370,25 +370,28 @@ static int ignoring_children(struct sighand_struct *sigh) */ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) { + bool dead; + __ptrace_unlink(p); - if (p->exit_state == EXIT_ZOMBIE) { - if (!task_detached(p) && thread_group_empty(p)) { - if (!same_thread_group(p->real_parent, tracer)) - do_notify_parent(p, p->exit_signal); - else if (ignoring_children(tracer->sighand)) { - __wake_up_parent(p, tracer); - p->exit_signal = -1; - } - } - if (task_detached(p)) { - /* Mark it as in the process of being reaped. */ - p->exit_state = EXIT_DEAD; - return true; + if (p->exit_state != EXIT_ZOMBIE) + return false; + + dead = !thread_group_leader(p); + + if (!dead && thread_group_empty(p)) { + if (!same_thread_group(p->real_parent, tracer)) + dead = do_notify_parent(p, p->exit_signal); + else if (ignoring_children(tracer->sighand)) { + __wake_up_parent(p, tracer); + p->exit_signal = -1; + dead = true; } } - - return false; + /* Mark it as in the process of being reaped. */ + if (dead) + p->exit_state = EXIT_DEAD; + return dead; } static int ptrace_detach(struct task_struct *child, unsigned int data) |