summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2005-01-14 23:39:11 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-14 23:39:11 -0800
commit0f9dea3fc12cfac611ca90d0ed0f6cbc063d2134 (patch)
treebf58e16470c37339629589e6856cea260bd74e54 /kernel
parent040e3e09c0905972d58c290240e1f626a8692565 (diff)
[PATCH] fix exec deadlock when ptrace used inside the thread group
If one thread uses ptrace on another thread in the same thread group, there can be a deadlock when calling exec. The ptrace_stop change ensures that no tracing stop can be entered for a queued signal, or exit tracing, if the tracer is part of the same dying group. The exit_notify change prevents a ptrace zombie from sticking around if its tracer is in the midst of a group exit (which an exec fakes), so these zombies don't hold up de_thread's synchronization. The de_thread change ensures the new thread group leader doesn't wind up ptracing itself, which would produce its own deadlocks. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/signal.c4
2 files changed, 6 insertions, 2 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index e0df301a4553..3171228f25c3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -747,7 +747,9 @@ static void exit_notify(struct task_struct *tsk)
}
state = EXIT_ZOMBIE;
- if (tsk->exit_signal == -1 && tsk->ptrace == 0)
+ if (tsk->exit_signal == -1 &&
+ (likely(tsk->ptrace == 0) ||
+ unlikely(tsk->parent->signal->flags & SIGNAL_GROUP_EXIT)))
state = EXIT_DEAD;
tsk->exit_state = state;
diff --git a/kernel/signal.c b/kernel/signal.c
index 6d0a3bd948ab..d98e9624ea30 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1588,7 +1588,9 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
read_lock(&tasklist_lock);
if (likely(current->ptrace & PT_PTRACED) &&
likely(current->parent != current->real_parent ||
- !(current->ptrace & PT_ATTACHED))) {
+ !(current->ptrace & PT_ATTACHED)) &&
+ (likely(current->parent->signal != current->signal) ||
+ !unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) {
do_notify_parent_cldstop(current, current->parent,
CLD_TRAPPED);
read_unlock(&tasklist_lock);