drm/nouveau: Implement mmap as GEM object function
[linux-2.6-microblaze.git] / kernel / ptrace.c
index 821cf17..2997ca6 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/cn_proc.h>
 #include <linux/compat.h>
 #include <linux/sched/signal.h>
+#include <linux/minmax.h>
 
 #include <asm/syscall.h>       /* for syscall_get_* */
 
@@ -169,6 +170,21 @@ void __ptrace_unlink(struct task_struct *child)
        spin_unlock(&child->sighand->siglock);
 }
 
+static bool looks_like_a_spurious_pid(struct task_struct *task)
+{
+       if (task->exit_code != ((PTRACE_EVENT_EXEC << 8) | SIGTRAP))
+               return false;
+
+       if (task_pid_vnr(task) == task->ptrace_message)
+               return false;
+       /*
+        * The tracee changed its pid but the PTRACE_EVENT_EXEC event
+        * was not wait()'ed, most probably debugger targets the old
+        * leader which was destroyed in de_thread().
+        */
+       return true;
+}
+
 /* Ensure that nothing can wake it up, even SIGKILL */
 static bool ptrace_freeze_traced(struct task_struct *task)
 {
@@ -179,7 +195,8 @@ static bool ptrace_freeze_traced(struct task_struct *task)
                return ret;
 
        spin_lock_irq(&task->sighand->siglock);
-       if (task_is_traced(task) && !__fatal_signal_pending(task)) {
+       if (task_is_traced(task) && !looks_like_a_spurious_pid(task) &&
+           !__fatal_signal_pending(task)) {
                task->state = __TASK_TRACED;
                ret = true;
        }
@@ -375,7 +392,7 @@ static int ptrace_attach(struct task_struct *task, long request,
        audit_ptrace(task);
 
        retval = -EPERM;
-       if (unlikely(task->flags & (PF_KTHREAD | PF_IO_WORKER)))
+       if (unlikely(task->flags & PF_KTHREAD))
                goto out;
        if (same_thread_group(task, current))
                goto out;
@@ -779,6 +796,24 @@ static int ptrace_peek_siginfo(struct task_struct *child,
        return ret;
 }
 
+#ifdef CONFIG_RSEQ
+static long ptrace_get_rseq_configuration(struct task_struct *task,
+                                         unsigned long size, void __user *data)
+{
+       struct ptrace_rseq_configuration conf = {
+               .rseq_abi_pointer = (u64)(uintptr_t)task->rseq,
+               .rseq_abi_size = sizeof(*task->rseq),
+               .signature = task->rseq_sig,
+               .flags = 0,
+       };
+
+       size = min_t(unsigned long, size, sizeof(conf));
+       if (copy_to_user(data, &conf, size))
+               return -EFAULT;
+       return sizeof(conf);
+}
+#endif
+
 #ifdef PTRACE_SINGLESTEP
 #define is_singlestep(request)         ((request) == PTRACE_SINGLESTEP)
 #else
@@ -1222,6 +1257,12 @@ int ptrace_request(struct task_struct *child, long request,
                ret = seccomp_get_metadata(child, addr, datavp);
                break;
 
+#ifdef CONFIG_RSEQ
+       case PTRACE_GET_RSEQ_CONFIGURATION:
+               ret = ptrace_get_rseq_configuration(child, addr, datavp);
+               break;
+#endif
+
        default:
                break;
        }