- Reintroduce tracehook_get_signal() as utrace_hook_signal().

- Change get_signal_to_deliver() to call utrace_hook_signal() first,
  before dequeue_signal()

- Always call ptrace_signal() if signal != SIGKILL, no matter whether
  this signal comes from utrace or not.

  Since this can change signr again, update "struct k_sigaction *ka"
  in this case.

IOW, roughly, ptrace acts as if it is the last attached engine, it
takes the final decision about the signal.

Signed-off-by: Oleg Nesterov <o...@redhat.com>
---
 include/linux/utrace.h |   31 +++++++++++++++++++++++++++++++
 kernel/signal.c        |   30 ++++++++++++++++++++----------
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/include/linux/utrace.h b/include/linux/utrace.h
index 0279c74..63103e2 100644
--- a/include/linux/utrace.h
+++ b/include/linux/utrace.h
@@ -730,4 +730,35 @@ static inline void utrace_end_stop(void)
                utrace_finish_stop();
 }
 
+/**
+ * utrace_hook_signal - deliver synthetic signal to traced task
+ * @task:              @current
+ * @regs:              task_pt_regs(@current)
+ * @info:              details of synthetic signal
+ * @return_ka:         sigaction for synthetic signal
+ *
+ * Return zero to check for a real pending signal normally.
+ * Return -1 after releasing the siglock to repeat the check.
+ * Return a signal number to induce an artificial signal delivery,
+ * setting *@info and *@return_ka to specify its details and behavior.
+ *
+ * The @return_ka->sa_handler value controls the disposition of the
+ * signal, no matter the signal number.  For %SIG_DFL, the return value
+ * is a representative signal to indicate the behavior (e.g. %SIGTERM
+ * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop,
+ * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number
+ * reported will be @info->si_signo instead.
+ *
+ * Called with @task->sighand->siglock held, before dequeuing pending signals.
+ */
+static inline int utrace_hook_signal(struct task_struct *task,
+                                      struct pt_regs *regs,
+                                      siginfo_t *info,
+                                      struct k_sigaction *return_ka)
+{
+       if (unlikely(task_utrace_flags(task)))
+               return utrace_get_signal(task, regs, info, return_ka);
+       return 0;
+}
+
 #endif /* linux/utrace.h */
diff --git a/kernel/signal.c b/kernel/signal.c
index 249760f..3c783d3 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2234,17 +2234,27 @@ relock:
        for (;;) {
                struct k_sigaction *ka;
 
-               if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) &&
-                   do_signal_stop(0))
+               signr = utrace_hook_signal(current, regs, info, return_ka);
+               if (unlikely(signr < 0))
                        goto relock;
 
-               if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) {
-                       do_jobctl_trap();
-                       spin_unlock_irq(&sighand->siglock);
-                       goto relock;
-               }
+               if (unlikely(signr != 0))
+                       ka = return_ka;
+               else {
+                       if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) &&
+                           do_signal_stop(0))
+                               goto relock;
 
-               signr = dequeue_signal(current, &current->blocked, info);
+                       if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) {
+                               do_jobctl_trap();
+                               spin_unlock_irq(&sighand->siglock);
+                               goto relock;
+                       }
+
+                       signr = dequeue_signal(current, &current->blocked, 
info);
+
+                       ka = &sighand->action[signr-1];
+               }
 
                if (!signr)
                        break; /* will return 0 */
@@ -2254,9 +2264,9 @@ relock:
                                              regs, cookie);
                        if (!signr)
                                continue;
-               }
 
-               ka = &sighand->action[signr-1];
+                       ka = &sighand->action[signr-1];
+               }
 
                /* Trace actually delivered signals. */
                trace_signal_deliver(signr, info, ka);
-- 
1.5.5.1


Reply via email to