]> git.kernelconcepts.de Git - karo-tx-linux.git/commit
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
authorOleg Nesterov <oleg@redhat.com>
Mon, 21 Jan 2013 19:48:00 +0000 (20:48 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Wed, 20 Feb 2013 03:15:30 +0000 (03:15 +0000)
commitf224540e9fc7be42e1867f1e4967889b29073abb
tree2eeedde26a6c6e7025fb90233bfc46030e1f5438
parentbb24eda9eee7a1cc865bb10dbb89edf7c1f5cdc7
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL

commit 9899d11f654474d2d54ea52ceaa2a1f4db3abd68 upstream.

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>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
arch/x86/kernel/step.c
kernel/ptrace.c
kernel/signal.c