Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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

+0 −32
Original line number Diff line number Diff line
@@ -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
+1 −37
Original line number Diff line number Diff line
@@ -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);