|
@@ -376,16 +376,29 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
|
|
|
|
|
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
|
|
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
|
|
{
|
|
{
|
|
- unsigned long sp;
|
|
|
|
|
|
+ unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
|
|
|
|
|
- sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * 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. */
|
|
/* This is the X/Open sanctioned signal stack switching. */
|
|
if (ka->sa.sa_flags & SA_ONSTACK) {
|
|
if (ka->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;
|
|
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);
|
|
return (void __user *)(sp - framesize);
|
|
}
|
|
}
|
|
|
|
|