diff options
author | Oleg Nesterov <oleg@redhat.com> | 2009-12-15 19:47:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:20:08 -0500 |
commit | 6580807da14c423f0d0a708108e6df6ebc8bc83d (patch) | |
tree | 553e2de8f2174f9bbb6ab9a2454b1306bb5eb4fa /kernel/fork.c | |
parent | c6a47cc2ccf9649ee09eeddd70a6d061bde69568 (diff) |
ptrace: copy_process() should disable stepping
If the tracee calls fork() after PTRACE_SINGLESTEP, the forked child
starts with TIF_SINGLESTEP/X86_EFLAGS_TF bits copied from ptraced parent.
This is not right, especially when the new child is not auto-attaced: in
this case it is killed by SIGTRAP.
Change copy_process() to call user_disable_single_step(). Tested on x86.
Test-case:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <assert.h>
int main(void)
{
int pid, status;
if (!(pid = fork())) {
assert(ptrace(PTRACE_TRACEME) == 0);
kill(getpid(), SIGSTOP);
if (!fork()) {
/* kernel bug: this child will be killed by SIGTRAP */
printf("Hello world\n");
return 43;
}
wait(&status);
return WEXITSTATUS(status);
}
for (;;) {
assert(pid == wait(&status));
if (WIFEXITED(status))
break;
assert(ptrace(PTRACE_SINGLESTEP, pid, 0,0) == 0);
}
assert(WEXITSTATUS(status) == 43);
return 0;
}
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
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/fork.c')
-rw-r--r-- | kernel/fork.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index b6cbd33dde80..202a0ba63d3c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1210,9 +1210,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1210 | p->sas_ss_sp = p->sas_ss_size = 0; | 1210 | p->sas_ss_sp = p->sas_ss_size = 0; |
1211 | 1211 | ||
1212 | /* | 1212 | /* |
1213 | * Syscall tracing should be turned off in the child regardless | 1213 | * Syscall tracing and stepping should be turned off in the |
1214 | * of CLONE_PTRACE. | 1214 | * child regardless of CLONE_PTRACE. |
1215 | */ | 1215 | */ |
1216 | user_disable_single_step(p); | ||
1216 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); | 1217 | clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); |
1217 | #ifdef TIF_SYSCALL_EMU | 1218 | #ifdef TIF_SYSCALL_EMU |
1218 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); | 1219 | clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); |