Commit 0f9dea3f authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[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: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 040e3e09
...@@ -685,6 +685,14 @@ static inline int de_thread(struct task_struct *tsk) ...@@ -685,6 +685,14 @@ static inline int de_thread(struct task_struct *tsk)
*/ */
ptrace = leader->ptrace; ptrace = leader->ptrace;
parent = leader->parent; parent = leader->parent;
if (unlikely(ptrace) && unlikely(parent == current)) {
/*
* Joker was ptracing his own group leader,
* and now he wants to be his own parent!
* We can't have that.
*/
ptrace = 0;
}
ptrace_unlink(current); ptrace_unlink(current);
ptrace_unlink(leader); ptrace_unlink(leader);
......
...@@ -747,7 +747,9 @@ static void exit_notify(struct task_struct *tsk) ...@@ -747,7 +747,9 @@ static void exit_notify(struct task_struct *tsk)
} }
state = EXIT_ZOMBIE; 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; state = EXIT_DEAD;
tsk->exit_state = state; tsk->exit_state = state;
......
...@@ -1588,7 +1588,9 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) ...@@ -1588,7 +1588,9 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
if (likely(current->ptrace & PT_PTRACED) && if (likely(current->ptrace & PT_PTRACED) &&
likely(current->parent != current->real_parent || 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, do_notify_parent_cldstop(current, current->parent,
CLD_TRAPPED); CLD_TRAPPED);
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment