diff options
| -rw-r--r-- | arch/m68k/kernel/signal.c | 173 |
1 files changed, 61 insertions, 112 deletions
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 16ea319d1ed5..d5f4a82515f3 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c | |||
| @@ -286,36 +286,10 @@ out: | |||
| 286 | return err; | 286 | return err; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | static inline int | 289 | static int mangle_kernel_stack(struct pt_regs *regs, int formatvec, |
| 290 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp, | 290 | void __user *fp) |
| 291 | int *pd0) | ||
| 292 | { | 291 | { |
| 293 | int fsize, formatvec; | 292 | int fsize = frame_extra_sizes[formatvec >> 12]; |
| 294 | struct sigcontext context; | ||
| 295 | int err; | ||
| 296 | |||
| 297 | /* Always make any pending restarted system calls return -EINTR */ | ||
| 298 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
| 299 | |||
| 300 | /* get previous context */ | ||
| 301 | if (copy_from_user(&context, usc, sizeof(context))) | ||
| 302 | goto badframe; | ||
| 303 | |||
| 304 | /* restore passed registers */ | ||
| 305 | regs->d1 = context.sc_d1; | ||
| 306 | regs->a0 = context.sc_a0; | ||
| 307 | regs->a1 = context.sc_a1; | ||
| 308 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
| 309 | regs->pc = context.sc_pc; | ||
| 310 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
| 311 | wrusp(context.sc_usp); | ||
| 312 | formatvec = context.sc_formatvec; | ||
| 313 | regs->format = formatvec >> 12; | ||
| 314 | regs->vector = formatvec & 0xfff; | ||
| 315 | |||
| 316 | err = restore_fpu_state(&context); | ||
| 317 | |||
| 318 | fsize = frame_extra_sizes[regs->format]; | ||
| 319 | if (fsize < 0) { | 293 | if (fsize < 0) { |
| 320 | /* | 294 | /* |
| 321 | * user process trying to return with weird frame format | 295 | * user process trying to return with weird frame format |
| @@ -323,16 +297,22 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u | |||
| 323 | #ifdef DEBUG | 297 | #ifdef DEBUG |
| 324 | printk("user process returning with weird frame format\n"); | 298 | printk("user process returning with weird frame format\n"); |
| 325 | #endif | 299 | #endif |
| 326 | goto badframe; | 300 | return 1; |
| 327 | } | 301 | } |
| 302 | if (!fsize) { | ||
| 303 | regs->format = formatvec >> 12; | ||
| 304 | regs->vector = formatvec & 0xfff; | ||
| 305 | } else { | ||
| 306 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
| 307 | unsigned long buf[fsize / 2]; /* yes, twice as much */ | ||
| 328 | 308 | ||
| 329 | /* OK. Make room on the supervisor stack for the extra junk, | 309 | /* that'll make sure that expansion won't crap over data */ |
| 330 | * if necessary. | 310 | if (copy_from_user(buf + fsize / 4, fp, fsize)) |
| 331 | */ | 311 | return 1; |
| 332 | 312 | ||
| 333 | if (fsize) { | 313 | /* point of no return */ |
| 334 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | 314 | regs->format = formatvec >> 12; |
| 335 | regs->d0 = context.sc_d0; | 315 | regs->vector = formatvec & 0xfff; |
| 336 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | 316 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) |
| 337 | __asm__ __volatile__ | 317 | __asm__ __volatile__ |
| 338 | (" movel %0,%/a0\n\t" | 318 | (" movel %0,%/a0\n\t" |
| @@ -344,30 +324,50 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u | |||
| 344 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | 324 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ |
| 345 | " lsrl #2,%1\n\t" | 325 | " lsrl #2,%1\n\t" |
| 346 | " subql #1,%1\n\t" | 326 | " subql #1,%1\n\t" |
| 347 | "2: movesl %4@+,%2\n\t" | 327 | /* copy to the gap we'd made */ |
| 348 | "3: movel %2,%/a0@+\n\t" | 328 | "2: movel %4@+,%/a0@+\n\t" |
| 349 | " dbra %1,2b\n\t" | 329 | " dbra %1,2b\n\t" |
| 350 | " bral ret_from_signal\n" | 330 | " bral ret_from_signal\n" |
| 351 | "4:\n" | ||
| 352 | ".section __ex_table,\"a\"\n" | ||
| 353 | " .align 4\n" | ||
| 354 | " .long 2b,4b\n" | ||
| 355 | " .long 3b,4b\n" | ||
| 356 | ".previous" | ||
| 357 | : /* no outputs, it doesn't ever return */ | 331 | : /* no outputs, it doesn't ever return */ |
| 358 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | 332 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), |
| 359 | "n" (frame_offset), "a" (fp) | 333 | "n" (frame_offset), "a" (buf + fsize/4) |
| 360 | : "a0"); | 334 | : "a0"); |
| 361 | #undef frame_offset | 335 | #undef frame_offset |
| 362 | /* | ||
| 363 | * If we ever get here an exception occurred while | ||
| 364 | * building the above stack-frame. | ||
| 365 | */ | ||
| 366 | goto badframe; | ||
| 367 | } | 336 | } |
| 337 | return 0; | ||
| 338 | } | ||
| 368 | 339 | ||
| 369 | *pd0 = context.sc_d0; | 340 | static inline int |
| 370 | return err; | 341 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp) |
| 342 | { | ||
| 343 | int formatvec; | ||
| 344 | struct sigcontext context; | ||
| 345 | int err; | ||
| 346 | |||
| 347 | /* Always make any pending restarted system calls return -EINTR */ | ||
| 348 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
| 349 | |||
| 350 | /* get previous context */ | ||
| 351 | if (copy_from_user(&context, usc, sizeof(context))) | ||
| 352 | goto badframe; | ||
| 353 | |||
| 354 | /* restore passed registers */ | ||
| 355 | regs->d0 = context.sc_d0; | ||
| 356 | regs->d1 = context.sc_d1; | ||
| 357 | regs->a0 = context.sc_a0; | ||
| 358 | regs->a1 = context.sc_a1; | ||
| 359 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
| 360 | regs->pc = context.sc_pc; | ||
| 361 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
| 362 | wrusp(context.sc_usp); | ||
| 363 | formatvec = context.sc_formatvec; | ||
| 364 | |||
| 365 | err = restore_fpu_state(&context); | ||
| 366 | |||
| 367 | if (err || mangle_kernel_stack(regs, formatvec, fp)) | ||
| 368 | goto badframe; | ||
| 369 | |||
| 370 | return 0; | ||
| 371 | 371 | ||
| 372 | badframe: | 372 | badframe: |
| 373 | return 1; | 373 | return 1; |
| @@ -375,9 +375,9 @@ badframe: | |||
| 375 | 375 | ||
| 376 | static inline int | 376 | static inline int |
| 377 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | 377 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, |
| 378 | struct ucontext __user *uc, int *pd0) | 378 | struct ucontext __user *uc) |
| 379 | { | 379 | { |
| 380 | int fsize, temp; | 380 | int temp; |
| 381 | greg_t __user *gregs = uc->uc_mcontext.gregs; | 381 | greg_t __user *gregs = uc->uc_mcontext.gregs; |
| 382 | unsigned long usp; | 382 | unsigned long usp; |
| 383 | int err; | 383 | int err; |
| @@ -411,65 +411,16 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | |||
| 411 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | 411 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); |
| 412 | regs->orig_d0 = -1; /* disable syscall checks */ | 412 | regs->orig_d0 = -1; /* disable syscall checks */ |
| 413 | err |= __get_user(temp, &uc->uc_formatvec); | 413 | err |= __get_user(temp, &uc->uc_formatvec); |
| 414 | regs->format = temp >> 12; | ||
| 415 | regs->vector = temp & 0xfff; | ||
| 416 | 414 | ||
| 417 | err |= rt_restore_fpu_state(uc); | 415 | err |= rt_restore_fpu_state(uc); |
| 418 | 416 | ||
| 419 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | 417 | if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) |
| 420 | goto badframe; | 418 | goto badframe; |
| 421 | 419 | ||
| 422 | fsize = frame_extra_sizes[regs->format]; | 420 | if (mangle_kernel_stack(regs, temp, &uc->uc_extra)) |
| 423 | if (fsize < 0) { | ||
| 424 | /* | ||
| 425 | * user process trying to return with weird frame format | ||
| 426 | */ | ||
| 427 | #ifdef DEBUG | ||
| 428 | printk("user process returning with weird frame format\n"); | ||
| 429 | #endif | ||
| 430 | goto badframe; | 421 | goto badframe; |
| 431 | } | ||
| 432 | 422 | ||
| 433 | /* OK. Make room on the supervisor stack for the extra junk, | 423 | return 0; |
| 434 | * if necessary. | ||
| 435 | */ | ||
| 436 | |||
| 437 | if (fsize) { | ||
| 438 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | ||
| 439 | __asm__ __volatile__ | ||
| 440 | (" movel %0,%/a0\n\t" | ||
| 441 | " subl %1,%/a0\n\t" /* make room on stack */ | ||
| 442 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | ||
| 443 | /* move switch_stack and pt_regs */ | ||
| 444 | "1: movel %0@+,%/a0@+\n\t" | ||
| 445 | " dbra %2,1b\n\t" | ||
| 446 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | ||
| 447 | " lsrl #2,%1\n\t" | ||
| 448 | " subql #1,%1\n\t" | ||
| 449 | "2: movesl %4@+,%2\n\t" | ||
| 450 | "3: movel %2,%/a0@+\n\t" | ||
| 451 | " dbra %1,2b\n\t" | ||
| 452 | " bral ret_from_signal\n" | ||
| 453 | "4:\n" | ||
| 454 | ".section __ex_table,\"a\"\n" | ||
| 455 | " .align 4\n" | ||
| 456 | " .long 2b,4b\n" | ||
| 457 | " .long 3b,4b\n" | ||
| 458 | ".previous" | ||
| 459 | : /* no outputs, it doesn't ever return */ | ||
| 460 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | ||
| 461 | "n" (frame_offset), "a" (&uc->uc_extra) | ||
| 462 | : "a0"); | ||
| 463 | #undef frame_offset | ||
| 464 | /* | ||
| 465 | * If we ever get here an exception occurred while | ||
| 466 | * building the above stack-frame. | ||
| 467 | */ | ||
| 468 | goto badframe; | ||
| 469 | } | ||
| 470 | |||
| 471 | *pd0 = regs->d0; | ||
| 472 | return err; | ||
| 473 | 424 | ||
| 474 | badframe: | 425 | badframe: |
| 475 | return 1; | 426 | return 1; |
| @@ -482,7 +433,6 @@ asmlinkage int do_sigreturn(unsigned long __unused) | |||
| 482 | unsigned long usp = rdusp(); | 433 | unsigned long usp = rdusp(); |
| 483 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); | 434 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); |
| 484 | sigset_t set; | 435 | sigset_t set; |
| 485 | int d0; | ||
| 486 | 436 | ||
| 487 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 437 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 488 | goto badframe; | 438 | goto badframe; |
| @@ -496,9 +446,9 @@ asmlinkage int do_sigreturn(unsigned long __unused) | |||
| 496 | current->blocked = set; | 446 | current->blocked = set; |
| 497 | recalc_sigpending(); | 447 | recalc_sigpending(); |
| 498 | 448 | ||
| 499 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) | 449 | if (restore_sigcontext(regs, &frame->sc, frame + 1)) |
| 500 | goto badframe; | 450 | goto badframe; |
| 501 | return d0; | 451 | return regs->d0; |
| 502 | 452 | ||
| 503 | badframe: | 453 | badframe: |
| 504 | force_sig(SIGSEGV, current); | 454 | force_sig(SIGSEGV, current); |
| @@ -512,7 +462,6 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) | |||
| 512 | unsigned long usp = rdusp(); | 462 | unsigned long usp = rdusp(); |
| 513 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); | 463 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); |
| 514 | sigset_t set; | 464 | sigset_t set; |
| 515 | int d0; | ||
| 516 | 465 | ||
| 517 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 466 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 518 | goto badframe; | 467 | goto badframe; |
| @@ -523,9 +472,9 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) | |||
| 523 | current->blocked = set; | 472 | current->blocked = set; |
| 524 | recalc_sigpending(); | 473 | recalc_sigpending(); |
| 525 | 474 | ||
| 526 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) | 475 | if (rt_restore_ucontext(regs, sw, &frame->uc)) |
| 527 | goto badframe; | 476 | goto badframe; |
| 528 | return d0; | 477 | return regs->d0; |
| 529 | 478 | ||
| 530 | badframe: | 479 | badframe: |
| 531 | force_sig(SIGSEGV, current); | 480 | force_sig(SIGSEGV, current); |
