diff options
| -rw-r--r-- | arch/arm/kernel/signal.c | 108 |
1 files changed, 47 insertions, 61 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 07429a23c720..296786bdbb73 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -318,18 +318,12 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) | |||
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | static inline void __user * | 320 | static inline void __user * |
| 321 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize) | 321 | get_sigframe(struct ksignal *ksig, struct pt_regs *regs, int framesize) |
| 322 | { | 322 | { |
| 323 | unsigned long sp = regs->ARM_sp; | 323 | unsigned long sp = sigsp(regs->ARM_sp, ksig); |
| 324 | void __user *frame; | 324 | void __user *frame; |
| 325 | 325 | ||
| 326 | /* | 326 | /* |
| 327 | * This is the X/Open sanctioned signal stack switching. | ||
| 328 | */ | ||
| 329 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) | ||
| 330 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
| 331 | |||
| 332 | /* | ||
| 333 | * ATPCS B01 mandates 8-byte alignment | 327 | * ATPCS B01 mandates 8-byte alignment |
| 334 | */ | 328 | */ |
| 335 | frame = (void __user *)((sp - framesize) & ~7); | 329 | frame = (void __user *)((sp - framesize) & ~7); |
| @@ -343,11 +337,22 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize) | |||
| 343 | return frame; | 337 | return frame; |
| 344 | } | 338 | } |
| 345 | 339 | ||
| 340 | /* | ||
| 341 | * translate the signal | ||
| 342 | */ | ||
| 343 | static inline int map_sig(int sig) | ||
| 344 | { | ||
| 345 | struct thread_info *thread = current_thread_info(); | ||
| 346 | if (sig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) | ||
| 347 | sig = thread->exec_domain->signal_invmap[sig]; | ||
| 348 | return sig; | ||
| 349 | } | ||
| 350 | |||
| 346 | static int | 351 | static int |
| 347 | setup_return(struct pt_regs *regs, struct k_sigaction *ka, | 352 | setup_return(struct pt_regs *regs, struct ksignal *ksig, |
| 348 | unsigned long __user *rc, void __user *frame, int usig) | 353 | unsigned long __user *rc, void __user *frame) |
| 349 | { | 354 | { |
| 350 | unsigned long handler = (unsigned long)ka->sa.sa_handler; | 355 | unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler; |
| 351 | unsigned long retcode; | 356 | unsigned long retcode; |
| 352 | int thumb = 0; | 357 | int thumb = 0; |
| 353 | unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); | 358 | unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); |
| @@ -357,7 +362,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, | |||
| 357 | /* | 362 | /* |
| 358 | * Maybe we need to deliver a 32-bit signal to a 26-bit task. | 363 | * Maybe we need to deliver a 32-bit signal to a 26-bit task. |
| 359 | */ | 364 | */ |
| 360 | if (ka->sa.sa_flags & SA_THIRTYTWO) | 365 | if (ksig->ka.sa.sa_flags & SA_THIRTYTWO) |
| 361 | cpsr = (cpsr & ~MODE_MASK) | USR_MODE; | 366 | cpsr = (cpsr & ~MODE_MASK) | USR_MODE; |
| 362 | 367 | ||
| 363 | #ifdef CONFIG_ARM_THUMB | 368 | #ifdef CONFIG_ARM_THUMB |
| @@ -379,12 +384,12 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, | |||
| 379 | } | 384 | } |
| 380 | #endif | 385 | #endif |
| 381 | 386 | ||
| 382 | if (ka->sa.sa_flags & SA_RESTORER) { | 387 | if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
| 383 | retcode = (unsigned long)ka->sa.sa_restorer; | 388 | retcode = (unsigned long)ksig->ka.sa.sa_restorer; |
| 384 | } else { | 389 | } else { |
| 385 | unsigned int idx = thumb << 1; | 390 | unsigned int idx = thumb << 1; |
| 386 | 391 | ||
| 387 | if (ka->sa.sa_flags & SA_SIGINFO) | 392 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
| 388 | idx += 3; | 393 | idx += 3; |
| 389 | 394 | ||
| 390 | if (__put_user(sigreturn_codes[idx], rc) || | 395 | if (__put_user(sigreturn_codes[idx], rc) || |
| @@ -409,7 +414,7 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, | |||
| 409 | } | 414 | } |
| 410 | } | 415 | } |
| 411 | 416 | ||
| 412 | regs->ARM_r0 = usig; | 417 | regs->ARM_r0 = map_sig(ksig->sig); |
| 413 | regs->ARM_sp = (unsigned long)frame; | 418 | regs->ARM_sp = (unsigned long)frame; |
| 414 | regs->ARM_lr = retcode; | 419 | regs->ARM_lr = retcode; |
| 415 | regs->ARM_pc = handler; | 420 | regs->ARM_pc = handler; |
| @@ -419,9 +424,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, | |||
| 419 | } | 424 | } |
| 420 | 425 | ||
| 421 | static int | 426 | static int |
| 422 | setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) | 427 | setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
| 423 | { | 428 | { |
| 424 | struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); | 429 | struct sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame)); |
| 425 | int err = 0; | 430 | int err = 0; |
| 426 | 431 | ||
| 427 | if (!frame) | 432 | if (!frame) |
| @@ -434,22 +439,21 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg | |||
| 434 | 439 | ||
| 435 | err |= setup_sigframe(frame, regs, set); | 440 | err |= setup_sigframe(frame, regs, set); |
| 436 | if (err == 0) | 441 | if (err == 0) |
| 437 | err = setup_return(regs, ka, frame->retcode, frame, usig); | 442 | err = setup_return(regs, ksig, frame->retcode, frame); |
| 438 | 443 | ||
| 439 | return err; | 444 | return err; |
| 440 | } | 445 | } |
| 441 | 446 | ||
| 442 | static int | 447 | static int |
| 443 | setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | 448 | setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) |
| 444 | sigset_t *set, struct pt_regs *regs) | ||
| 445 | { | 449 | { |
| 446 | struct rt_sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); | 450 | struct rt_sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame)); |
| 447 | int err = 0; | 451 | int err = 0; |
| 448 | 452 | ||
| 449 | if (!frame) | 453 | if (!frame) |
| 450 | return 1; | 454 | return 1; |
| 451 | 455 | ||
| 452 | err |= copy_siginfo_to_user(&frame->info, info); | 456 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); |
| 453 | 457 | ||
| 454 | __put_user_error(0, &frame->sig.uc.uc_flags, err); | 458 | __put_user_error(0, &frame->sig.uc.uc_flags, err); |
| 455 | __put_user_error(NULL, &frame->sig.uc.uc_link, err); | 459 | __put_user_error(NULL, &frame->sig.uc.uc_link, err); |
| @@ -457,7 +461,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | |||
| 457 | err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp); | 461 | err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp); |
| 458 | err |= setup_sigframe(&frame->sig, regs, set); | 462 | err |= setup_sigframe(&frame->sig, regs, set); |
| 459 | if (err == 0) | 463 | if (err == 0) |
| 460 | err = setup_return(regs, ka, frame->sig.retcode, frame, usig); | 464 | err = setup_return(regs, ksig, frame->sig.retcode, frame); |
| 461 | 465 | ||
| 462 | if (err == 0) { | 466 | if (err == 0) { |
| 463 | /* | 467 | /* |
| @@ -475,40 +479,25 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | |||
| 475 | /* | 479 | /* |
| 476 | * OK, we're invoking a handler | 480 | * OK, we're invoking a handler |
| 477 | */ | 481 | */ |
| 478 | static void | 482 | static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
| 479 | handle_signal(unsigned long sig, struct k_sigaction *ka, | ||
| 480 | siginfo_t *info, struct pt_regs *regs) | ||
| 481 | { | 483 | { |
| 482 | struct thread_info *thread = current_thread_info(); | ||
| 483 | struct task_struct *tsk = current; | ||
| 484 | sigset_t *oldset = sigmask_to_save(); | 484 | sigset_t *oldset = sigmask_to_save(); |
| 485 | int usig = sig; | ||
| 486 | int ret; | 485 | int ret; |
| 487 | 486 | ||
| 488 | /* | 487 | /* |
| 489 | * translate the signal | ||
| 490 | */ | ||
| 491 | if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) | ||
| 492 | usig = thread->exec_domain->signal_invmap[usig]; | ||
| 493 | |||
| 494 | /* | ||
| 495 | * Set up the stack frame | 488 | * Set up the stack frame |
| 496 | */ | 489 | */ |
| 497 | if (ka->sa.sa_flags & SA_SIGINFO) | 490 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
| 498 | ret = setup_rt_frame(usig, ka, info, oldset, regs); | 491 | ret = setup_rt_frame(ksig, oldset, regs); |
| 499 | else | 492 | else |
| 500 | ret = setup_frame(usig, ka, oldset, regs); | 493 | ret = setup_frame(ksig, oldset, regs); |
| 501 | 494 | ||
| 502 | /* | 495 | /* |
| 503 | * Check that the resulting registers are actually sane. | 496 | * Check that the resulting registers are actually sane. |
| 504 | */ | 497 | */ |
| 505 | ret |= !valid_user_regs(regs); | 498 | ret |= !valid_user_regs(regs); |
| 506 | 499 | ||
| 507 | if (ret != 0) { | 500 | signal_setup_done(ret, ksig, 0); |
| 508 | force_sigsegv(sig, tsk); | ||
| 509 | return; | ||
| 510 | } | ||
| 511 | signal_delivered(sig, info, ka, regs, 0); | ||
| 512 | } | 501 | } |
| 513 | 502 | ||
| 514 | /* | 503 | /* |
| @@ -523,9 +512,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
| 523 | static int do_signal(struct pt_regs *regs, int syscall) | 512 | static int do_signal(struct pt_regs *regs, int syscall) |
| 524 | { | 513 | { |
| 525 | unsigned int retval = 0, continue_addr = 0, restart_addr = 0; | 514 | unsigned int retval = 0, continue_addr = 0, restart_addr = 0; |
| 526 | struct k_sigaction ka; | 515 | struct ksignal ksig; |
| 527 | siginfo_t info; | ||
| 528 | int signr; | ||
| 529 | int restart = 0; | 516 | int restart = 0; |
| 530 | 517 | ||
| 531 | /* | 518 | /* |
| @@ -557,33 +544,32 @@ static int do_signal(struct pt_regs *regs, int syscall) | |||
| 557 | * Get the signal to deliver. When running under ptrace, at this | 544 | * Get the signal to deliver. When running under ptrace, at this |
| 558 | * point the debugger may change all our registers ... | 545 | * point the debugger may change all our registers ... |
| 559 | */ | 546 | */ |
| 560 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
| 561 | /* | 547 | /* |
| 562 | * Depending on the signal settings we may need to revert the | 548 | * Depending on the signal settings we may need to revert the |
| 563 | * decision to restart the system call. But skip this if a | 549 | * decision to restart the system call. But skip this if a |
| 564 | * debugger has chosen to restart at a different PC. | 550 | * debugger has chosen to restart at a different PC. |
| 565 | */ | 551 | */ |
| 566 | if (regs->ARM_pc != restart_addr) | 552 | if (get_signal(&ksig)) { |
| 567 | restart = 0; | 553 | /* handler */ |
| 568 | if (signr > 0) { | 554 | if (unlikely(restart) && regs->ARM_pc == restart_addr) { |
| 569 | if (unlikely(restart)) { | ||
| 570 | if (retval == -ERESTARTNOHAND || | 555 | if (retval == -ERESTARTNOHAND || |
| 571 | retval == -ERESTART_RESTARTBLOCK | 556 | retval == -ERESTART_RESTARTBLOCK |
| 572 | || (retval == -ERESTARTSYS | 557 | || (retval == -ERESTARTSYS |
| 573 | && !(ka.sa.sa_flags & SA_RESTART))) { | 558 | && !(ksig.ka.sa.sa_flags & SA_RESTART))) { |
| 574 | regs->ARM_r0 = -EINTR; | 559 | regs->ARM_r0 = -EINTR; |
| 575 | regs->ARM_pc = continue_addr; | 560 | regs->ARM_pc = continue_addr; |
| 576 | } | 561 | } |
| 577 | } | 562 | } |
| 578 | 563 | handle_signal(&ksig, regs); | |
| 579 | handle_signal(signr, &ka, &info, regs); | 564 | } else { |
| 580 | return 0; | 565 | /* no handler */ |
| 566 | restore_saved_sigmask(); | ||
| 567 | if (unlikely(restart) && regs->ARM_pc == restart_addr) { | ||
| 568 | regs->ARM_pc = continue_addr; | ||
| 569 | return restart; | ||
| 570 | } | ||
| 581 | } | 571 | } |
| 582 | 572 | return 0; | |
| 583 | restore_saved_sigmask(); | ||
| 584 | if (unlikely(restart)) | ||
| 585 | regs->ARM_pc = continue_addr; | ||
| 586 | return restart; | ||
| 587 | } | 573 | } |
| 588 | 574 | ||
| 589 | asmlinkage int | 575 | asmlinkage int |
