[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, &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 */
@@ -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