ptrace: implement PTRACE_SEIZE
[pandora-kernel.git] / kernel / ptrace.c
index 45a8a4c..dcf9f97 100644 (file)
@@ -209,10 +209,28 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
        return !err;
 }
 
-static int ptrace_attach(struct task_struct *task)
+static int ptrace_attach(struct task_struct *task, long request,
+                        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;
+
        audit_ptrace(task);
 
        retval = -EPERM;
@@ -244,11 +262,16 @@ static int ptrace_attach(struct task_struct *task)
                goto unlock_tasklist;
 
        task->ptrace = PT_PTRACED;
+       if (seize)
+               task->ptrace |= PT_SEIZED;
        if (task_ns_capable(task, CAP_SYS_PTRACE))
                task->ptrace |= PT_PTRACE_CAP;
 
        __ptrace_link(task, current);
-       send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
+
+       /* SEIZE doesn't trap tracee on attach */
+       if (!seize)
+               send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
 
        spin_lock(&task->sighand->siglock);
 
@@ -785,8 +808,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
                goto out;
        }
 
-       if (request == PTRACE_ATTACH) {
-               ret = ptrace_attach(child);
+       if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
+               ret = ptrace_attach(child, request, data);
                /*
                 * Some architectures need to do book-keeping after
                 * a ptrace attach.
@@ -927,8 +950,8 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
                goto out;
        }
 
-       if (request == PTRACE_ATTACH) {
-               ret = ptrace_attach(child);
+       if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
+               ret = ptrace_attach(child, request, data);
                /*
                 * Some architectures need to do book-keeping after
                 * a ptrace attach.