aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2008-02-08 07:19:03 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:26 -0500
commit20686a309aa98c518adbbd9b57cdbb1804143deb (patch)
tree4aac811e67d777d3c0015ca51312aa93b4832d35 /kernel
parent9cbab8100538efdd93aeae6fc37787d986f2f558 (diff)
ptrace_stop: fix racy nonstop_code setting
If the tracer is gone and we are not going to stop, ptrace_stop() sets ->exit_code = nostop_code. However, the tracer could actually clear the exit code before detaching. In that case get_signal_to_deliver() "resends" the signal which was cancelled by the debugger. For example, it is possible that a quick PTRACE_ATTACH + PTRACE_DETACH can leave the tracee in STOPPED state. Change the behaviour of ptrace_stop(). If the caller is ptrace notify(), we should always clear ->exit_code. If the caller is get_signal_to_deliver(), we should not touch it at all. To do so, change the nonstop_code parameter to "bool clear_code" and change the callers accordingly. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Acked-by: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/signal.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 678bffa437c1..3fca710a5cd7 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1591,10 +1591,10 @@ static int sigkill_pending(struct task_struct *tsk)
1591 * That makes it a way to test a stopped process for 1591 * That makes it a way to test a stopped process for
1592 * being ptrace-stopped vs being job-control-stopped. 1592 * being ptrace-stopped vs being job-control-stopped.
1593 * 1593 *
1594 * If we actually decide not to stop at all because the tracer is gone, 1594 * If we actually decide not to stop at all because the tracer
1595 * we leave nostop_code in current->exit_code. 1595 * is gone, we keep current->exit_code unless clear_code.
1596 */ 1596 */
1597static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) 1597static void ptrace_stop(int exit_code, int clear_code, siginfo_t *info)
1598{ 1598{
1599 int killed = 0; 1599 int killed = 0;
1600 1600
@@ -1641,7 +1641,8 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
1641 * Don't drop the lock yet, another tracer may come. 1641 * Don't drop the lock yet, another tracer may come.
1642 */ 1642 */
1643 __set_current_state(TASK_RUNNING); 1643 __set_current_state(TASK_RUNNING);
1644 current->exit_code = nostop_code; 1644 if (clear_code)
1645 current->exit_code = 0;
1645 read_unlock(&tasklist_lock); 1646 read_unlock(&tasklist_lock);
1646 } 1647 }
1647 1648
@@ -1675,7 +1676,7 @@ void ptrace_notify(int exit_code)
1675 1676
1676 /* Let the debugger run. */ 1677 /* Let the debugger run. */
1677 spin_lock_irq(&current->sighand->siglock); 1678 spin_lock_irq(&current->sighand->siglock);
1678 ptrace_stop(exit_code, 0, &info); 1679 ptrace_stop(exit_code, 1, &info);
1679 spin_unlock_irq(&current->sighand->siglock); 1680 spin_unlock_irq(&current->sighand->siglock);
1680} 1681}
1681 1682
@@ -1782,7 +1783,7 @@ relock:
1782 ptrace_signal_deliver(regs, cookie); 1783 ptrace_signal_deliver(regs, cookie);
1783 1784
1784 /* Let the debugger run. */ 1785 /* Let the debugger run. */
1785 ptrace_stop(signr, signr, info); 1786 ptrace_stop(signr, 0, info);
1786 1787
1787 /* We're back. Did the debugger cancel the sig? */ 1788 /* We're back. Did the debugger cancel the sig? */
1788 signr = current->exit_code; 1789 signr = current->exit_code;