diff options
author | Roland McGrath <roland@redhat.com> | 2008-07-25 22:45:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-26 15:00:09 -0400 |
commit | 35de254dc60f91004b3b5ebb1fc7b2c3093d6032 (patch) | |
tree | 101e174247bb3174c8abe0fb8d1405ed6a4db6d1 | |
parent | c45aea27617d6a1e0aacddc3b0233f704222fcbd (diff) |
tracehook: tracehook_consider_ignored_signal
This defines tracehook_consider_ignored_signal() has a fine-grained hook
for deciding to prevent the normal short-circuit of sending an ignored
signal, as ptrace does. There is no change, only cleanup.
Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/tracehook.h | 19 | ||||
-rw-r--r-- | kernel/signal.c | 27 |
2 files changed, 35 insertions, 11 deletions
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 2d1426f8e33b..8cffd34f88d5 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h | |||
@@ -312,4 +312,23 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info, | |||
312 | ptrace_notify(SIGTRAP); | 312 | ptrace_notify(SIGTRAP); |
313 | } | 313 | } |
314 | 314 | ||
315 | /** | ||
316 | * tracehook_consider_ignored_signal - suppress short-circuit of ignored signal | ||
317 | * @task: task receiving the signal | ||
318 | * @sig: signal number being sent | ||
319 | * @handler: %SIG_IGN or %SIG_DFL | ||
320 | * | ||
321 | * Return zero iff tracing doesn't care to examine this ignored signal, | ||
322 | * so it can short-circuit normal delivery and never even get queued. | ||
323 | * Either @handler is %SIG_DFL and @sig's default is ignore, or it's %SIG_IGN. | ||
324 | * | ||
325 | * Called with @task->sighand->siglock held. | ||
326 | */ | ||
327 | static inline int tracehook_consider_ignored_signal(struct task_struct *task, | ||
328 | int sig, | ||
329 | void __user *handler) | ||
330 | { | ||
331 | return (task_ptrace(task) & PT_PTRACED) != 0; | ||
332 | } | ||
333 | |||
315 | #endif /* <linux/tracehook.h> */ | 334 | #endif /* <linux/tracehook.h> */ |
diff --git a/kernel/signal.c b/kernel/signal.c index 8715c18b27b9..9efd1cee6d0b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/signal.h> | 23 | #include <linux/signal.h> |
24 | #include <linux/signalfd.h> | 24 | #include <linux/signalfd.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <linux/capability.h> | 26 | #include <linux/capability.h> |
26 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
27 | #include <linux/pid_namespace.h> | 28 | #include <linux/pid_namespace.h> |
@@ -39,24 +40,21 @@ | |||
39 | 40 | ||
40 | static struct kmem_cache *sigqueue_cachep; | 41 | static struct kmem_cache *sigqueue_cachep; |
41 | 42 | ||
42 | static int __sig_ignored(struct task_struct *t, int sig) | 43 | static void __user *sig_handler(struct task_struct *t, int sig) |
43 | { | 44 | { |
44 | void __user *handler; | 45 | return t->sighand->action[sig - 1].sa.sa_handler; |
46 | } | ||
45 | 47 | ||
48 | static int sig_handler_ignored(void __user *handler, int sig) | ||
49 | { | ||
46 | /* Is it explicitly or implicitly ignored? */ | 50 | /* Is it explicitly or implicitly ignored? */ |
47 | |||
48 | handler = t->sighand->action[sig - 1].sa.sa_handler; | ||
49 | return handler == SIG_IGN || | 51 | return handler == SIG_IGN || |
50 | (handler == SIG_DFL && sig_kernel_ignore(sig)); | 52 | (handler == SIG_DFL && sig_kernel_ignore(sig)); |
51 | } | 53 | } |
52 | 54 | ||
53 | static int sig_ignored(struct task_struct *t, int sig) | 55 | static int sig_ignored(struct task_struct *t, int sig) |
54 | { | 56 | { |
55 | /* | 57 | void __user *handler; |
56 | * Tracers always want to know about signals.. | ||
57 | */ | ||
58 | if (t->ptrace & PT_PTRACED) | ||
59 | return 0; | ||
60 | 58 | ||
61 | /* | 59 | /* |
62 | * Blocked signals are never ignored, since the | 60 | * Blocked signals are never ignored, since the |
@@ -66,7 +64,14 @@ static int sig_ignored(struct task_struct *t, int sig) | |||
66 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) | 64 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) |
67 | return 0; | 65 | return 0; |
68 | 66 | ||
69 | return __sig_ignored(t, sig); | 67 | handler = sig_handler(t, sig); |
68 | if (!sig_handler_ignored(handler, sig)) | ||
69 | return 0; | ||
70 | |||
71 | /* | ||
72 | * Tracers may want to know about even ignored signals. | ||
73 | */ | ||
74 | return !tracehook_consider_ignored_signal(t, sig, handler); | ||
70 | } | 75 | } |
71 | 76 | ||
72 | /* | 77 | /* |
@@ -2298,7 +2303,7 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) | |||
2298 | * (for example, SIGCHLD), shall cause the pending signal to | 2303 | * (for example, SIGCHLD), shall cause the pending signal to |
2299 | * be discarded, whether or not it is blocked" | 2304 | * be discarded, whether or not it is blocked" |
2300 | */ | 2305 | */ |
2301 | if (__sig_ignored(t, sig)) { | 2306 | if (sig_handler_ignored(sig_handler(t, sig), sig)) { |
2302 | sigemptyset(&mask); | 2307 | sigemptyset(&mask); |
2303 | sigaddset(&mask, sig); | 2308 | sigaddset(&mask, sig); |
2304 | rm_from_queue_full(&mask, &t->signal->shared_pending); | 2309 | rm_from_queue_full(&mask, &t->signal->shared_pending); |