aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m32r/kernel/signal.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-09-24 01:24:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-09-24 16:54:19 -0400
commitbb9c861ee1b94c97cd98c783a2b4c1cf53ff1712 (patch)
tree91052edab9906811181b9701d5a450fb1107cebe /arch/m32r/kernel/signal.c
parenta05c4e1d669d09faa90ce7b22646ad1a4b0de3ff (diff)
m32r: hole in shifting pc back
It's a userland pointer; worse, an untrustable one since ptrace has just provided a chance to modify it. X-Roothole-Covering-Cabal: TINRCC Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/m32r/kernel/signal.c')
-rw-r--r--arch/m32r/kernel/signal.c38
1 files changed, 17 insertions, 21 deletions
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index a56fcbd8abe6..7bbe38645ed5 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -251,6 +251,19 @@ give_sigsegv:
251 return -EFAULT; 251 return -EFAULT;
252} 252}
253 253
254static int prev_insn(struct pt_regs *regs)
255{
256 u16 inst;
257 if (get_user(&inst, (u16 __user *)(regs->bpc - 2)))
258 return -EFAULT;
259 if ((inst & 0xfff0) == 0x10f0) /* trap ? */
260 regs->bpc -= 2;
261 else
262 regs->bpc -= 4;
263 regs->syscall_nr = -1;
264 return 0;
265}
266
254/* 267/*
255 * OK, we're invoking a handler 268 * OK, we're invoking a handler
256 */ 269 */
@@ -259,8 +272,6 @@ static int
259handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, 272handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
260 sigset_t *oldset, struct pt_regs *regs) 273 sigset_t *oldset, struct pt_regs *regs)
261{ 274{
262 unsigned short inst;
263
264 /* Are we from a system call? */ 275 /* Are we from a system call? */
265 if (regs->syscall_nr >= 0) { 276 if (regs->syscall_nr >= 0) {
266 /* If so, check system call restarting.. */ 277 /* If so, check system call restarting.. */
@@ -278,12 +289,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
278 /* fallthrough */ 289 /* fallthrough */
279 case -ERESTARTNOINTR: 290 case -ERESTARTNOINTR:
280 regs->r0 = regs->orig_r0; 291 regs->r0 = regs->orig_r0;
281 inst = *(unsigned short *)(regs->bpc - 2); 292 if (prev_insn(regs) < 0)
282 if ((inst & 0xfff0) == 0x10f0) /* trap ? */ 293 return -EFAULT;
283 regs->bpc -= 2;
284 else
285 regs->bpc -= 4;
286 regs->syscall_nr = -1;
287 } 294 }
288 } 295 }
289 296
@@ -310,7 +317,6 @@ static void do_signal(struct pt_regs *regs)
310 siginfo_t info; 317 siginfo_t info;
311 int signr; 318 int signr;
312 struct k_sigaction ka; 319 struct k_sigaction ka;
313 unsigned short inst;
314 sigset_t *oldset; 320 sigset_t *oldset;
315 321
316 /* 322 /*
@@ -353,21 +359,11 @@ static void do_signal(struct pt_regs *regs)
353 regs->r0 == -ERESTARTSYS || 359 regs->r0 == -ERESTARTSYS ||
354 regs->r0 == -ERESTARTNOINTR) { 360 regs->r0 == -ERESTARTNOINTR) {
355 regs->r0 = regs->orig_r0; 361 regs->r0 = regs->orig_r0;
356 inst = *(unsigned short *)(regs->bpc - 2); 362 prev_insn(regs);
357 if ((inst & 0xfff0) == 0x10f0) /* trap ? */
358 regs->bpc -= 2;
359 else
360 regs->bpc -= 4;
361 regs->syscall_nr = -1;
362 } else if (regs->r0 == -ERESTART_RESTARTBLOCK){ 363 } else if (regs->r0 == -ERESTART_RESTARTBLOCK){
363 regs->r0 = regs->orig_r0; 364 regs->r0 = regs->orig_r0;
364 regs->r7 = __NR_restart_syscall; 365 regs->r7 = __NR_restart_syscall;
365 inst = *(unsigned short *)(regs->bpc - 2); 366 prev_insn(regs);
366 if ((inst & 0xfff0) == 0x10f0) /* trap ? */
367 regs->bpc -= 2;
368 else
369 regs->bpc -= 4;
370 regs->syscall_nr = -1;
371 } 367 }
372 } 368 }
373 if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 369 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {