Suppose that a PTRACE_O_TRACEFORK tracee does fork() and stops in
SYSCALL_ENTRY state. The tracer does PTRACE_SINGLESTEP.

In this case the tracee resumes and stops after syscall_trace_leave()
to report PTRACE_EVENT_FORK, but since it passes syscall_trace_leave()
with TIF_SINGLESTEP set the tracee gets the unwanted send_sigtrap().

Note: of course, this is hack. I think this should be move to utrace
layer. Unless we are going to call finish_resume_report(), finish_report()
should look at report->action and clear TIF_SINGLESTEP when needed.

What do you think?

---

 kernel/ptrace.c |   16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

--- PU/kernel/ptrace.c~128_SUPRESS_UNWANTED_SEND_SIGTRAP        2009-11-02 
05:31:46.000000000 +0100
+++ PU/kernel/ptrace.c  2009-11-02 06:16:53.000000000 +0100
@@ -327,6 +327,16 @@ static void ptrace_clone_attach(struct t
        set_tsk_thread_flag(child, TIF_SIGPENDING);
 }
 
+/*
+ * Prevents sending SIGTRAP after tracehook_report_syscall_exit().
+ * Called when we are going to emulate the stop before SYSCALL_EXIT.
+ */
+static void suppress_sigtrap(struct task_struct *task)
+{
+       if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
+               user_disable_single_step(task);
+}
+
 static u32 ptrace_report_clone(enum utrace_resume_action action,
                               struct utrace_engine *engine,
                               struct task_struct *parent,
@@ -362,6 +372,8 @@ static u32 ptrace_report_clone(enum utra
        if (!event)
                return UTRACE_RESUME;
 
+       suppress_sigtrap(parent);
+
        set_stop_code(ctx, event);
        ctx->eventmsg = child->pid;
        /*
@@ -393,8 +405,7 @@ static u32 ptrace_report_syscall_entry(u
        set_syscall_code(ctx, PTRACE_EVENT_SYSCALL_ENTRY);
 
        if (unlikely(ctx->options & PTRACE_O_SYSEMU)) {
-               if (test_thread_flag(TIF_SINGLESTEP))
-                       user_disable_single_step(task);
+               suppress_sigtrap(task);
                return UTRACE_SYSCALL_ABORT | UTRACE_REPORT;
        }
        return UTRACE_SYSCALL_RUN | UTRACE_STOP;
@@ -434,6 +445,7 @@ static u32 ptrace_report_exec(enum utrac
                return UTRACE_RESUME;
        }
 
+       suppress_sigtrap(task);
        set_stop_code(ctx, PTRACE_EVENT_EXEC);
 
        return UTRACE_STOP;

Reply via email to