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 /arch/m68k/kernel | |
| 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>
Diffstat (limited to 'arch/m68k/kernel')
| -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 a18b251fe59..a6dd61418e7 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 | ||
