Commit 392c2180 authored by David S. Miller's avatar David S. Miller

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: default avatarAl Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 05c5e769
...@@ -511,8 +511,8 @@ static void flush_signal_insns(unsigned long address) ...@@ -511,8 +511,8 @@ static void flush_signal_insns(unsigned long address)
} }
static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset) int signo, sigset_t *oldset)
{ {
struct signal_frame32 __user *sf; struct signal_frame32 __user *sf;
int sigframe_size; int sigframe_size;
...@@ -620,13 +620,16 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, ...@@ -620,13 +620,16 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
sigill: sigill:
do_exit(SIGILL); do_exit(SIGILL);
return -EINVAL;
sigsegv: sigsegv:
force_sigsegv(signo, current); force_sigsegv(signo, current);
return -EFAULT;
} }
static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
unsigned long signr, sigset_t *oldset, unsigned long signr, sigset_t *oldset,
siginfo_t *info) siginfo_t *info)
{ {
struct rt_signal_frame32 __user *sf; struct rt_signal_frame32 __user *sf;
int sigframe_size; int sigframe_size;
...@@ -738,22 +741,30 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, ...@@ -738,22 +741,30 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
flush_signal_insns(address); flush_signal_insns(address);
} }
return; return 0;
sigill: sigill:
do_exit(SIGILL); do_exit(SIGILL);
return -EINVAL;
sigsegv: sigsegv:
force_sigsegv(signr, current); force_sigsegv(signr, current);
return -EFAULT;
} }
static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs) sigset_t *oldset, struct pt_regs *regs)
{ {
int err;
if (ka->sa.sa_flags & SA_SIGINFO) if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame32(ka, regs, signr, oldset, info); err = setup_rt_frame32(ka, regs, signr, oldset, info);
else else
setup_frame32(ka, regs, signr, oldset); err = setup_frame32(ka, regs, signr, oldset);
if (err)
return err;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
...@@ -761,6 +772,10 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, ...@@ -761,6 +772,10 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
sigaddset(&current->blocked,signr); sigaddset(&current->blocked,signr);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
tracehook_signal_handler(signr, info, ka, regs, 0);
return 0;
} }
static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, 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,16 +822,14 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs,
if (signr > 0) { if (signr > 0) {
if (restart_syscall) if (restart_syscall)
syscall_restart32(orig_i0, regs, &ka.sa); syscall_restart32(orig_i0, regs, &ka.sa);
handle_signal32(signr, &ka, &info, oldset, regs); if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) {
/* A signal was successfully delivered; the saved
/* A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame,
* sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply
* and will be restored by sigreturn, so we can simply * clear the TS_RESTORE_SIGMASK flag.
* clear the TS_RESTORE_SIGMASK flag. */
*/ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
current_thread_info()->status &= ~TS_RESTORE_SIGMASK; }
tracehook_signal_handler(signr, &info, &ka, regs, 0);
return; return;
} }
if (restart_syscall && if (restart_syscall &&
......
...@@ -315,8 +315,8 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) ...@@ -315,8 +315,8 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
return err; return err;
} }
static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset) int signo, sigset_t *oldset)
{ {
struct signal_frame __user *sf; struct signal_frame __user *sf;
int sigframe_size, err; int sigframe_size, err;
...@@ -384,16 +384,19 @@ static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, ...@@ -384,16 +384,19 @@ static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* Flush instruction space. */ /* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
} }
return; return 0;
sigill_and_return: sigill_and_return:
do_exit(SIGILL); do_exit(SIGILL);
return -EINVAL;
sigsegv: sigsegv:
force_sigsegv(signo, current); force_sigsegv(signo, current);
return -EFAULT;
} }
static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset, siginfo_t *info) int signo, sigset_t *oldset, siginfo_t *info)
{ {
struct rt_signal_frame __user *sf; struct rt_signal_frame __user *sf;
int sigframe_size; int sigframe_size;
...@@ -466,22 +469,30 @@ static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, ...@@ -466,22 +469,30 @@ static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* Flush instruction space. */ /* Flush instruction space. */
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
} }
return; return 0;
sigill: sigill:
do_exit(SIGILL); do_exit(SIGILL);
return -EINVAL;
sigsegv: sigsegv:
force_sigsegv(signo, current); force_sigsegv(signo, current);
return -EFAULT;
} }
static inline void static inline int
handle_signal(unsigned long signr, struct k_sigaction *ka, handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{ {
int err;
if (ka->sa.sa_flags & SA_SIGINFO) if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(ka, regs, signr, oldset, info); err = setup_rt_frame(ka, regs, signr, oldset, info);
else else
setup_frame(ka, regs, signr, oldset); err = setup_frame(ka, regs, signr, oldset);
if (err)
return err;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
...@@ -489,6 +500,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, ...@@ -489,6 +500,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
sigaddset(&current->blocked, signr); sigaddset(&current->blocked, signr);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
tracehook_signal_handler(signr, info, ka, regs, 0);
return 0;
} }
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
...@@ -546,17 +561,15 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -546,17 +561,15 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
if (signr > 0) { if (signr > 0) {
if (restart_syscall) if (restart_syscall)
syscall_restart(orig_i0, regs, &ka.sa); syscall_restart(orig_i0, regs, &ka.sa);
handle_signal(signr, &ka, &info, oldset, regs); if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
/* a signal was successfully delivered; the saved
/* a signal was successfully delivered; the saved * sigmask will have been stored in the signal frame,
* sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply
* and will be restored by sigreturn, so we can simply * clear the TIF_RESTORE_SIGMASK flag.
* clear the TIF_RESTORE_SIGMASK flag. */
*/ if (test_thread_flag(TIF_RESTORE_SIGMASK))
if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK);
clear_thread_flag(TIF_RESTORE_SIGMASK); }
tracehook_signal_handler(signr, &info, &ka, regs, 0);
return; return;
} }
if (restart_syscall && if (restart_syscall &&
......
...@@ -409,7 +409,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs * ...@@ -409,7 +409,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *
return (void __user *) sp; return (void __user *) sp;
} }
static inline void static inline int
setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset, siginfo_t *info) int signo, sigset_t *oldset, siginfo_t *info)
{ {
...@@ -483,26 +483,37 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, ...@@ -483,26 +483,37 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
} }
/* 4. return to kernel instructions */ /* 4. return to kernel instructions */
regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
return; return 0;
sigill: sigill:
do_exit(SIGILL); do_exit(SIGILL);
return -EINVAL;
sigsegv: sigsegv:
force_sigsegv(signo, current); force_sigsegv(signo, current);
return -EFAULT;
} }
static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, static inline int handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs) sigset_t *oldset, struct pt_regs *regs)
{ {
setup_rt_frame(ka, regs, signr, oldset, int err;
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
err = setup_rt_frame(ka, regs, signr, oldset,
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
if (err)
return err;
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NOMASK)) if (!(ka->sa.sa_flags & SA_NOMASK))
sigaddset(&current->blocked,signr); sigaddset(&current->blocked,signr);
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
tracehook_signal_handler(signr, info, ka, regs, 0);
return 0;
} }
static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
...@@ -571,16 +582,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -571,16 +582,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
if (signr > 0) { if (signr > 0) {
if (restart_syscall) if (restart_syscall)
syscall_restart(orig_i0, regs, &ka.sa); syscall_restart(orig_i0, regs, &ka.sa);
handle_signal(signr, &ka, &info, oldset, regs); if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
/* A signal was successfully delivered; the saved
/* A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame,
* sigmask will have been stored in the signal frame, * and will be restored by sigreturn, so we can simply
* and will be restored by sigreturn, so we can simply * clear the TS_RESTORE_SIGMASK flag.
* clear the TS_RESTORE_SIGMASK flag. */
*/ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
current_thread_info()->status &= ~TS_RESTORE_SIGMASK; }
tracehook_signal_handler(signr, &info, &ka, regs, 0);
return; return;
} }
if (restart_syscall && if (restart_syscall &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment