{
        struct task_struct *task;
        int allowed = 0;
-       /* Allow access to a task's file descriptors if either we may
-        * use ptrace attach to the process and find out that
-        * information, or if the task cannot possibly be ptraced
-        * allow access if we have the proper capability.
+       /* Allow access to a task's file descriptors if it is us or we
+        * may use ptrace attach to the process and find out that
+        * information.
         */
        task = get_proc_task(inode);
-       if (task == current)
-               allowed = 1;
-       if (task && !allowed) {
-               int alive;
-
-               task_lock(task);
-               alive = !!task->mm;
-               task_unlock(task);
-               if (alive)
-                       /* For a living task obey ptrace_may_attach */
-                       allowed = ptrace_may_attach(task);
-               else
-                       /* For a special task simply check the capability */
-                       allowed = capable(CAP_SYS_PTRACE);
-       }
-       if (task)
+       if (task) {
+               allowed = ptrace_may_attach(task);
                put_task_struct(task);
+       }
        return allowed;
 }
 
 
 
 static int may_attach(struct task_struct *task)
 {
-       if (!task->mm)
-               return -EPERM;
+       /* May we inspect the given task?
+        * This check is used both for attaching with ptrace
+        * and for allowing access to sensitive information in /proc.
+        *
+        * ptrace_attach denies several cases that /proc allows
+        * because setting up the necessary parent/child relationship
+        * or halting the specified task is impossible.
+        */
+       int dumpable = 0;
+       /* Don't let security modules deny introspection */
+       if (task == current)
+               return 0;
        if (((current->uid != task->euid) ||
             (current->uid != task->suid) ||
             (current->uid != task->uid) ||
             (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
                return -EPERM;
        smp_rmb();
-       if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+       if (task->mm)
+               dumpable = task->mm->dumpable;
+       if (!dumpable && !capable(CAP_SYS_PTRACE))
                return -EPERM;
 
        return security_ptrace(current, task);
                goto repeat;
        }
 
+       if (!task->mm)
+               goto bad;
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;