[PATCH 19/33] get_signal_to_deliver: restore/restructure utrace/ptrace signal reporting
Oleg Nesterov
oleg at redhat.com
Mon Nov 21 20:02:18 UTC 2011
- 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 at 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 9348da6..38ea4e6 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2242,17 +2242,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 */
@@ -2262,9 +2272,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
More information about the kernel
mailing list