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 UTRACE_DETACH and the tracee gets another trap after resume. Change utrace_reset() to do user_disable_single_step() if we are going to wake up the tracee without another report. This also cleanups the code, we can kill the similar logic in utrace_control(UTRACE_RESUME). Signed-off-by: Oleg Nesterov <o...@redhat.com> --- kernel/utrace.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) --- kstub/kernel/utrace.c~10_utrace_reset_should_clear_ss 2010-10-12 21:19:33.000000000 +0200 +++ kstub/kernel/utrace.c 2010-10-20 18:18:40.000000000 +0200 @@ -714,8 +714,15 @@ static bool utrace_reset(struct task_str /* * If no more engines want it stopped, wake it up. */ - if (task_is_traced(task) && !(flags & ENGINE_STOP)) + if (task_is_traced(task) && !(flags & ENGINE_STOP)) { + /* + * It just resumes, so make sure single-step + * is not left set. + */ + if (utrace->resume == UTRACE_RESUME) + user_disable_single_step(task); utrace_wakeup(task, utrace); + } /* * In theory spin_lock() doesn't imply rcu_read_lock(). @@ -1155,14 +1162,7 @@ int utrace_control(struct task_struct *t break; case UTRACE_RESUME: - /* - * This and all other cases imply resuming if stopped. - * There might not be another report before it just - * resumes, so make sure single-step is not left set. - */ clear_engine_wants_stop(engine); - if (likely(reset)) - user_disable_single_step(target); break; case UTRACE_BLOCKSTEP: