diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-09-24 01:24:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-09-24 16:54:19 -0400 |
commit | bb9c861ee1b94c97cd98c783a2b4c1cf53ff1712 (patch) | |
tree | 91052edab9906811181b9701d5a450fb1107cebe /arch/m32r/kernel/signal.c | |
parent | a05c4e1d669d09faa90ce7b22646ad1a4b0de3ff (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.c | 38 |
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 | ||
254 | static 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 | |||
259 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 272 | handle_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)) { |