Commit bb9c861ee1b94c97cd98c783a2b4c1cf53ff1712
Committed by
Linus Torvalds
1 parent
a05c4e1d66
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 17 additions and 21 deletions Side-by-side Diff
arch/m32r/kernel/signal.c
... | ... | @@ -251,6 +251,19 @@ |
251 | 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 | 268 | * OK, we're invoking a handler |
256 | 269 | */ |
... | ... | @@ -259,8 +272,6 @@ |
259 | 272 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, |
260 | 273 | sigset_t *oldset, struct pt_regs *regs) |
261 | 274 | { |
262 | - unsigned short inst; | |
263 | - | |
264 | 275 | /* Are we from a system call? */ |
265 | 276 | if (regs->syscall_nr >= 0) { |
266 | 277 | /* If so, check system call restarting.. */ |
... | ... | @@ -278,12 +289,8 @@ |
278 | 289 | /* fallthrough */ |
279 | 290 | case -ERESTARTNOINTR: |
280 | 291 | regs->r0 = regs->orig_r0; |
281 | - inst = *(unsigned short *)(regs->bpc - 2); | |
282 | - if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | |
283 | - regs->bpc -= 2; | |
284 | - else | |
285 | - regs->bpc -= 4; | |
286 | - regs->syscall_nr = -1; | |
292 | + if (prev_insn(regs) < 0) | |
293 | + return -EFAULT; | |
287 | 294 | } |
288 | 295 | } |
289 | 296 | |
... | ... | @@ -310,7 +317,6 @@ |
310 | 317 | siginfo_t info; |
311 | 318 | int signr; |
312 | 319 | struct k_sigaction ka; |
313 | - unsigned short inst; | |
314 | 320 | sigset_t *oldset; |
315 | 321 | |
316 | 322 | /* |
317 | 323 | |
... | ... | @@ -353,21 +359,11 @@ |
353 | 359 | regs->r0 == -ERESTARTSYS || |
354 | 360 | regs->r0 == -ERESTARTNOINTR) { |
355 | 361 | regs->r0 = regs->orig_r0; |
356 | - inst = *(unsigned short *)(regs->bpc - 2); | |
357 | - if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | |
358 | - regs->bpc -= 2; | |
359 | - else | |
360 | - regs->bpc -= 4; | |
361 | - regs->syscall_nr = -1; | |
362 | + prev_insn(regs); | |
362 | 363 | } else if (regs->r0 == -ERESTART_RESTARTBLOCK){ |
363 | 364 | regs->r0 = regs->orig_r0; |
364 | 365 | regs->r7 = __NR_restart_syscall; |
365 | - inst = *(unsigned short *)(regs->bpc - 2); | |
366 | - if ((inst & 0xfff0) == 0x10f0) /* trap ? */ | |
367 | - regs->bpc -= 2; | |
368 | - else | |
369 | - regs->bpc -= 4; | |
370 | - regs->syscall_nr = -1; | |
366 | + prev_insn(regs); | |
371 | 367 | } |
372 | 368 | } |
373 | 369 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |