aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
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
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')
-rw-r--r--arch/mips/kernel/branch.c1
-rw-r--r--arch/mips/kernel/scall32-o32.S9
-rw-r--r--arch/mips/kernel/scall64-64.S7
-rw-r--r--arch/mips/kernel/scall64-n32.S6
-rw-r--r--arch/mips/kernel/scall64-o32.S7
-rw-r--r--arch/mips/kernel/signal.c37
-rw-r--r--arch/mips/kernel/unaligned.c2
7 files changed, 34 insertions, 35 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 0176ed015c89..32103cc2a257 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -40,7 +40,6 @@ int __compute_return_epc(struct pt_regs *regs)
40 return -EFAULT; 40 return -EFAULT;
41 } 41 }
42 42
43 regs->regs[0] = 0;
44 switch (insn.i_format.opcode) { 43 switch (insn.i_format.opcode) {
45 /* 44 /*
46 * jr and jalr are in r_format format. 45 * jr and jalr are in r_format format.
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 17202bbe843f..73a061e85531 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -63,9 +63,9 @@ stack_done:
63 sw t0, PT_R7(sp) # set error flag 63 sw t0, PT_R7(sp) # set error flag
64 beqz t0, 1f 64 beqz t0, 1f
65 65
66 lw t1, PT_R2(sp) # syscall number
66 negu v0 # error 67 negu v0 # error
67 sw v0, PT_R0(sp) # set flag for syscall 68 sw t1, PT_R0(sp) # save it for syscall restarting
68 # restarting
691: sw v0, PT_R2(sp) # result 691: sw v0, PT_R2(sp) # result
70 70
71o32_syscall_exit: 71o32_syscall_exit:
@@ -104,9 +104,9 @@ syscall_trace_entry:
104 sw t0, PT_R7(sp) # set error flag 104 sw t0, PT_R7(sp) # set error flag
105 beqz t0, 1f 105 beqz t0, 1f
106 106
107 lw t1, PT_R2(sp) # syscall number
107 negu v0 # error 108 negu v0 # error
108 sw v0, PT_R0(sp) # set flag for syscall 109 sw t1, PT_R0(sp) # save it for syscall restarting
109 # restarting
1101: sw v0, PT_R2(sp) # result 1101: sw v0, PT_R2(sp) # result
111 111
112 j syscall_exit 112 j syscall_exit
@@ -170,7 +170,6 @@ stackargs:
170 */ 170 */
171bad_stack: 171bad_stack:
172 negu v0 # error 172 negu v0 # error
173 sw v0, PT_R0(sp)
174 sw v0, PT_R2(sp) 173 sw v0, PT_R2(sp)
175 li t0, 1 # set error flag 174 li t0, 1 # set error flag
176 sw t0, PT_R7(sp) 175 sw t0, PT_R7(sp)
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index a8a6c596eb04..eb0bb73172c3 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -66,9 +66,9 @@ NESTED(handle_sys64, PT_SIZE, sp)
66 sd t0, PT_R7(sp) # set error flag 66 sd t0, PT_R7(sp) # set error flag
67 beqz t0, 1f 67 beqz t0, 1f
68 68
69 ld t1, PT_R2(sp) # syscall number
69 dnegu v0 # error 70 dnegu v0 # error
70 sd v0, PT_R0(sp) # set flag for syscall 71 sd t1, PT_R0(sp) # save it for syscall restarting
71 # restarting
721: sd v0, PT_R2(sp) # result 721: sd v0, PT_R2(sp) # result
73 73
74n64_syscall_exit: 74n64_syscall_exit:
@@ -109,8 +109,9 @@ syscall_trace_entry:
109 sd t0, PT_R7(sp) # set error flag 109 sd t0, PT_R7(sp) # set error flag
110 beqz t0, 1f 110 beqz t0, 1f
111 111
112 ld t1, PT_R2(sp) # syscall number
112 dnegu v0 # error 113 dnegu v0 # error
113 sd v0, PT_R0(sp) # set flag for syscall restarting 114 sd t1, PT_R0(sp) # save it for syscall restarting
1141: sd v0, PT_R2(sp) # result 1151: sd v0, PT_R2(sp) # result
115 116
116 j syscall_exit 117 j syscall_exit
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index a3d66137731a..4da3fafaa313 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -65,8 +65,9 @@ NESTED(handle_sysn32, PT_SIZE, sp)
65 sd t0, PT_R7(sp) # set error flag 65 sd t0, PT_R7(sp) # set error flag
66 beqz t0, 1f 66 beqz t0, 1f
67 67
68 ld t1, PT_R2(sp) # syscall number
68 dnegu v0 # error 69 dnegu v0 # error
69 sd v0, PT_R0(sp) # set flag for syscall restarting 70 sd t1, PT_R0(sp) # save it for syscall restarting
701: sd v0, PT_R2(sp) # result 711: sd v0, PT_R2(sp) # result
71 72
72 local_irq_disable # make sure need_resched and 73 local_irq_disable # make sure need_resched and
@@ -106,8 +107,9 @@ n32_syscall_trace_entry:
106 sd t0, PT_R7(sp) # set error flag 107 sd t0, PT_R7(sp) # set error flag
107 beqz t0, 1f 108 beqz t0, 1f
108 109
110 ld t1, PT_R2(sp) # syscall number
109 dnegu v0 # error 111 dnegu v0 # error
110 sd v0, PT_R0(sp) # set flag for syscall restarting 112 sd t1, PT_R0(sp) # save it for syscall restarting
1111: sd v0, PT_R2(sp) # result 1131: sd v0, PT_R2(sp) # result
112 114
113 j syscall_exit 115 j syscall_exit
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 813689ef2384..7ce0a3685627 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -93,8 +93,9 @@ NESTED(handle_sys, PT_SIZE, sp)
93 sd t0, PT_R7(sp) # set error flag 93 sd t0, PT_R7(sp) # set error flag
94 beqz t0, 1f 94 beqz t0, 1f
95 95
96 ld t1, PT_R2(sp) # syscall number
96 dnegu v0 # error 97 dnegu v0 # error
97 sd v0, PT_R0(sp) # flag for syscall restarting 98 sd t1, PT_R0(sp) # save it for syscall restarting
981: sd v0, PT_R2(sp) # result 991: sd v0, PT_R2(sp) # result
99 100
100o32_syscall_exit: 101o32_syscall_exit:
@@ -142,8 +143,9 @@ trace_a_syscall:
142 sd t0, PT_R7(sp) # set error flag 143 sd t0, PT_R7(sp) # set error flag
143 beqz t0, 1f 144 beqz t0, 1f
144 145
146 ld t1, PT_R2(sp) # syscall number
145 dnegu v0 # error 147 dnegu v0 # error
146 sd v0, PT_R0(sp) # set flag for syscall restarting 148 sd t1, PT_R0(sp) # save it for syscall restarting
1471: sd v0, PT_R2(sp) # result 1491: sd v0, PT_R2(sp) # result
148 150
149 j syscall_exit 151 j syscall_exit
@@ -155,7 +157,6 @@ trace_a_syscall:
155 */ 157 */
156bad_stack: 158bad_stack:
157 dnegu v0 # error 159 dnegu v0 # error
158 sd v0, PT_R0(sp)
159 sd v0, PT_R2(sp) 160 sd v0, PT_R2(sp)
160 li t0, 1 # set error flag 161 li t0, 1 # set error flag
161 sd t0, PT_R7(sp) 162 sd t0, PT_R7(sp)
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;
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 69b039ca8d83..33d5a5ce4a29 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -109,8 +109,6 @@ static void emulate_load_store_insn(struct pt_regs *regs,
109 unsigned long value; 109 unsigned long value;
110 unsigned int res; 110 unsigned int res;
111 111
112 regs->regs[0] = 0;
113
114 /* 112 /*
115 * This load never faults. 113 * This load never faults.
116 */ 114 */