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)

Reply via email to