Merge tag 'upstream-3.7-rc1' of git://git.infradead.org/linux-ubifs
[linux-3.10.git] / kernel / ptrace.c
index 273f56e..a232bb5 100644 (file)
@@ -198,15 +198,14 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
                return 0;
        rcu_read_lock();
        tcred = __task_cred(task);
-       if (cred->user->user_ns == tcred->user->user_ns &&
-           (cred->uid == tcred->euid &&
-            cred->uid == tcred->suid &&
-            cred->uid == tcred->uid  &&
-            cred->gid == tcred->egid &&
-            cred->gid == tcred->sgid &&
-            cred->gid == tcred->gid))
+       if (uid_eq(cred->uid, tcred->euid) &&
+           uid_eq(cred->uid, tcred->suid) &&
+           uid_eq(cred->uid, tcred->uid)  &&
+           gid_eq(cred->gid, tcred->egid) &&
+           gid_eq(cred->gid, tcred->sgid) &&
+           gid_eq(cred->gid, tcred->gid))
                goto ok;
-       if (ptrace_has_cap(tcred->user->user_ns, mode))
+       if (ptrace_has_cap(tcred->user_ns, mode))
                goto ok;
        rcu_read_unlock();
        return -EPERM;
@@ -231,26 +230,22 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 }
 
 static int ptrace_attach(struct task_struct *task, long request,
+                        unsigned long addr,
                         unsigned long flags)
 {
        bool seize = (request == PTRACE_SEIZE);
        int retval;
 
-       /*
-        * SEIZE will enable new ptrace behaviors which will be implemented
-        * gradually.  SEIZE_DEVEL is used to prevent applications
-        * expecting full SEIZE behaviors trapping on kernel commits which
-        * are still in the process of implementing them.
-        *
-        * Only test programs for new ptrace behaviors being implemented
-        * should set SEIZE_DEVEL.  If unset, SEIZE will fail with -EIO.
-        *
-        * Once SEIZE behaviors are completely implemented, this flag and
-        * the following test will be removed.
-        */
        retval = -EIO;
-       if (seize && !(flags & PTRACE_SEIZE_DEVEL))
-               goto out;
+       if (seize) {
+               if (addr != 0)
+                       goto out;
+               if (flags & ~(unsigned long)PTRACE_O_MASK)
+                       goto out;
+               flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT);
+       } else {
+               flags = PT_PTRACED;
+       }
 
        audit_ptrace(task);
 
@@ -262,7 +257,7 @@ static int ptrace_attach(struct task_struct *task, long request,
 
        /*
         * Protect exec's credential calculations against our interference;
-        * interference; SUID, SGID and LSM creds get determined differently
+        * SUID, SGID and LSM creds get determined differently
         * under ptrace.
         */
        retval = -ERESTARTNOINTR;
@@ -282,11 +277,11 @@ static int ptrace_attach(struct task_struct *task, long request,
        if (task->ptrace)
                goto unlock_tasklist;
 
-       task->ptrace = PT_PTRACED;
        if (seize)
-               task->ptrace |= PT_SEIZED;
+               flags |= PT_SEIZED;
        if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE))
-               task->ptrace |= PT_PTRACE_CAP;
+               flags |= PT_PTRACE_CAP;
+       task->ptrace = flags;
 
        __ptrace_link(task, current);
 
@@ -528,31 +523,16 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds
 
 static int ptrace_setoptions(struct task_struct *child, unsigned long data)
 {
+       unsigned flags;
+
        if (data & ~(unsigned long)PTRACE_O_MASK)
                return -EINVAL;
 
-       child->ptrace &= ~PT_TRACE_MASK;
-
-       if (data & PTRACE_O_TRACESYSGOOD)
-               child->ptrace |= PT_TRACESYSGOOD;
-
-       if (data & PTRACE_O_TRACEFORK)
-               child->ptrace |= PT_TRACE_FORK;
-
-       if (data & PTRACE_O_TRACEVFORK)
-               child->ptrace |= PT_TRACE_VFORK;
-
-       if (data & PTRACE_O_TRACECLONE)
-               child->ptrace |= PT_TRACE_CLONE;
-
-       if (data & PTRACE_O_TRACEEXEC)
-               child->ptrace |= PT_TRACE_EXEC;
-
-       if (data & PTRACE_O_TRACEVFORKDONE)
-               child->ptrace |= PT_TRACE_VFORK_DONE;
-
-       if (data & PTRACE_O_TRACEEXIT)
-               child->ptrace |= PT_TRACE_EXIT;
+       /* Avoid intermediate state when all opts are cleared */
+       flags = child->ptrace;
+       flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT);
+       flags |= (data << PT_OPT_FLAG_SHIFT);
+       child->ptrace = flags;
 
        return 0;
 }
@@ -894,7 +874,7 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
        }
 
        if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
-               ret = ptrace_attach(child, request, data);
+               ret = ptrace_attach(child, request, addr, data);
                /*
                 * Some architectures need to do book-keeping after
                 * a ptrace attach.
@@ -1037,7 +1017,7 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
        }
 
        if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
-               ret = ptrace_attach(child, request, data);
+               ret = ptrace_attach(child, request, addr, data);
                /*
                 * Some architectures need to do book-keeping after
                 * a ptrace attach.