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>
This commit is contained in:
Родитель
05c5e7698b
Коммит
392c21802e
|
@ -511,7 +511,7 @@ out_irqs_on:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -620,11 +620,14 @@ 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)
|
||||||
{
|
{
|
||||||
|
@ -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(¤t->sighand->siglock);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
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,
|
||||||
sigaddset(¤t->blocked,signr);
|
sigaddset(¤t->blocked,signr);
|
||||||
recalc_sigpending();
|
recalc_sigpending();
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->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,
|
||||||
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,7 +315,7 @@ 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;
|
||||||
|
@ -384,15 +384,18 @@ 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;
|
||||||
|
@ -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(¤t->sighand->siglock);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
||||||
|
@ -489,6 +500,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
|
||||||
sigaddset(¤t->blocked, signr);
|
sigaddset(¤t->blocked, signr);
|
||||||
recalc_sigpending();
|
recalc_sigpending();
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->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,8 +561,7 @@ 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
|
||||||
|
@ -555,8 +569,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
|
||||||
*/
|
*/
|
||||||
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 *
|
||||||
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,
|
||||||
}
|
}
|
||||||
/* 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;
|
||||||
|
|
||||||
|
err = setup_rt_frame(ka, regs, signr, oldset,
|
||||||
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
|
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
spin_lock_irq(¤t->sighand->siglock);
|
||||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
||||||
if (!(ka->sa.sa_flags & SA_NOMASK))
|
if (!(ka->sa.sa_flags & SA_NOMASK))
|
||||||
sigaddset(¤t->blocked,signr);
|
sigaddset(¤t->blocked,signr);
|
||||||
recalc_sigpending();
|
recalc_sigpending();
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
spin_unlock_irq(¤t->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)
|
||||||
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 &&
|
||||||
|
|
Загрузка…
Ссылка в новой задаче