Merge branch 'master' into next
[safe/jmp/linux-2.6] / kernel / ptrace.c
index 937f6b5..ca2df68 100644 (file)
@@ -115,6 +115,8 @@ int ptrace_check_attach(struct task_struct *child, int kill)
 
 int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
+       const struct cred *cred = current_cred(), *tcred;
+
        /* May we inspect the given task?
         * This check is used both for attaching with ptrace
         * and for allowing access to sensitive information in /proc.
@@ -123,20 +125,23 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
         * because setting up the necessary parent/child relationship
         * or halting the specified task is impossible.
         */
-       uid_t uid;
-       gid_t gid;
        int dumpable = 0;
        /* Don't let security modules deny introspection */
        if (task == current)
                return 0;
-       current_uid_gid(&uid, &gid);
-       if ((uid != task->euid ||
-            uid != task->suid ||
-            uid != task->uid  ||
-            gid != task->egid ||
-            gid != task->sgid ||
-            gid != task->gid) && !capable(CAP_SYS_PTRACE))
+       rcu_read_lock();
+       tcred = __task_cred(task);
+       if ((cred->uid != tcred->euid ||
+            cred->uid != tcred->suid ||
+            cred->uid != tcred->uid  ||
+            cred->gid != tcred->egid ||
+            cred->gid != tcred->sgid ||
+            cred->gid != tcred->gid) &&
+           !capable(CAP_SYS_PTRACE)) {
+               rcu_read_unlock();
                return -EPERM;
+       }
+       rcu_read_unlock();
        smp_rmb();
        if (task->mm)
                dumpable = get_dumpable(task->mm);
@@ -166,6 +171,14 @@ int ptrace_attach(struct task_struct *task)
        if (same_thread_group(task, current))
                goto out;
 
+       /* Protect exec's credential calculations against our interference;
+        * SUID, SGID and LSM creds get determined differently under ptrace.
+        */
+       retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+       if (retval  < 0)
+               goto out;
+
+       retval = -EPERM;
 repeat:
        /*
         * Nasty, nasty.
@@ -205,6 +218,7 @@ repeat:
 bad:
        write_unlock_irqrestore(&tasklist_lock, flags);
        task_unlock(task);
+       mutex_unlock(&current->cred_exec_mutex);
 out:
        return retval;
 }
@@ -615,7 +629,7 @@ int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data)
        return (copied == sizeof(data)) ? 0 : -EIO;
 }
 
-#if defined CONFIG_COMPAT && defined __ARCH_WANT_COMPAT_SYS_PTRACE
+#if defined CONFIG_COMPAT
 #include <linux/compat.h>
 
 int compat_ptrace_request(struct task_struct *child, compat_long_t request,
@@ -712,4 +726,4 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
        unlock_kernel();
        return ret;
 }
-#endif /* CONFIG_COMPAT && __ARCH_WANT_COMPAT_SYS_PTRACE */
+#endif /* CONFIG_COMPAT */