[PATCH] proc: Cleanup proc_fd_access_allowed
authorEric W. Biederman <ebiederm@xmission.com>
Mon, 26 Jun 2006 07:25:59 +0000 (00:25 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 26 Jun 2006 16:58:26 +0000 (09:58 -0700)
In process of getting proc_fd_access_allowed to work it has developed a few
warts.  In particular the special case that always allows introspection and
the special case to allow inspection of kernel threads.

The special case for introspection is needed for /proc/self/mem.

The special case for kernel threads really should be overridable
by security modules.

So consolidate these checks into ptrace.c:may_attach().

The check to always allow introspection is trivial.

The check to allow access to kernel threads, and zombies is a little
trickier.  mem_read and mem_write already verify an mm exists so it isn't
needed twice.  proc_fd_access_allowed only doesn't want a check to verify
task->mm exits, s it prevents all access to kernel threads.  So just move
the task->mm check into ptrace_attach where it is needed for practical
reasons.

I did a quick audit and none of the security modules in the kernel seem to
care if they are passed a task without an mm into security_ptrace.  So the
above move should be safe and it allows security modules to come up with
more restrictive policy.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/proc/base.c
kernel/ptrace.c

index f38da6bda269c3b7627dbd755d4fa8714ca6fb71..773469703c62b62c222490e624c1168d02fb5fdc 100644 (file)
@@ -536,29 +536,15 @@ static int proc_fd_access_allowed(struct inode *inode)
 {
        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;
 }
 
index 921c22ad16e40e898b2cdceda7db6ea13babb36f..6252d2fa2bf345cf2e3a11456d29a526d7f131c3 100644 (file)
@@ -120,8 +120,18 @@ int ptrace_check_attach(struct task_struct *child, int kill)
 
 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) ||
@@ -130,7 +140,9 @@ static int may_attach(struct task_struct *task)
             (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);
@@ -176,6 +188,8 @@ repeat:
                goto repeat;
        }
 
+       if (!task->mm)
+               goto bad;
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;