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;
                }

Reply via email to