aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal.c
diff options
context:
space:
mode:
authorAl Viro <viro@ftp.linux.org.uk>2010-09-28 13:50:37 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-10-18 11:59:02 -0400
commit8f5a00eb422ed86e77bb8f67e08b9fe6d30f679a (patch)
tree6b625361c9581fb71fd2d005b5de54804d4f9798 /arch/mips/kernel/signal.c
parente5b377a8fb7b05f27647698ac739a0504cb2bf80 (diff)
MIPS: Sanitize restart logics
Put the original syscall number into ->regs[0] when we leave syscall with error. Use it in restart logics. Everything else will have it 0 since we pass through SAVE_SOME on all the ways in. Note that in places like bad_stack and inllegal_syscall we leave it 0 - it's not restartable. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Cc: linux-kernel@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1698/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r--arch/mips/kernel/signal.c37
1 files changed, 18 insertions, 19 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index b3273aeaeedc..604f077bb5bf 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -550,23 +550,26 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
550 struct mips_abi *abi = current->thread.abi; 550 struct mips_abi *abi = current->thread.abi;
551 void *vdso = current->mm->context.vdso; 551 void *vdso = current->mm->context.vdso;
552 552
553 switch(regs->regs[0]) { 553 if (regs->regs[0]) {
554 case ERESTART_RESTARTBLOCK: 554 switch(regs->regs[2]) {
555 case ERESTARTNOHAND: 555 case ERESTART_RESTARTBLOCK:
556 regs->regs[2] = EINTR; 556 case ERESTARTNOHAND:
557 break;
558 case ERESTARTSYS:
559 if (!(ka->sa.sa_flags & SA_RESTART)) {
560 regs->regs[2] = EINTR; 557 regs->regs[2] = EINTR;
561 break; 558 break;
559 case ERESTARTSYS:
560 if (!(ka->sa.sa_flags & SA_RESTART)) {
561 regs->regs[2] = EINTR;
562 break;
563 }
564 /* fallthrough */
565 case ERESTARTNOINTR:
566 regs->regs[7] = regs->regs[26];
567 regs->regs[2] = regs->regs[0];
568 regs->cp0_epc -= 4;
562 } 569 }
563 /* fallthrough */
564 case ERESTARTNOINTR: /* Userland will reload $v0. */
565 regs->regs[7] = regs->regs[26];
566 regs->cp0_epc -= 8;
567 }
568 570
569 regs->regs[0] = 0; /* Don't deal with this again. */ 571 regs->regs[0] = 0; /* Don't deal with this again. */
572 }
570 573
571 if (sig_uses_siginfo(ka)) 574 if (sig_uses_siginfo(ka))
572 ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, 575 ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
@@ -625,17 +628,13 @@ static void do_signal(struct pt_regs *regs)
625 return; 628 return;
626 } 629 }
627 630
628 /*
629 * Who's code doesn't conform to the restartable syscall convention
630 * dies here!!! The li instruction, a single machine instruction,
631 * must directly be followed by the syscall instruction.
632 */
633 if (regs->regs[0]) { 631 if (regs->regs[0]) {
634 if (regs->regs[2] == ERESTARTNOHAND || 632 if (regs->regs[2] == ERESTARTNOHAND ||
635 regs->regs[2] == ERESTARTSYS || 633 regs->regs[2] == ERESTARTSYS ||
636 regs->regs[2] == ERESTARTNOINTR) { 634 regs->regs[2] == ERESTARTNOINTR) {
635 regs->regs[2] = regs->regs[0];
637 regs->regs[7] = regs->regs[26]; 636 regs->regs[7] = regs->regs[26];
638 regs->cp0_epc -= 8; 637 regs->cp0_epc -= 4;
639 } 638 }
640 if (regs->regs[2] == ERESTART_RESTARTBLOCK) { 639 if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
641 regs->regs[2] = current->thread.abi->restart; 640 regs->regs[2] = current->thread.abi->restart;