aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-01-21 14:48:00 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-01-22 13:08:00 -0500
commit9899d11f654474d2d54ea52ceaa2a1f4db3abd68 (patch)
tree4ac2411ec2d79335128afd0142a91c8cbaac251f /kernel/signal.c
parent910ffdb18a6408e14febbb6e4b6840fd2c928c82 (diff)
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
putreg() assumes that the tracee is not running and pt_regs_access() can safely play with its stack. However a killed tracee can return from ptrace_stop() to the low-level asm code and do RESTORE_REST, this means that debugger can actually read/modify the kernel stack until the tracee does SAVE_REST again. set_task_blockstep() can race with SIGKILL too and in some sense this race is even worse, the very fact the tracee can be woken up breaks the logic. As Linus suggested we can clear TASK_WAKEKILL around the arch_ptrace() call, this ensures that nobody can ever wakeup the tracee while the debugger looks at it. Not only this fixes the mentioned problems, we can do some cleanups/simplifications in arch_ptrace() paths. Probably ptrace_unfreeze_traced() needs more callers, for example it makes sense to make the tracee killable for oom-killer before access_process_vm(). While at it, add the comment into may_ptrace_stop() to explain why ptrace_stop() still can't rely on SIGKILL and signal_pending_state(). Reported-by: Salman Qazi <sqazi@google.com> Reported-by: Suleiman Souhlal <suleiman@google.com> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 6e97aa6fa32c..3d09cf6cde75 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1794,6 +1794,10 @@ static inline int may_ptrace_stop(void)
1794 * If SIGKILL was already sent before the caller unlocked 1794 * If SIGKILL was already sent before the caller unlocked
1795 * ->siglock we must see ->core_state != NULL. Otherwise it 1795 * ->siglock we must see ->core_state != NULL. Otherwise it
1796 * is safe to enter schedule(). 1796 * is safe to enter schedule().
1797 *
1798 * This is almost outdated, a task with the pending SIGKILL can't
1799 * block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported
1800 * after SIGKILL was already dequeued.
1797 */ 1801 */
1798 if (unlikely(current->mm->core_state) && 1802 if (unlikely(current->mm->core_state) &&
1799 unlikely(current->mm == current->parent->mm)) 1803 unlikely(current->mm == current->parent->mm))
@@ -1919,6 +1923,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
1919 if (gstop_done) 1923 if (gstop_done)
1920 do_notify_parent_cldstop(current, false, why); 1924 do_notify_parent_cldstop(current, false, why);
1921 1925
1926 /* tasklist protects us from ptrace_freeze_traced() */
1922 __set_current_state(TASK_RUNNING); 1927 __set_current_state(TASK_RUNNING);
1923 if (clear_code) 1928 if (clear_code)
1924 current->exit_code = 0; 1929 current->exit_code = 0;