- 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 <oleg@xxxxxxxxxx> --- 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, ¤t->blocked, info); + if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { + do_jobctl_trap(); + spin_unlock_irq(&sighand->siglock); + goto relock; + } + + signr = dequeue_signal(current, ¤t->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 _______________________________________________ kernel mailing list kernel@xxxxxxxxxxxxxxxxxxxxxxx https://admin.fedoraproject.org/mailman/listinfo/kernel