lockdep: more robust lockdep_map init sequence
[safe/jmp/linux-2.6] / kernel / ptrace.c
index f5a9fa5..dfcd83c 100644 (file)
@@ -21,9 +21,7 @@
 #include <linux/audit.h>
 #include <linux/pid_namespace.h>
 #include <linux/syscalls.h>
-
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 
 /*
@@ -48,7 +46,7 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
        list_add(&child->ptrace_entry, &new_parent->ptraced);
        child->parent = new_parent;
 }
+
 /*
  * Turn a tracing stop into a normal stop now, since with no tracer there
  * would be no way to wake it up with SIGCONT or SIGKILL.  If there was a
@@ -60,11 +58,15 @@ static void ptrace_untrace(struct task_struct *child)
 {
        spin_lock(&child->sighand->siglock);
        if (task_is_traced(child)) {
-               if (child->signal->flags & SIGNAL_STOP_STOPPED) {
+               /*
+                * If the group stop is completed or in progress,
+                * this thread was already counted as stopped.
+                */
+               if (child->signal->flags & SIGNAL_STOP_STOPPED ||
+                   child->signal->group_stop_count)
                        __set_task_state(child, TASK_STOPPED);
-               } else {
+               else
                        signal_wake_up(child, 1);
-               }
        }
        spin_unlock(&child->sighand->siglock);
 }
@@ -169,7 +171,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
        task_lock(task);
        err = __ptrace_may_access(task, mode);
        task_unlock(task);
-       return (!err ? true : false);
+       return !err;
 }
 
 int ptrace_attach(struct task_struct *task)
@@ -301,11 +303,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
         */
        if (child->ptrace) {
                child->exit_code = data;
-
                dead = __ptrace_detach(current, child);
-
-               if (!child->exit_state)
-                       wake_up_process(child);
        }
        write_unlock_irq(&tasklist_lock);
 
@@ -358,7 +356,7 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst
                copied += retval;
                src += retval;
                dst += retval;
-               len -= retval;                  
+               len -= retval;
        }
        return copied;
 }
@@ -383,7 +381,7 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds
                copied += retval;
                src += retval;
                dst += retval;
-               len -= retval;                  
+               len -= retval;
        }
        return copied;
 }
@@ -496,9 +494,9 @@ static int ptrace_resume(struct task_struct *child, long request, long data)
                if (unlikely(!arch_has_single_step()))
                        return -EIO;
                user_enable_single_step(child);
-       }
-       else
+       } else {
                user_disable_single_step(child);
+       }
 
        child->exit_code = data;
        wake_up_process(child);
@@ -606,10 +604,11 @@ repeat:
                ret = security_ptrace_traceme(current->parent);
 
                /*
-                * Set the ptrace bit in the process ptrace flags.
-                * Then link us on our parent's ptraced list.
+                * Check PF_EXITING to ensure ->real_parent has not passed
+                * exit_ptrace(). Otherwise we don't report the error but
+                * pretend ->real_parent untraces us right after return.
                 */
-               if (!ret) {
+               if (!ret && !(current->real_parent->flags & PF_EXITING)) {
                        current->ptrace |= PT_PTRACED;
                        __ptrace_link(current, current->real_parent);
                }
@@ -687,8 +686,6 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data)
                goto out_put_task_struct;
 
        ret = arch_ptrace(child, request, addr, data);
-       if (ret < 0)
-               goto out_put_task_struct;
 
  out_put_task_struct:
        put_task_struct(child);