tracehook_report_exit() calls ptrace_utrace_exit() to early. We don't
have PF_EXITING yet, we can race with ptrace_traceme().

Granted, exit_ptrace/ptrace_utrace_exit should be reworked later. Just
a minimal fix for now.

---

 include/linux/ptrace.h    |    2 --
 include/linux/tracehook.h |    2 --
 kernel/ptrace.c           |   20 +++++++++++---------
 3 files changed, 11 insertions(+), 13 deletions(-)

--- PU/include/linux/ptrace.h~04_PTRACE_EXIT    2009-08-13 15:19:18.000000000 
+0200
+++ PU/include/linux/ptrace.h   2009-08-13 17:53:02.000000000 +0200
@@ -131,8 +131,6 @@ static inline int task_ptrace(struct tas
        return task->ptrace;
 }
 
-extern void ptrace_utrace_exit(struct task_struct *);
-
 /**
  * ptrace_init_task - initialize ptrace state for a new child
  * @child:             new child task
--- PU/include/linux/tracehook.h~04_PTRACE_EXIT 2009-08-13 15:50:27.000000000 
+0200
+++ PU/include/linux/tracehook.h        2009-08-13 17:51:52.000000000 +0200
@@ -195,8 +195,6 @@ static inline void tracehook_report_exit
 {
        if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXIT)))
                utrace_report_exit(exit_code);
-       if (unlikely(!list_empty(&current->ptraced)))
-               ptrace_utrace_exit(current);
 }
 
 /**
--- PU/kernel/ptrace.c~04_PTRACE_EXIT   2009-08-13 17:35:29.000000000 +0200
+++ PU/kernel/ptrace.c  2009-08-13 17:55:13.000000000 +0200
@@ -70,15 +70,6 @@ static void ptrace_detach_task(struct ta
        utrace_engine_put(engine);
 }
 
-void ptrace_utrace_exit(struct task_struct *task)
-{
-       struct task_struct *child;
-       read_lock(&tasklist_lock);
-       list_for_each_entry(child, &task->ptraced, ptrace_entry)
-               ptrace_detach_task(child, 0);
-       read_unlock(&tasklist_lock);
-}
-
 /*
  * unptrace a task: move it back to its original parent and
  * remove it from the ptrace list.
@@ -810,6 +801,15 @@ int ptrace_detach(struct task_struct *ch
        return 0;
 }
 
+static void ptrace_utrace_exit(struct task_struct *task)
+{
+       struct task_struct *child;
+       read_lock(&tasklist_lock);
+       list_for_each_entry(child, &task->ptraced, ptrace_entry)
+               ptrace_detach_task(child, 0);
+       read_unlock(&tasklist_lock);
+}
+
 /*
  * Detach all tasks we were using ptrace on.
  */
@@ -818,6 +818,8 @@ void exit_ptrace(struct task_struct *tra
        struct task_struct *p, *n;
        LIST_HEAD(ptrace_dead);
 
+       ptrace_utrace_exit(tracer);
+
        write_lock_irq(&tasklist_lock);
        list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
                if (__ptrace_detach(tracer, p))

Reply via email to