Merge tag 'ptrace-cleanups-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / kernel / signal.c
index e93de6d..368a34c 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/signal.h>
 #include <linux/signalfd.h>
 #include <linux/ratelimit.h>
-#include <linux/tracehook.h>
+#include <linux/task_work.h>
 #include <linux/capability.h>
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
@@ -2229,14 +2229,17 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
  * That makes it a way to test a stopped process for
  * being ptrace-stopped vs being job-control-stopped.
  *
- * If we actually decide not to stop at all because the tracer
- * is gone, we keep current->exit_code unless clear_code.
+ * Returns the signal the ptracer requested the code resume
+ * with.  If the code did not stop because the tracer is gone,
+ * the stop signal remains unchanged unless clear_code.
  */
-static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t *info)
+static int ptrace_stop(int exit_code, int why, int clear_code,
+                       unsigned long message, kernel_siginfo_t *info)
        __releases(&current->sighand->siglock)
        __acquires(&current->sighand->siglock)
 {
        bool gstop_done = false;
+       bool read_code = true;
 
        if (arch_ptrace_stop_needed()) {
                /*
@@ -2278,6 +2281,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
         */
        smp_wmb();
 
+       current->ptrace_message = message;
        current->last_siginfo = info;
        current->exit_code = exit_code;
 
@@ -2344,8 +2348,9 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
 
                /* tasklist protects us from ptrace_freeze_traced() */
                __set_current_state(TASK_RUNNING);
+               read_code = false;
                if (clear_code)
-                       current->exit_code = 0;
+                       exit_code = 0;
                read_unlock(&tasklist_lock);
        }
 
@@ -2355,7 +2360,11 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
         * any signal-sending on another CPU that wants to examine it.
         */
        spin_lock_irq(&current->sighand->siglock);
+       if (read_code)
+               exit_code = current->exit_code;
        current->last_siginfo = NULL;
+       current->ptrace_message = 0;
+       current->exit_code = 0;
 
        /* LISTENING can be set only during STOP traps, clear it */
        current->jobctl &= ~JOBCTL_LISTENING;
@@ -2366,9 +2375,10 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
         * This sets TIF_SIGPENDING, but never clears it.
         */
        recalc_sigpending_tsk(current);
+       return exit_code;
 }
 
-static void ptrace_do_notify(int signr, int exit_code, int why)
+static int ptrace_do_notify(int signr, int exit_code, int why, unsigned long message)
 {
        kernel_siginfo_t info;
 
@@ -2379,18 +2389,21 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
        info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
 
        /* Let the debugger run.  */
-       ptrace_stop(exit_code, why, 1, &info);
+       return ptrace_stop(exit_code, why, 1, message, &info);
 }
 
-void ptrace_notify(int exit_code)
+int ptrace_notify(int exit_code, unsigned long message)
 {
+       int signr;
+
        BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
-       if (unlikely(current->task_works))
+       if (unlikely(task_work_pending(current)))
                task_work_run();
 
        spin_lock_irq(&current->sighand->siglock);
-       ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED);
+       signr = ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED, message);
        spin_unlock_irq(&current->sighand->siglock);
+       return signr;
 }
 
 /**
@@ -2545,11 +2558,10 @@ static void do_jobctl_trap(void)
                        signr = SIGTRAP;
                WARN_ON_ONCE(!signr);
                ptrace_do_notify(signr, signr | (PTRACE_EVENT_STOP << 8),
-                                CLD_STOPPED);
+                                CLD_STOPPED, 0);
        } else {
                WARN_ON_ONCE(!signr);
-               ptrace_stop(signr, CLD_STOPPED, 0, NULL);
-               current->exit_code = 0;
+               ptrace_stop(signr, CLD_STOPPED, 0, 0, NULL);
        }
 }
 
@@ -2602,15 +2614,12 @@ static int ptrace_signal(int signr, kernel_siginfo_t *info, enum pid_type type)
         * comment in dequeue_signal().
         */
        current->jobctl |= JOBCTL_STOP_DEQUEUED;
-       ptrace_stop(signr, CLD_TRAPPED, 0, info);
+       signr = ptrace_stop(signr, CLD_TRAPPED, 0, 0, info);
 
        /* We're back.  Did the debugger cancel the sig?  */
-       signr = current->exit_code;
        if (signr == 0)
                return signr;
 
-       current->exit_code = 0;
-
        /*
         * Update the siginfo structure if the signal has
         * changed.  If the debugger wanted something
@@ -2667,20 +2676,12 @@ bool get_signal(struct ksignal *ksig)
        struct signal_struct *signal = current->signal;
        int signr;
 
-       if (unlikely(current->task_works))
+       clear_notify_signal();
+       if (unlikely(task_work_pending(current)))
                task_work_run();
 
-       /*
-        * For non-generic architectures, check for TIF_NOTIFY_SIGNAL so
-        * that the arch handlers don't all have to do it. If we get here
-        * without TIF_SIGPENDING, just exit after running signal work.
-        */
-       if (!IS_ENABLED(CONFIG_GENERIC_ENTRY)) {
-               if (test_thread_flag(TIF_NOTIFY_SIGNAL))
-                       tracehook_notify_signal();
-               if (!task_sigpending(current))
-                       return false;
-       }
+       if (!task_sigpending(current))
+               return false;
 
        if (unlikely(uprobe_deny_signal()))
                return false;
@@ -2939,7 +2940,8 @@ static void signal_delivered(struct ksignal *ksig, int stepping)
        set_current_blocked(&blocked);
        if (current->sas_ss_flags & SS_AUTODISARM)
                sas_ss_reset(current);
-       tracehook_signal_handler(stepping);
+       if (stepping)
+               ptrace_notify(SIGTRAP, 0);
 }
 
 void signal_setup_done(int failed, struct ksignal *ksig, int stepping)