forked from Minki/linux
alpha: unb0rk sigsuspend() and rt_sigsuspend()
Old code used to set regs->r0 and regs->r19 to force the right return value. Leaving that after switch to ERESTARTNOHAND was a Bad Idea(tm), since now that screws the restart - if we hit the case when get_signal_to_deliver() returns 0, we will step back to syscall insn, with v0 set to EINTR and a3 to 1. The latter won't matter, since EINTR is 4, aka __NR_write. Testcase: #include <signal.h> #define _GNU_SOURCE #include <unistd.h> #include <sys/syscall.h> main() { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCONT); sigprocmask(SIG_SETMASK, &mask, NULL); kill(0, SIGCONT); syscall(__NR_sigsuspend, 1, "b0rken\n", 7); } results on alpha in immediate message to stdout... Fix is obvious; moreover, since we don't need regs anymore, we can switch to normal prototypes for these guys and lose the wrappers. Even better, rt_sigsuspend() is identical to generic version in kernel/signal.c now. Tested-by: Michael Cree <mcree@orcon.net.nz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Matt Turner <mattst88@gmail.com>
This commit is contained in:
parent
2deba1bd71
commit
392fb6e354
@ -466,6 +466,7 @@
|
||||
#define __ARCH_WANT_SYS_OLD_GETRLIMIT
|
||||
#define __ARCH_WANT_SYS_OLDUMOUNT
|
||||
#define __ARCH_WANT_SYS_SIGPENDING
|
||||
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
|
||||
|
||||
/* "Conditional" syscalls. What we want is
|
||||
|
||||
|
@ -778,38 +778,6 @@ sys_rt_sigreturn:
|
||||
br ret_from_sys_call
|
||||
.end sys_rt_sigreturn
|
||||
|
||||
.align 4
|
||||
.globl sys_sigsuspend
|
||||
.ent sys_sigsuspend
|
||||
sys_sigsuspend:
|
||||
.prologue 0
|
||||
mov $sp, $17
|
||||
br $1, do_switch_stack
|
||||
mov $sp, $18
|
||||
subq $sp, 16, $sp
|
||||
stq $26, 0($sp)
|
||||
jsr $26, do_sigsuspend
|
||||
ldq $26, 0($sp)
|
||||
lda $sp, SWITCH_STACK_SIZE+16($sp)
|
||||
ret
|
||||
.end sys_sigsuspend
|
||||
|
||||
.align 4
|
||||
.globl sys_rt_sigsuspend
|
||||
.ent sys_rt_sigsuspend
|
||||
sys_rt_sigsuspend:
|
||||
.prologue 0
|
||||
mov $sp, $18
|
||||
br $1, do_switch_stack
|
||||
mov $sp, $19
|
||||
subq $sp, 16, $sp
|
||||
stq $26, 0($sp)
|
||||
jsr $26, do_rt_sigsuspend
|
||||
ldq $26, 0($sp)
|
||||
lda $sp, SWITCH_STACK_SIZE+16($sp)
|
||||
ret
|
||||
.end sys_rt_sigsuspend
|
||||
|
||||
.align 4
|
||||
.globl sys_sethae
|
||||
.ent sys_sethae
|
||||
|
@ -144,8 +144,7 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
|
||||
/*
|
||||
* Atomically swap in the new signal mask, and wait for a signal.
|
||||
*/
|
||||
asmlinkage int
|
||||
do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
|
||||
SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
|
||||
{
|
||||
mask &= _BLOCKABLE;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
@ -154,41 +153,6 @@ do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
/* Indicate EINTR on return from any possible signal handler,
|
||||
which will not come back through here, but via sigreturn. */
|
||||
regs->r0 = EINTR;
|
||||
regs->r19 = 1;
|
||||
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
set_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
return -ERESTARTNOHAND;
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
|
||||
struct pt_regs *regs, struct switch_stack *sw)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
/* XXX: Don't preclude handling different sized sigset_t's. */
|
||||
if (sigsetsize != sizeof(sigset_t))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&set, uset, sizeof(set)))
|
||||
return -EFAULT;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->saved_sigmask = current->blocked;
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
/* Indicate EINTR on return from any possible signal handler,
|
||||
which will not come back through here, but via sigreturn. */
|
||||
regs->r0 = EINTR;
|
||||
regs->r19 = 1;
|
||||
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
set_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
|
Loading…
Reference in New Issue
Block a user