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.0 +0200
+++ kstub/kernel/utrace.c 2010-09-20 21:33:47.0 +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);
}
/*