diff options
author | David S. Miller <davem@davemloft.net> | 2010-09-22 00:41:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-22 00:41:12 -0400 |
commit | 392c21802ee3aa85cee0e703105f797a8a7b9416 (patch) | |
tree | d0b40070dbd80817f069a5b033044e6370b55f26 /arch/sparc/kernel/signal32.c | |
parent | 05c5e7698bdc54b3079a3517d86077f49ebcc788 (diff) |
sparc: Don't mask signal when we can't setup signal frame.
Don't invoke the signal handler tracehook in that situation
either.
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/signal32.c')
-rw-r--r-- | arch/sparc/kernel/signal32.c | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 76b67c4c6aa4..643a354795cc 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c | |||
@@ -511,8 +511,8 @@ out_irqs_on: | |||
511 | 511 | ||
512 | } | 512 | } |
513 | 513 | ||
514 | static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, | 514 | static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, |
515 | int signo, sigset_t *oldset) | 515 | int signo, sigset_t *oldset) |
516 | { | 516 | { |
517 | struct signal_frame32 __user *sf; | 517 | struct signal_frame32 __user *sf; |
518 | int sigframe_size; | 518 | int sigframe_size; |
@@ -620,13 +620,16 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, | |||
620 | 620 | ||
621 | sigill: | 621 | sigill: |
622 | do_exit(SIGILL); | 622 | do_exit(SIGILL); |
623 | return -EINVAL; | ||
624 | |||
623 | sigsegv: | 625 | sigsegv: |
624 | force_sigsegv(signo, current); | 626 | force_sigsegv(signo, current); |
627 | return -EFAULT; | ||
625 | } | 628 | } |
626 | 629 | ||
627 | static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, | 630 | static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, |
628 | unsigned long signr, sigset_t *oldset, | 631 | unsigned long signr, sigset_t *oldset, |
629 | siginfo_t *info) | 632 | siginfo_t *info) |
630 | { | 633 | { |
631 | struct rt_signal_frame32 __user *sf; | 634 | struct rt_signal_frame32 __user *sf; |
632 | int sigframe_size; | 635 | int sigframe_size; |
@@ -738,22 +741,30 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, | |||
738 | 741 | ||
739 | flush_signal_insns(address); | 742 | flush_signal_insns(address); |
740 | } | 743 | } |
741 | return; | 744 | return 0; |
742 | 745 | ||
743 | sigill: | 746 | sigill: |
744 | do_exit(SIGILL); | 747 | do_exit(SIGILL); |
748 | return -EINVAL; | ||
749 | |||
745 | sigsegv: | 750 | sigsegv: |
746 | force_sigsegv(signr, current); | 751 | force_sigsegv(signr, current); |
752 | return -EFAULT; | ||
747 | } | 753 | } |
748 | 754 | ||
749 | static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, | 755 | static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka, |
750 | siginfo_t *info, | 756 | siginfo_t *info, |
751 | sigset_t *oldset, struct pt_regs *regs) | 757 | sigset_t *oldset, struct pt_regs *regs) |
752 | { | 758 | { |
759 | int err; | ||
760 | |||
753 | if (ka->sa.sa_flags & SA_SIGINFO) | 761 | if (ka->sa.sa_flags & SA_SIGINFO) |
754 | setup_rt_frame32(ka, regs, signr, oldset, info); | 762 | err = setup_rt_frame32(ka, regs, signr, oldset, info); |
755 | else | 763 | else |
756 | setup_frame32(ka, regs, signr, oldset); | 764 | err = setup_frame32(ka, regs, signr, oldset); |
765 | |||
766 | if (err) | ||
767 | return err; | ||
757 | 768 | ||
758 | spin_lock_irq(¤t->sighand->siglock); | 769 | spin_lock_irq(¤t->sighand->siglock); |
759 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 770 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
@@ -761,6 +772,10 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, | |||
761 | sigaddset(¤t->blocked,signr); | 772 | sigaddset(¤t->blocked,signr); |
762 | recalc_sigpending(); | 773 | recalc_sigpending(); |
763 | spin_unlock_irq(¤t->sighand->siglock); | 774 | spin_unlock_irq(¤t->sighand->siglock); |
775 | |||
776 | tracehook_signal_handler(signr, info, ka, regs, 0); | ||
777 | |||
778 | return 0; | ||
764 | } | 779 | } |
765 | 780 | ||
766 | static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, | 781 | static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, |
@@ -807,16 +822,14 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, | |||
807 | if (signr > 0) { | 822 | if (signr > 0) { |
808 | if (restart_syscall) | 823 | if (restart_syscall) |
809 | syscall_restart32(orig_i0, regs, &ka.sa); | 824 | syscall_restart32(orig_i0, regs, &ka.sa); |
810 | handle_signal32(signr, &ka, &info, oldset, regs); | 825 | if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) { |
811 | 826 | /* A signal was successfully delivered; the saved | |
812 | /* A signal was successfully delivered; the saved | 827 | * sigmask will have been stored in the signal frame, |
813 | * sigmask will have been stored in the signal frame, | 828 | * and will be restored by sigreturn, so we can simply |
814 | * and will be restored by sigreturn, so we can simply | 829 | * clear the TS_RESTORE_SIGMASK flag. |
815 | * clear the TS_RESTORE_SIGMASK flag. | 830 | */ |
816 | */ | 831 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
817 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; | 832 | } |
818 | |||
819 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | ||
820 | return; | 833 | return; |
821 | } | 834 | } |
822 | if (restart_syscall && | 835 | if (restart_syscall && |