aboutsummaryrefslogtreecommitdiff
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-08-02 20:17:49 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-08-02 20:17:49 -0700
commitae74c3b69a08e1de20cb681ec959f3a48af0006a (patch)
tree97def06a79fdaee2294ef197666a369b18728058 /kernel/signal.c
parent202668ecb6cb221460d884598dd4cd2e1f3292f3 (diff)
Fix force_sig_info() semantics after cleanups
Suresh points out that commit b0423a0d9cc836b2c3d796623cd19236bfedfe63 broke the semantics of a synchronous signal like SIGSEGV occurring recursively inside its own handler handler (or, indeed, any other context when the signal was blocked). That was unintentional, and this fixes things up by reinstating the old semantics, but without reverting the cleanups. Cc: Paul E. McKenney <paulmck@us.ibm.com> Acked-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 7fe874d12fa..bfdb5686fa3 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -791,22 +791,31 @@ out:
/*
* Force a signal that the process can't ignore: if necessary
* we unblock the signal and change any SIG_IGN to SIG_DFL.
+ *
+ * Note: If we unblock the signal, we always reset it to SIG_DFL,
+ * since we do not want to have a signal handler that was blocked
+ * be invoked when user space had explicitly blocked it.
+ *
+ * We don't want to have recursive SIGSEGV's etc, for example.
*/
-
int
force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{
unsigned long int flags;
- int ret;
+ int ret, blocked, ignored;
+ struct k_sigaction *action;
spin_lock_irqsave(&t->sighand->siglock, flags);
- if (t->sighand->action[sig-1].sa.sa_handler == SIG_IGN) {
- t->sighand->action[sig-1].sa.sa_handler = SIG_DFL;
- }
- if (sigismember(&t->blocked, sig)) {
- sigdelset(&t->blocked, sig);
+ action = &t->sighand->action[sig-1];
+ ignored = action->sa.sa_handler == SIG_IGN;
+ blocked = sigismember(&t->blocked, sig);
+ if (blocked || ignored) {
+ action->sa.sa_handler = SIG_DFL;
+ if (blocked) {
+ sigdelset(&t->blocked, sig);
+ recalc_sigpending_tsk(t);
+ }
}
- recalc_sigpending_tsk(t);
ret = specific_send_sig_info(sig, info, t);
spin_unlock_irqrestore(&t->sighand->siglock, flags);