Test-case: #include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <assert.h>
int main(void) { int pid, status; pid = fork(); if (!pid) { assert(ptrace(PTRACE_TRACEME, 0,0,0) == 0); kill(getpid(), SIGSTOP); return 0x23; } assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); assert(ptrace(PTRACE_SINGLESTEP, pid, 0,0) == 0); assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP); assert(ptrace(PTRACE_DETACH, pid, 0,0) == 0); assert(wait(&status) == pid); if (WIFEXITED(status) && WEXITSTATUS(status) == 0x23) return 0; printf("ERR!! exit status: %04x\n", status); return 1; } It fails because TIF_SINGLESTEP is not cleared after PTRACE_DETACH and the tracee gets another trap after resume. Change utrace_reset() to do user_disable_single_step(). Alternatively we could change ptrace layer, but I think this is not ptrace specific. Signed-off-by: Oleg Nesterov <o...@redhat.com> --- kernel/utrace.c | 1 + 1 file changed, 1 insertion(+) --- kstub/kernel/utrace.c~10_utrace_reset_should_clear_ss 2010-09-20 03:55:12.000000000 +0200 +++ kstub/kernel/utrace.c 2010-09-20 21:33:47.000000000 +0200 @@ -709,6 +709,7 @@ static bool utrace_reset(struct task_str */ utrace->resume = UTRACE_RESUME; utrace->signal_handler = 0; + user_disable_single_step(task); } /*