diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-09-18 08:40:07 -0400 |
---|---|---|
committer | Matt Turner <mattst88@gmail.com> | 2010-09-18 23:08:28 -0400 |
commit | 392fb6e35400edbee183baba24b34a0fa2053813 (patch) | |
tree | e11587c8b7ca75ab41b23f9e09e2c6a9365e2187 /arch/alpha/kernel/signal.c | |
parent | 2deba1bd7126aadb5750beb927c878a6490065e6 (diff) |
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>
Diffstat (limited to 'arch/alpha/kernel/signal.c')
-rw-r--r-- | arch/alpha/kernel/signal.c | 38 |
1 files changed, 1 insertions, 37 deletions
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index e5b1b3c79ff3..0f6b51ae865a 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
@@ -144,8 +144,7 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, | |||
144 | /* | 144 | /* |
145 | * Atomically swap in the new signal mask, and wait for a signal. | 145 | * Atomically swap in the new signal mask, and wait for a signal. |
146 | */ | 146 | */ |
147 | asmlinkage int | 147 | SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) |
148 | do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) | ||
149 | { | 148 | { |
150 | mask &= _BLOCKABLE; | 149 | mask &= _BLOCKABLE; |
151 | spin_lock_irq(¤t->sighand->siglock); | 150 | spin_lock_irq(¤t->sighand->siglock); |
@@ -154,41 +153,6 @@ do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) | |||
154 | recalc_sigpending(); | 153 | recalc_sigpending(); |
155 | spin_unlock_irq(¤t->sighand->siglock); | 154 | spin_unlock_irq(¤t->sighand->siglock); |
156 | 155 | ||
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(¤t->sighand->siglock); | ||
182 | current->saved_sigmask = current->blocked; | ||
183 | current->blocked = set; | ||
184 | recalc_sigpending(); | ||
185 | spin_unlock_irq(¤t->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 | |||
192 | current->state = TASK_INTERRUPTIBLE; | 156 | current->state = TASK_INTERRUPTIBLE; |
193 | schedule(); | 157 | schedule(); |
194 | set_thread_flag(TIF_RESTORE_SIGMASK); | 158 | set_thread_flag(TIF_RESTORE_SIGMASK); |