diff options
author | George Anzinger <george@mvista.com> | 2006-01-08 04:02:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:13:53 -0500 |
commit | 71fabd5e4835309b4feca6209122ce56c595c461 (patch) | |
tree | 7d9467a4f9678d2271f82d48ec075a316cb1523f | |
parent | b5f545c880a2a47947ba2118b2509644ab7a2969 (diff) |
[PATCH] sigaction should clear all signals on SIG_IGN, not just < 32
While rooting aroung in the signal code trying to understand how to fix the
SIG_IGN ploy (set sig handler to SIG_IGN and flood system with high speed
repeating timers) I came across what, I think, is a problem in sigaction()
in that when processing a SIG_IGN request it flushes signals from 1 to
SIGRTMIN and leaves the rest. Attempt to fix this.
Signed-off-by: George Anzinger <george@mvista.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/linux/signal.h | 17 | ||||
-rw-r--r-- | kernel/signal.c | 34 |
2 files changed, 49 insertions, 2 deletions
diff --git a/include/linux/signal.h b/include/linux/signal.h index ea9eff16c4b7..b7d093520bb6 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h | |||
@@ -94,6 +94,23 @@ static inline int sigfindinword(unsigned long word) | |||
94 | 94 | ||
95 | #endif /* __HAVE_ARCH_SIG_BITOPS */ | 95 | #endif /* __HAVE_ARCH_SIG_BITOPS */ |
96 | 96 | ||
97 | static inline int sigisemptyset(sigset_t *set) | ||
98 | { | ||
99 | extern void _NSIG_WORDS_is_unsupported_size(void); | ||
100 | switch (_NSIG_WORDS) { | ||
101 | case 4: | ||
102 | return (set->sig[3] | set->sig[2] | | ||
103 | set->sig[1] | set->sig[0]) == 0; | ||
104 | case 2: | ||
105 | return (set->sig[1] | set->sig[0]) == 0; | ||
106 | case 1: | ||
107 | return set->sig[0] == 0; | ||
108 | default: | ||
109 | _NSIG_WORDS_is_unsupported_size(); | ||
110 | return 0; | ||
111 | } | ||
112 | } | ||
113 | |||
97 | #define sigmask(sig) (1UL << ((sig) - 1)) | 114 | #define sigmask(sig) (1UL << ((sig) - 1)) |
98 | 115 | ||
99 | #ifndef __HAVE_ARCH_SIG_SETOPS | 116 | #ifndef __HAVE_ARCH_SIG_SETOPS |
diff --git a/kernel/signal.c b/kernel/signal.c index 9b6fda5e87f1..e20724af9b36 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -625,6 +625,33 @@ void signal_wake_up(struct task_struct *t, int resume) | |||
625 | * Returns 1 if any signals were found. | 625 | * Returns 1 if any signals were found. |
626 | * | 626 | * |
627 | * All callers must be holding the siglock. | 627 | * All callers must be holding the siglock. |
628 | * | ||
629 | * This version takes a sigset mask and looks at all signals, | ||
630 | * not just those in the first mask word. | ||
631 | */ | ||
632 | static int rm_from_queue_full(sigset_t *mask, struct sigpending *s) | ||
633 | { | ||
634 | struct sigqueue *q, *n; | ||
635 | sigset_t m; | ||
636 | |||
637 | sigandsets(&m, mask, &s->signal); | ||
638 | if (sigisemptyset(&m)) | ||
639 | return 0; | ||
640 | |||
641 | signandsets(&s->signal, &s->signal, mask); | ||
642 | list_for_each_entry_safe(q, n, &s->list, list) { | ||
643 | if (sigismember(mask, q->info.si_signo)) { | ||
644 | list_del_init(&q->list); | ||
645 | __sigqueue_free(q); | ||
646 | } | ||
647 | } | ||
648 | return 1; | ||
649 | } | ||
650 | /* | ||
651 | * Remove signals in mask from the pending set and queue. | ||
652 | * Returns 1 if any signals were found. | ||
653 | * | ||
654 | * All callers must be holding the siglock. | ||
628 | */ | 655 | */ |
629 | static int rm_from_queue(unsigned long mask, struct sigpending *s) | 656 | static int rm_from_queue(unsigned long mask, struct sigpending *s) |
630 | { | 657 | { |
@@ -2408,6 +2435,7 @@ int | |||
2408 | do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) | 2435 | do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) |
2409 | { | 2436 | { |
2410 | struct k_sigaction *k; | 2437 | struct k_sigaction *k; |
2438 | sigset_t mask; | ||
2411 | 2439 | ||
2412 | if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) | 2440 | if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) |
2413 | return -EINVAL; | 2441 | return -EINVAL; |
@@ -2455,9 +2483,11 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) | |||
2455 | *k = *act; | 2483 | *k = *act; |
2456 | sigdelsetmask(&k->sa.sa_mask, | 2484 | sigdelsetmask(&k->sa.sa_mask, |
2457 | sigmask(SIGKILL) | sigmask(SIGSTOP)); | 2485 | sigmask(SIGKILL) | sigmask(SIGSTOP)); |
2458 | rm_from_queue(sigmask(sig), &t->signal->shared_pending); | 2486 | sigemptyset(&mask); |
2487 | sigaddset(&mask, sig); | ||
2488 | rm_from_queue_full(&mask, &t->signal->shared_pending); | ||
2459 | do { | 2489 | do { |
2460 | rm_from_queue(sigmask(sig), &t->pending); | 2490 | rm_from_queue_full(&mask, &t->pending); |
2461 | recalc_sigpending_tsk(t); | 2491 | recalc_sigpending_tsk(t); |
2462 | t = next_thread(t); | 2492 | t = next_thread(t); |
2463 | } while (t != current); | 2493 | } while (t != current); |