Commit 392fb6e35400edbee183baba24b34a0fa2053813

Authored by Al Viro
Committed by Matt Turner
1 parent 2deba1bd71

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>

Showing 3 changed files with 2 additions and 69 deletions Side-by-side Diff

arch/alpha/include/asm/unistd.h
... ... @@ -466,6 +466,7 @@
466 466 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
467 467 #define __ARCH_WANT_SYS_OLDUMOUNT
468 468 #define __ARCH_WANT_SYS_SIGPENDING
  469 +#define __ARCH_WANT_SYS_RT_SIGSUSPEND
469 470  
470 471 /* "Conditional" syscalls. What we want is
471 472  
arch/alpha/kernel/entry.S
... ... @@ -779,38 +779,6 @@
779 779 .end sys_rt_sigreturn
780 780  
781 781 .align 4
782   - .globl sys_sigsuspend
783   - .ent sys_sigsuspend
784   -sys_sigsuspend:
785   - .prologue 0
786   - mov $sp, $17
787   - br $1, do_switch_stack
788   - mov $sp, $18
789   - subq $sp, 16, $sp
790   - stq $26, 0($sp)
791   - jsr $26, do_sigsuspend
792   - ldq $26, 0($sp)
793   - lda $sp, SWITCH_STACK_SIZE+16($sp)
794   - ret
795   -.end sys_sigsuspend
796   -
797   - .align 4
798   - .globl sys_rt_sigsuspend
799   - .ent sys_rt_sigsuspend
800   -sys_rt_sigsuspend:
801   - .prologue 0
802   - mov $sp, $18
803   - br $1, do_switch_stack
804   - mov $sp, $19
805   - subq $sp, 16, $sp
806   - stq $26, 0($sp)
807   - jsr $26, do_rt_sigsuspend
808   - ldq $26, 0($sp)
809   - lda $sp, SWITCH_STACK_SIZE+16($sp)
810   - ret
811   -.end sys_rt_sigsuspend
812   -
813   - .align 4
814 782 .globl sys_sethae
815 783 .ent sys_sethae
816 784 sys_sethae:
arch/alpha/kernel/signal.c
... ... @@ -144,8 +144,7 @@
144 144 /*
145 145 * Atomically swap in the new signal mask, and wait for a signal.
146 146 */
147   -asmlinkage int
148   -do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
  147 +SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
149 148 {
150 149 mask &= _BLOCKABLE;
151 150 spin_lock_irq(&current->sighand->siglock);
... ... @@ -153,41 +152,6 @@
153 152 siginitset(&current->blocked, mask);
154 153 recalc_sigpending();
155 154 spin_unlock_irq(&current->sighand->siglock);
156   -
157   - /* Indicate EINTR on return from any possible signal handler,
158   - which will not come back through here, but via sigreturn. */
159   - regs->r0 = EINTR;
160   - regs->r19 = 1;
161   -
162   - current->state = TASK_INTERRUPTIBLE;
163   - schedule();
164   - set_thread_flag(TIF_RESTORE_SIGMASK);
165   - return -ERESTARTNOHAND;
166   -}
167   -
168   -asmlinkage int
169   -do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
170   - struct pt_regs *regs, struct switch_stack *sw)
171   -{
172   - sigset_t set;
173   -
174   - /* XXX: Don't preclude handling different sized sigset_t's. */
175   - if (sigsetsize != sizeof(sigset_t))
176   - return -EINVAL;
177   - if (copy_from_user(&set, uset, sizeof(set)))
178   - return -EFAULT;
179   -
180   - sigdelsetmask(&set, ~_BLOCKABLE);
181   - spin_lock_irq(&current->sighand->siglock);
182   - current->saved_sigmask = current->blocked;
183   - current->blocked = set;
184   - recalc_sigpending();
185   - spin_unlock_irq(&current->sighand->siglock);
186   -
187   - /* Indicate EINTR on return from any possible signal handler,
188   - which will not come back through here, but via sigreturn. */
189   - regs->r0 = EINTR;
190   - regs->r19 = 1;
191 155  
192 156 current->state = TASK_INTERRUPTIBLE;
193 157 schedule();