Commit 44383059 authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

[PATCH] uml: fix signal mask on delivery error

From: Bodo Stroesser <bstroesser@fujitsu-siemens.com>

If the user stack limit is reached or the signal stack assigned with
sigaltstack() is invalid when a user signal handler with SA_ONSTACK has to be
started, the signal mask of the interrupted user program is modified.  This
happens because the mask, that should be used with the handler only, is
written to "current->blocked" even if the handler could not be started.  But
without a handler, no rewrite of the original mask at sys_sigreturn will be
done.

A slightly different case is sys_sigsuspend(), where the mask is already
modified when kern_do_signal() is started.  "*oldset" and "current->blocked"
are not equal here and thus current->blocked has to be set to *oldset, if an
error occurs in handle_signal().

For both cases I've written small tests, and with the patch the result is OK. 
This issue is relevant for other architectures too (e.g.  i386, I've seen).
Signed-off-by: default avatarJeff Dike <jdike@addtoit.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6dc56113
...@@ -79,7 +79,14 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr, ...@@ -79,7 +79,14 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
else else
err = setup_signal_stack_sc(sp, signr, ka, regs, oldset); err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
if (!err && !(ka->sa.sa_flags & SA_NODEFER)) { if(err){
spin_lock_irq(&current->sighand->siglock);
current->blocked = *oldset;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
force_sigsegv(signr, current);
}
else if(!(ka->sa.sa_flags & SA_NODEFER)){
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked, sigorsets(&current->blocked, &current->blocked,
&ka->sa.sa_mask); &ka->sa.sa_mask);
...@@ -87,9 +94,6 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr, ...@@ -87,9 +94,6 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
} }
if(err)
force_sigsegv(signr, current);
} }
static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset) static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment