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