
From: David Woodhouse <dwmw2@infradead.org>

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 <akpm@osdl.org>
---

 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(&current->sighand->siglock);
+		current->blocked = *oldset;
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+		force_sigsegv(signr, current);
+	} else if (!(ka.sa.sa_flags & SA_NODEFER)) {
 		spin_lock_irq(&current->sighand->siglock);
 		sigorsets(&current->blocked, &current->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(&current->sighand->siglock);
@@ -479,6 +481,8 @@ static void handle_signal(unsigned long 
 		recalc_sigpending();
 		spin_unlock_irq(&current->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! */
_
