From: David Woodhouse Make sure that when a signal is (not) delivered to a bogus stack, that a segfault is delivered then, and not after returning to userspace. Signed-off-by: Andrew Morton --- 25-akpm/arch/ppc64/kernel/signal.c | 17 ++++++++++------- 25-akpm/arch/ppc64/kernel/signal32.c | 31 ++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 18 deletions(-) diff -puN arch/ppc64/kernel/signal32.c~ppc64-sigmasking-fix arch/ppc64/kernel/signal32.c --- 25/arch/ppc64/kernel/signal32.c~ppc64-sigmasking-fix Tue Nov 30 14:55:15 2004 +++ 25-akpm/arch/ppc64/kernel/signal32.c Tue Nov 30 14:55:15 2004 @@ -653,9 +653,9 @@ int sys32_sigaltstack(u32 __new, u32 __o * Set up a signal frame for a "real-time" signal handler * (one which gets siginfo). */ -static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long newsp) +static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, + struct pt_regs * regs, unsigned long newsp) { struct rt_sigframe32 __user *rt_sf; struct mcontext32 __user *frame; @@ -704,14 +704,14 @@ static void handle_rt_signal32(unsigned regs->trap = 0; regs->result = 0; - return; + return 1; badframe: #if DEBUG_SIG printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - force_sigsegv(sig, current); + return 0; } static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig) @@ -822,7 +822,7 @@ long sys32_rt_sigreturn(int r3, int r4, /* * OK, we're invoking a handler */ -static void handle_signal32(unsigned long sig, struct k_sigaction *ka, +static int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, unsigned long newsp) { @@ -867,14 +867,14 @@ static void handle_signal32(unsigned lon regs->trap = 0; regs->result = 0; - return; + return 1; badframe: #if DEBUG_SIG printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n", regs, frame, *newspp); #endif - force_sigsegv(sig, current); + return 0; } /* @@ -984,11 +984,20 @@ int do_signal32(sigset_t *oldset, struct /* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags & SA_SIGINFO) - handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); + ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); else - handle_signal32(signr, &ka, &info, oldset, regs, newsp); + ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp); - if (!(ka.sa.sa_flags & SA_NODEFER)) { + if (!ret) { + /* Setting up the stack frame failed, but if we came here + from sigsuspend we may already have masked signals. + Put back the old sigmask before forcing SEGV. */ + spin_lock_irq(¤t->sighand->siglock); + current->blocked = *oldset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + force_sigsegv(signr, current); + } else if (!(ka.sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); diff -puN arch/ppc64/kernel/signal.c~ppc64-sigmasking-fix arch/ppc64/kernel/signal.c --- 25/arch/ppc64/kernel/signal.c~ppc64-sigmasking-fix Tue Nov 30 14:55:15 2004 +++ 25-akpm/arch/ppc64/kernel/signal.c Tue Nov 30 14:55:15 2004 @@ -387,7 +387,7 @@ badframe: return 0; } -static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, +static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { /* Handler is *really* a pointer to the function descriptor for @@ -452,7 +452,7 @@ static void setup_rt_frame(int signr, st if (err) goto badframe; - return; + return 0; badframe: #if DEBUG_SIG @@ -460,17 +460,19 @@ badframe: regs, frame, newsp); #endif force_sigsegv(signr, current); + return -1; } /* * OK, we're invoking a handler */ -static void handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) +static int handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { /* Set up Signal Frame */ - setup_rt_frame(sig, ka, info, oldset, regs); + if (setup_rt_frame(sig, ka, info, oldset, regs)) + return 0; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); @@ -479,6 +481,8 @@ static void handle_signal(unsigned long recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } + + return 1; } static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) @@ -538,8 +542,7 @@ int do_signal(sigset_t *oldset, struct p /* Whee! Actually deliver the signal. */ if (TRAP(regs) == 0x0C00) syscall_restart(regs, &ka); - handle_signal(signr, &ka, &info, oldset, regs); - return 1; + return handle_signal(signr, &ka, &info, oldset, regs); } if (TRAP(regs) == 0x0C00) { /* System Call! */ _