diff options
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/kernel/signal.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 3c312290c3c2..368157926d24 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -245,15 +245,29 @@ static inline int invalid_frame_pointer(void __user *fp, int fplen) static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) { - unsigned long sp; + unsigned long sp = regs->u_regs[UREG_FP]; - sp = regs->u_regs[UREG_FP]; + /* + * If we are on the alternate signal stack and would overflow it, don't. + * Return an always-bogus address instead so we will die with SIGSEGV. + */ + if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) + return (void __user *) -1L; /* This is the X/Open sanctioned signal stack switching. */ if (sa->sa_flags & SA_ONSTACK) { - if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + if (sas_ss_flags(sp) == 0) sp = current->sas_ss_sp + current->sas_ss_size; } + + /* Always align the stack frame. This handles two cases. First, + * sigaltstack need not be mindful of platform specific stack + * alignment. Second, if we took this signal because the stack + * is not aligned properly, we'd like to take the signal cleanly + * and report that. + */ + sp &= ~7UL; + return (void __user *)(sp - framesize); } |