diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 21:11:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 21:11:45 -0400 |
commit | f9369910a6225b8d4892c3f20ae740a711cd5ace (patch) | |
tree | 8650ff79d7607bceb35509c028400ecf1c317de0 /arch/alpha | |
parent | 05f144a0d5c2207a0349348127f996e104ad7404 (diff) | |
parent | 415d04d08fec74b226c92c1fb54ad117c9c6bac4 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull first series of signal handling cleanups from Al Viro:
"This is just the first part of the queue (about a half of it);
assorted fixes all over the place in signal handling.
This one ends with all sigsuspend() implementations switched to
generic one (->saved_sigmask-based).
With this, a bunch of assorted old buglets are fixed and most of the
missing bits of NOTIFY_RESUME hookup are in place. Two more fixes sit
in arm and um trees respectively, and there's a couple of broken ones
that need obvious fixes - parisc and avr32 check TIF_NOTIFY_RESUME
only on one of two codepaths; fixes for that will happen in the next
series"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (55 commits)
unicore32: if there's no handler we need to restore sigmask, syscall or no syscall
xtensa: add handling of TIF_NOTIFY_RESUME
microblaze: drop 'oldset' argument of do_notify_resume()
microblaze: handle TIF_NOTIFY_RESUME
score: add handling of NOTIFY_RESUME to do_notify_resume()
m68k: add TIF_NOTIFY_RESUME and handle it.
sparc: kill ancient comment in sparc_sigaction()
h8300: missing checks of __get_user()/__put_user() return values
frv: missing checks of __get_user()/__put_user() return values
cris: missing checks of __get_user()/__put_user() return values
powerpc: missing checks of __get_user()/__put_user() return values
sh: missing checks of __get_user()/__put_user() return values
sparc: missing checks of __get_user()/__put_user() return values
avr32: struct old_sigaction is never used
m32r: struct old_sigaction is never used
xtensa: xtensa_sigaction doesn't exist
alpha: tidy signal delivery up
score: don't open-code force_sigsegv()
cris: don't open-code force_sigsegv()
blackfin: don't open-code force_sigsegv()
...
Diffstat (limited to 'arch/alpha')
-rw-r--r-- | arch/alpha/kernel/signal.c | 80 |
1 files changed, 27 insertions, 53 deletions
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 35f2ef44de12..10ab2d74ecbb 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
@@ -34,9 +34,6 @@ | |||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
35 | 35 | ||
36 | asmlinkage void ret_from_sys_call(void); | 36 | asmlinkage void ret_from_sys_call(void); |
37 | static void do_signal(struct pt_regs *, struct switch_stack *, | ||
38 | unsigned long, unsigned long); | ||
39 | |||
40 | 37 | ||
41 | /* | 38 | /* |
42 | * The OSF/1 sigprocmask calling sequence is different from the | 39 | * The OSF/1 sigprocmask calling sequence is different from the |
@@ -121,17 +118,8 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, | |||
121 | SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) | 118 | SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) |
122 | { | 119 | { |
123 | sigset_t blocked; | 120 | sigset_t blocked; |
124 | |||
125 | current->saved_sigmask = current->blocked; | ||
126 | |||
127 | mask &= _BLOCKABLE; | ||
128 | siginitset(&blocked, mask); | 121 | siginitset(&blocked, mask); |
129 | set_current_blocked(&blocked); | 122 | return sigsuspend(&blocked); |
130 | |||
131 | current->state = TASK_INTERRUPTIBLE; | ||
132 | schedule(); | ||
133 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
134 | return -ERESTARTNOHAND; | ||
135 | } | 123 | } |
136 | 124 | ||
137 | asmlinkage int | 125 | asmlinkage int |
@@ -376,11 +364,11 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
376 | oldsp = rdusp(); | 364 | oldsp = rdusp(); |
377 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 365 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); |
378 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 366 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
379 | goto give_sigsegv; | 367 | return -EFAULT; |
380 | 368 | ||
381 | err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); | 369 | err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); |
382 | if (err) | 370 | if (err) |
383 | goto give_sigsegv; | 371 | return -EFAULT; |
384 | 372 | ||
385 | /* Set up to return from userspace. If provided, use a stub | 373 | /* Set up to return from userspace. If provided, use a stub |
386 | already in userspace. */ | 374 | already in userspace. */ |
@@ -396,7 +384,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
396 | 384 | ||
397 | /* Check that everything was written properly. */ | 385 | /* Check that everything was written properly. */ |
398 | if (err) | 386 | if (err) |
399 | goto give_sigsegv; | 387 | return err; |
400 | 388 | ||
401 | /* "Return" to the handler */ | 389 | /* "Return" to the handler */ |
402 | regs->r26 = r26; | 390 | regs->r26 = r26; |
@@ -410,12 +398,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
410 | printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", | 398 | printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", |
411 | current->comm, current->pid, frame, regs->pc, regs->r26); | 399 | current->comm, current->pid, frame, regs->pc, regs->r26); |
412 | #endif | 400 | #endif |
413 | |||
414 | return 0; | 401 | return 0; |
415 | |||
416 | give_sigsegv: | ||
417 | force_sigsegv(sig, current); | ||
418 | return -EFAULT; | ||
419 | } | 402 | } |
420 | 403 | ||
421 | static int | 404 | static int |
@@ -428,7 +411,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
428 | oldsp = rdusp(); | 411 | oldsp = rdusp(); |
429 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 412 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); |
430 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 413 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
431 | goto give_sigsegv; | 414 | return -EFAULT; |
432 | 415 | ||
433 | err |= copy_siginfo_to_user(&frame->info, info); | 416 | err |= copy_siginfo_to_user(&frame->info, info); |
434 | 417 | ||
@@ -443,7 +426,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
443 | set->sig[0], oldsp); | 426 | set->sig[0], oldsp); |
444 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 427 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
445 | if (err) | 428 | if (err) |
446 | goto give_sigsegv; | 429 | return -EFAULT; |
447 | 430 | ||
448 | /* Set up to return from userspace. If provided, use a stub | 431 | /* Set up to return from userspace. If provided, use a stub |
449 | already in userspace. */ | 432 | already in userspace. */ |
@@ -459,7 +442,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
459 | } | 442 | } |
460 | 443 | ||
461 | if (err) | 444 | if (err) |
462 | goto give_sigsegv; | 445 | return -EFAULT; |
463 | 446 | ||
464 | /* "Return" to the handler */ | 447 | /* "Return" to the handler */ |
465 | regs->r26 = r26; | 448 | regs->r26 = r26; |
@@ -475,31 +458,37 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
475 | #endif | 458 | #endif |
476 | 459 | ||
477 | return 0; | 460 | return 0; |
478 | |||
479 | give_sigsegv: | ||
480 | force_sigsegv(sig, current); | ||
481 | return -EFAULT; | ||
482 | } | 461 | } |
483 | 462 | ||
484 | 463 | ||
485 | /* | 464 | /* |
486 | * OK, we're invoking a handler. | 465 | * OK, we're invoking a handler. |
487 | */ | 466 | */ |
488 | static inline int | 467 | static inline void |
489 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 468 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
490 | sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw) | 469 | struct pt_regs * regs, struct switch_stack *sw) |
491 | { | 470 | { |
471 | sigset_t *oldset = ¤t->blocked; | ||
492 | int ret; | 472 | int ret; |
493 | 473 | ||
474 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
475 | oldset = ¤t->saved_sigmask; | ||
476 | |||
494 | if (ka->sa.sa_flags & SA_SIGINFO) | 477 | if (ka->sa.sa_flags & SA_SIGINFO) |
495 | ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); | 478 | ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); |
496 | else | 479 | else |
497 | ret = setup_frame(sig, ka, oldset, regs, sw); | 480 | ret = setup_frame(sig, ka, oldset, regs, sw); |
498 | 481 | ||
499 | if (ret == 0) | 482 | if (ret) { |
500 | block_sigmask(ka, sig); | 483 | force_sigsegv(sig, current); |
501 | 484 | return; | |
502 | return ret; | 485 | } |
486 | block_sigmask(ka, sig); | ||
487 | /* A signal was successfully delivered, and the | ||
488 | saved sigmask was stored on the signal frame, | ||
489 | and will be restored by sigreturn. So we can | ||
490 | simply clear the restore sigmask flag. */ | ||
491 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
503 | } | 492 | } |
504 | 493 | ||
505 | static inline void | 494 | static inline void |
@@ -547,12 +536,6 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
547 | int signr; | 536 | int signr; |
548 | unsigned long single_stepping = ptrace_cancel_bpt(current); | 537 | unsigned long single_stepping = ptrace_cancel_bpt(current); |
549 | struct k_sigaction ka; | 538 | struct k_sigaction ka; |
550 | sigset_t *oldset; | ||
551 | |||
552 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
553 | oldset = ¤t->saved_sigmask; | ||
554 | else | ||
555 | oldset = ¤t->blocked; | ||
556 | 539 | ||
557 | /* This lets the debugger run, ... */ | 540 | /* This lets the debugger run, ... */ |
558 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 541 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
@@ -564,14 +547,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
564 | /* Whee! Actually deliver the signal. */ | 547 | /* Whee! Actually deliver the signal. */ |
565 | if (r0) | 548 | if (r0) |
566 | syscall_restart(r0, r19, regs, &ka); | 549 | syscall_restart(r0, r19, regs, &ka); |
567 | if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) { | 550 | handle_signal(signr, &ka, &info, regs, sw); |
568 | /* A signal was successfully delivered, and the | ||
569 | saved sigmask was stored on the signal frame, | ||
570 | and will be restored by sigreturn. So we can | ||
571 | simply clear the restore sigmask flag. */ | ||
572 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
573 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
574 | } | ||
575 | if (single_stepping) | 551 | if (single_stepping) |
576 | ptrace_set_bpt(current); /* re-set bpt */ | 552 | ptrace_set_bpt(current); /* re-set bpt */ |
577 | return; | 553 | return; |
@@ -596,10 +572,8 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, | |||
596 | } | 572 | } |
597 | 573 | ||
598 | /* If there's no signal to deliver, we just restore the saved mask. */ | 574 | /* If there's no signal to deliver, we just restore the saved mask. */ |
599 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 575 | if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) |
600 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 576 | set_current_blocked(¤t->saved_sigmask); |
601 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
602 | } | ||
603 | 577 | ||
604 | if (single_stepping) | 578 | if (single_stepping) |
605 | ptrace_set_bpt(current); /* re-set breakpoint */ | 579 | ptrace_set_bpt(current); /* re-set breakpoint */ |
@@ -610,7 +584,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, | |||
610 | unsigned long thread_info_flags, | 584 | unsigned long thread_info_flags, |
611 | unsigned long r0, unsigned long r19) | 585 | unsigned long r0, unsigned long r19) |
612 | { | 586 | { |
613 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 587 | if (thread_info_flags & _TIF_SIGPENDING) |
614 | do_signal(regs, sw, r0, r19); | 588 | do_signal(regs, sw, r0, r19); |
615 | 589 | ||
616 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 590 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |