diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-10-03 01:15:49 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2011-01-07 08:01:34 -0500 |
commit | f85741eb5fb2653fd9138b4bef68396615c720f7 (patch) | |
tree | cf57bfb2816c43ab7bc832ce1535b92000b20af0 | |
parent | 9e4930dbf17c1eba72631cd52a0c621da3d1a816 (diff) |
m68k: Don't lose state if sigframe setup fails
If we'd failed in setup_frame(), we've no place to store
the original sigmask. It's not an unrecoverable situation -
we raise SIGSEGV, but that SIGSEGV might be successfully
handled (e.g. on altstack). In that case we really don't
want sa_mask of original signal permanently slapped on
the set of blocked signals.
Standard solution: have setup_frame()/setup_rt_frame()
report failure and don't mess with the signal-related
state if that has happened...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
-rw-r--r-- | arch/m68k/kernel/signal.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index a18b251fe593..a6dd61418e76 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c | |||
@@ -743,7 +743,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
743 | return (void __user *)((usp - frame_size) & -8UL); | 743 | return (void __user *)((usp - frame_size) & -8UL); |
744 | } | 744 | } |
745 | 745 | ||
746 | static void setup_frame (int sig, struct k_sigaction *ka, | 746 | static int setup_frame (int sig, struct k_sigaction *ka, |
747 | sigset_t *set, struct pt_regs *regs) | 747 | sigset_t *set, struct pt_regs *regs) |
748 | { | 748 | { |
749 | struct sigframe __user *frame; | 749 | struct sigframe __user *frame; |
@@ -813,14 +813,14 @@ adjust_stack: | |||
813 | tregs->pc = regs->pc; | 813 | tregs->pc = regs->pc; |
814 | tregs->sr = regs->sr; | 814 | tregs->sr = regs->sr; |
815 | } | 815 | } |
816 | return; | 816 | return err; |
817 | 817 | ||
818 | give_sigsegv: | 818 | give_sigsegv: |
819 | force_sigsegv(sig, current); | 819 | force_sigsegv(sig, current); |
820 | goto adjust_stack; | 820 | goto adjust_stack; |
821 | } | 821 | } |
822 | 822 | ||
823 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | 823 | static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, |
824 | sigset_t *set, struct pt_regs *regs) | 824 | sigset_t *set, struct pt_regs *regs) |
825 | { | 825 | { |
826 | struct rt_sigframe __user *frame; | 826 | struct rt_sigframe __user *frame; |
@@ -901,7 +901,7 @@ adjust_stack: | |||
901 | tregs->pc = regs->pc; | 901 | tregs->pc = regs->pc; |
902 | tregs->sr = regs->sr; | 902 | tregs->sr = regs->sr; |
903 | } | 903 | } |
904 | return; | 904 | return err; |
905 | 905 | ||
906 | give_sigsegv: | 906 | give_sigsegv: |
907 | force_sigsegv(sig, current); | 907 | force_sigsegv(sig, current); |
@@ -963,6 +963,7 @@ static void | |||
963 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 963 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
964 | sigset_t *oldset, struct pt_regs *regs) | 964 | sigset_t *oldset, struct pt_regs *regs) |
965 | { | 965 | { |
966 | int err; | ||
966 | /* are we from a system call? */ | 967 | /* are we from a system call? */ |
967 | if (regs->orig_d0 >= 0) | 968 | if (regs->orig_d0 >= 0) |
968 | /* If so, check system call restarting.. */ | 969 | /* If so, check system call restarting.. */ |
@@ -970,9 +971,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
970 | 971 | ||
971 | /* set up the stack frame */ | 972 | /* set up the stack frame */ |
972 | if (ka->sa.sa_flags & SA_SIGINFO) | 973 | if (ka->sa.sa_flags & SA_SIGINFO) |
973 | setup_rt_frame(sig, ka, info, oldset, regs); | 974 | err = setup_rt_frame(sig, ka, info, oldset, regs); |
974 | else | 975 | else |
975 | setup_frame(sig, ka, oldset, regs); | 976 | err = setup_frame(sig, ka, oldset, regs); |
977 | |||
978 | if (err) | ||
979 | return; | ||
976 | 980 | ||
977 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 981 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
978 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 982 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
@@ -983,6 +987,8 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
983 | regs->sr &= ~0x8000; | 987 | regs->sr &= ~0x8000; |
984 | send_sig(SIGTRAP, current, 1); | 988 | send_sig(SIGTRAP, current, 1); |
985 | } | 989 | } |
990 | |||
991 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
986 | } | 992 | } |
987 | 993 | ||
988 | /* | 994 | /* |
@@ -1008,7 +1014,6 @@ asmlinkage void do_signal(struct pt_regs *regs) | |||
1008 | if (signr > 0) { | 1014 | if (signr > 0) { |
1009 | /* Whee! Actually deliver the signal. */ | 1015 | /* Whee! Actually deliver the signal. */ |
1010 | handle_signal(signr, &ka, &info, oldset, regs); | 1016 | handle_signal(signr, &ka, &info, oldset, regs); |
1011 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1012 | return; | 1017 | return; |
1013 | } | 1018 | } |
1014 | 1019 | ||