I am a bit surprised there is nothing in ptrace-tests to check CONT/SYSCALL behaviour. I had to write this one:
#define WEVENT(s) ((s & 0xFF0000) >> 16) int main(void) { int pid, stat; pid = fork(); if (!pid) { assert(0 == ptrace(PTRACE_TRACEME, 0,0,0)); kill(getpid(), SIGSTOP); execl("/bin/false", "true", NULL); assert(0); } assert(wait(&stat) == pid); assert(WIFSTOPPED(stat) && WSTOPSIG(stat) == SIGSTOP); assert(0 == ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXEC)); for (;;) { assert(0 == ptrace(PTRACE_SYSCALL, pid, 0, 0)); assert(waitpid(pid, &stat, __WALL) == pid); if (WEVENT(stat) == PTRACE_EVENT_EXEC) break; } kill(pid, SIGINT); assert(0 == ptrace(PTRACE_CONT, pid, 0, 0)); assert(waitpid(pid, &stat, __WALL) == pid); // we must see SIGINT, not SYSCALL_EXIT assert(WIFSTOPPED(stat) && WSTOPSIG(stat) == SIGINT); return 0; } If the tracee reports PTRACE_EVENT_EXEC, then it must not report SYSCALL_EXIT if the traces resumes it via PTRACE_CONT. The previous patch introduced ptrace_event->ev_options to filter out unwanted events. But since there is no option for syscall tracing, we add the "fake" PTRACE_O_TRACE_SYSCALL. It is not visible to user space, and this bit is not used outside of ptrace_resume() path. --- kernel/ptrace.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) --- PU/kernel/ptrace.c~38_FIX_EXEC_CONT 2009-09-15 18:06:53.000000000 +0200 +++ PU/kernel/ptrace.c 2009-09-15 18:36:40.000000000 +0200 @@ -303,10 +303,15 @@ static void ptrace_resume_syscall(struct } } +#define PTRACE_O_TRACE_SYSCALL 0x100 + static void push_syscall_event(struct ptrace_context *context) { struct ptrace_event *ev = ev_push(context); + BUILD_BUG_ON(PTRACE_O_TRACE_SYSCALL & PTRACE_O_MASK); + + ev->ev_options = PTRACE_O_TRACE_SYSCALL; ev->ev_resume = ptrace_resume_syscall; ev->ev_code = (context->options & PTRACE_O_TRACESYSGOOD) ? (SIGTRAP | 0x80) : SIGTRAP; @@ -998,10 +1003,15 @@ static void ptrace_wake_up(struct utrace static void do_ptrace_resume(struct utrace_engine *engine, struct task_struct *tracee, - long data) + long request, long data) { struct ptrace_context *context = ptrace_context(engine); + if (request == PTRACE_SYSCALL) + context->options |= PTRACE_O_TRACE_SYSCALL; + else + context->options &= ~PTRACE_O_TRACE_SYSCALL; + if (!ev_empty(context)) { struct ptrace_event *ev = ev_pop(context); @@ -1072,7 +1082,7 @@ static int ptrace_resume(struct task_str int event; if (!ev_empty(context)) { - do_ptrace_resume(engine, child, data); + do_ptrace_resume(engine, child, request, data); utrace_engine_put(engine); return 0; }