do_ptrace_notify_stop()->do_notify_parent_cldstop() is not safe
when called by tracer.

By the time we take tasklist the tracee can be SIGKILL'ed and
released by our sub-thread. In this case it is wrong to notify
its ->real_parent.

If ->real_parent has exited, then do_notify_parent_cldstop()
can use the freed/unmapped/resused/ task_struct.

Check task_ptrace(tracee) under tasklist_lock.

---

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

--- PU/kernel/ptrace.c~58_NOTIFY_FIX_RACE       2009-10-02 23:19:41.000000000 
+0200
+++ PU/kernel/ptrace.c  2009-10-02 23:34:57.000000000 +0200
@@ -831,14 +831,15 @@ static void do_ptrace_notify_stop(struct
        WARN_ON(!context->ev_code);
        context->ev_code = 0;
 
-       // XXX: !!!!!!!! UNSAFE when called by tracer !!!!!!!!!!!!!
        read_lock(&tasklist_lock);
        /*
         * Don't want to allow preemption here, because
         * sys_ptrace() needs this task to be inactive.
         */
        preempt_disable();
-       do_notify_parent_cldstop(tracee, CLD_TRAPPED);
+       /* It can be killed and then released by our subthread */
+       if (task_ptrace(tracee))
+               do_notify_parent_cldstop(tracee, CLD_TRAPPED);
        read_unlock(&tasklist_lock);
        preempt_enable_no_resched();
 }

Reply via email to