ptrace_report_clone: /* * Any of these reports implies auto-attaching the new child. * So does CLONE_PTRACE, even with no event to report. */ if (event || (clone_flags & CLONE_PTRACE)) ptrace_clone_attach(parent, child, context->options);
Yes, but even CLONE_UNTRACED must not suppress the auto-attach, we should check it later. To simplify the review: static u32 ptrace_report_clone(enum utrace_resume_action action, struct utrace_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) { struct ptrace_context *context = ptrace_context(engine); int event = 0; WARN_ON(ptrace_event_pending(context)); if (clone_flags & CLONE_VFORK) { if (context->options & PTRACE_O_TRACEVFORK) event = PTRACE_EVENT_VFORK; } else if ((clone_flags & CSIGNAL) != SIGCHLD) { if (context->options & PTRACE_O_TRACECLONE) event = PTRACE_EVENT_CLONE; } else if (context->options & PTRACE_O_TRACEFORK) { event = PTRACE_EVENT_FORK; } /* * Any of these reports implies auto-attaching the new child. * So does CLONE_PTRACE, even with no event to report. */ if (event || (clone_flags & CLONE_PTRACE)) ptrace_clone_attach(parent, child, context->options); if (!event || (clone_flags & CLONE_UNTRACED)) return UTRACE_RESUME; set_stop_code(context, event); context->eventmsg = child->pid; return UTRACE_STOP; } Also, kill the fast-path check in ptrace_clone_attach(), it doesn't make much sense since we know that parent (== current) was ptraced at least when tracehook_report_clone() was called. HOWEVER!!! man 2 clone: CLONE_PTRACE If CLONE_PTRACE is specified, and the calling process is being traced, then trace the child also (see ptrace(2)). OK, CLONE_UNTRACED (since Linux 2.5.46) If CLONE_UNTRACED is specified, then a tracing process cannot force CLONE_PTRACE on this child process. ??? --- kernel/ptrace.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) --- PU/kernel/ptrace.c~96_FIX_CLONE_PTRACE 2009-10-17 16:15:58.000000000 +0200 +++ PU/kernel/ptrace.c 2009-10-17 17:28:10.000000000 +0200 @@ -163,8 +163,6 @@ static void ptrace_clone_attach(struct t struct task_struct *tracer; bool abort = true; - if (!parent->ptrace) - return; if (unlikely(ptrace_attach_task(child, options))) { WARN_ON(1); return; @@ -194,15 +192,10 @@ static u32 ptrace_report_clone(enum utra struct task_struct *child) { struct ptrace_context *context = ptrace_context(engine); - int event, ret = UTRACE_RESUME; + int event = 0; WARN_ON(ptrace_event_pending(context)); - // XXX: WRONG!!! - if (clone_flags & CLONE_UNTRACED) - return ret; - - event = 0; if (clone_flags & CLONE_VFORK) { if (context->options & PTRACE_O_TRACEVFORK) event = PTRACE_EVENT_VFORK; @@ -212,7 +205,6 @@ static u32 ptrace_report_clone(enum utra } else if (context->options & PTRACE_O_TRACEFORK) { event = PTRACE_EVENT_FORK; } - /* * Any of these reports implies auto-attaching the new child. * So does CLONE_PTRACE, even with no event to report. @@ -220,15 +212,13 @@ static u32 ptrace_report_clone(enum utra if (event || (clone_flags & CLONE_PTRACE)) ptrace_clone_attach(parent, child, context->options); - // XXX: child->pid is wrong! use tracer's pid_ns - if (event) { - set_stop_code(context, event); - context->eventmsg = child->pid; + if (!event || (clone_flags & CLONE_UNTRACED)) + return UTRACE_RESUME; - ret = UTRACE_STOP; - } + set_stop_code(context, event); + context->eventmsg = child->pid; - return ret; + return UTRACE_STOP; } static inline void set_syscall_code(struct ptrace_context *context, int event)