Commit 392fb6e3 authored by Al Viro's avatar Al Viro Committed by Matt Turner

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: default avatarMichael Cree <mcree@orcon.net.nz>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarMatt Turner <mattst88@gmail.com>
parent 2deba1bd
......@@ -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(&current->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(&current->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(&current->sighand->siglock);
current->saved_sigmask = current->blocked;
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->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);
......
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