From: Paul Mackerras <paulus@samba.org>

I see that the patch to fix the race in do_signal is in -mm4.  Here is a
patch to make the corresponding changes for ppc32 and ppc64.


---

 25-akpm/arch/ppc/kernel/signal.c     |   39 +++++++++++++-------------
 25-akpm/arch/ppc64/kernel/signal.c   |   51 +++++++++++++++++------------------
 25-akpm/arch/ppc64/kernel/signal32.c |   38 +++++++++++---------------
 3 files changed, 61 insertions(+), 67 deletions(-)

diff -puN arch/ppc64/kernel/signal32.c~signal-race-fixes-ppc arch/ppc64/kernel/signal32.c
--- 25/arch/ppc64/kernel/signal32.c~signal-race-fixes-ppc	2004-04-14 18:54:30.905252376 -0700
+++ 25-akpm/arch/ppc64/kernel/signal32.c	2004-04-14 18:54:30.912251312 -0700
@@ -660,7 +660,7 @@ int sys32_sigaltstack(u32 newstack, u32 
  * 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,
+static void handle_rt_signal32(unsigned long sig, struct k_sigaction *ka_copy,
 			       siginfo_t *info, sigset_t *oldset,
 			       struct pt_regs * regs, unsigned long newsp)
 {
@@ -706,7 +706,7 @@ static void handle_rt_signal32(unsigned 
 	regs->gpr[4] = (unsigned long) &rt_sf->info;
 	regs->gpr[5] = (unsigned long) &rt_sf->uc;
 	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->nip = (unsigned long) ka->sa.sa_handler;
+	regs->nip = (unsigned long) ka_copy->sa.sa_handler;
 	regs->link = (unsigned long) frame->tramp;
 	regs->trap = 0;
 
@@ -718,7 +718,7 @@ badframe:
 	       regs, frame, newsp);
 #endif
 	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
+		current->sighand->action[SIGSEGV-1].sa.sa_handler = SIG_DFL;
 	force_sig(SIGSEGV, current);
 }
 
@@ -831,7 +831,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 void handle_signal32(unsigned long sig, struct k_sigaction *ka_copy,
 			    siginfo_t *info, sigset_t *oldset,
 			    struct pt_regs * regs, unsigned long newsp)
 {
@@ -856,7 +856,7 @@ static void handle_signal32(unsigned lon
 #if _NSIG != 64
 #error "Please adjust handle_signal32()"
 #endif
-	if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler)
+	if (__put_user((u32)(u64)ka_copy->sa.sa_handler, &sc->handler)
 	    || __put_user(oldset->sig[0], &sc->oldmask)
 	    || __put_user((oldset->sig[0] >> 32), &sc->_unused[3])
 	    || __put_user((u32)(u64)frame, &sc->regs)
@@ -871,7 +871,7 @@ static void handle_signal32(unsigned lon
 	regs->gpr[1] = (unsigned long) newsp;
 	regs->gpr[3] = sig;
 	regs->gpr[4] = (unsigned long) sc;
-	regs->nip = (unsigned long) ka->sa.sa_handler;
+	regs->nip = (unsigned long) ka_copy->sa.sa_handler;
 	regs->link = (unsigned long) frame->mctx.tramp;
 	regs->trap = 0;
 
@@ -883,7 +883,7 @@ badframe:
 	       regs, frame, *newspp);
 #endif
 	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
+		current->sighand->action[SIGSEGV-1].sa.sa_handler = SIG_DFL;
 	force_sig(SIGSEGV, current);
 }
 
@@ -947,18 +947,16 @@ badframe:
 int do_signal32(sigset_t *oldset, struct pt_regs *regs)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
 	unsigned int frame, newsp;
 	int signr, ret;
+	struct k_sigaction ka_copy;
 
 	if (!oldset)
 		oldset = &current->blocked;
 
 	newsp = frame = 0;
 
-	signr = get_signal_to_deliver(&info, regs, NULL);
-
-	ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
+	signr = get_signal_to_deliver(&info, &ka_copy, regs, NULL);
 
 	if (regs->trap == 0x0C00		/* System Call! */
 	    && regs->ccr & 0x10000000		/* error signalled */
@@ -969,7 +967,7 @@ int do_signal32(sigset_t *oldset, struct
 		if (signr > 0
 		    && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
 			|| (ret == ERESTARTSYS
-			    && !(ka->sa.sa_flags & SA_RESTART)))) {
+			    && !(ka_copy.sa.sa_flags & SA_RESTART)))) {
 			/* make the system call return an EINTR error */
 			regs->result = -EINTR;
 			regs->gpr[3] = EINTR;
@@ -988,7 +986,7 @@ int do_signal32(sigset_t *oldset, struct
 	if (signr == 0)
 		return 0;		/* no signals delivered */
 
-	if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+	if ((ka_copy.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
 	    && (!on_sig_stack(regs->gpr[1])))
 		newsp = (current->sas_ss_sp + current->sas_ss_size);
 	else
@@ -996,17 +994,15 @@ int do_signal32(sigset_t *oldset, struct
 	newsp &= ~0xfUL;
 
 	/* Whee!  Actually deliver the signal.  */
-	if (ka->sa.sa_flags & SA_SIGINFO)
-		handle_rt_signal32(signr, ka, &info, oldset, regs, newsp);
+	if (ka_copy.sa.sa_flags & SA_SIGINFO)
+		handle_rt_signal32(signr, &ka_copy, &info, oldset, regs, newsp);
 	else
-		handle_signal32(signr, ka, &info, oldset, regs, newsp);
-
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+		handle_signal32(signr, &ka_copy, &info, oldset, regs, newsp);
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+	if (!(ka_copy.sa.sa_flags & SA_NODEFER)) {
 		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigorsets(&current->blocked, &current->blocked,
+			  &ka_copy.sa.sa_mask);
 		sigaddset(&current->blocked, signr);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
diff -puN arch/ppc64/kernel/signal.c~signal-race-fixes-ppc arch/ppc64/kernel/signal.c
--- 25/arch/ppc64/kernel/signal.c~signal-race-fixes-ppc	2004-04-14 18:54:30.906252224 -0700
+++ 25-akpm/arch/ppc64/kernel/signal.c	2004-04-14 18:54:30.913251160 -0700
@@ -230,15 +230,15 @@ static long restore_sigcontext(struct pt
 /*
  * Allocate space for the signal frame
  */
-static inline void * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
-				  size_t frame_size)
+static inline void * get_sigframe(struct k_sigaction *ka_copy,
+				  struct pt_regs *regs, size_t frame_size)
 {
         unsigned long newsp;
 
         /* Default to using normal stack */
         newsp = regs->gpr[1];
 
-	if (ka->sa.sa_flags & SA_ONSTACK) {
+	if (ka_copy->sa.sa_flags & SA_ONSTACK) {
 		if (! on_sig_stack(regs->gpr[1]))
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
 	}
@@ -376,8 +376,8 @@ badframe:
 	do_exit(SIGSEGV);
 }
 
-static void setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
-		sigset_t *set, struct pt_regs *regs)
+static void setup_rt_frame(int signr, struct k_sigaction *ka_copy,
+		siginfo_t *info, sigset_t *set, struct pt_regs *regs)
 {
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
@@ -389,7 +389,7 @@ static void setup_rt_frame(int signr, st
 	unsigned long newsp = 0;
 	long err = 0;
 
-	frame = get_sigframe(ka, regs, sizeof(*frame));
+	frame = get_sigframe(ka_copy, regs, sizeof(*frame));
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
@@ -408,7 +408,7 @@ static void setup_rt_frame(int signr, st
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
 	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
-				(unsigned long)ka->sa.sa_handler);
+				(unsigned long)ka_copy->sa.sa_handler);
 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 	if (err)
 		goto badframe;
@@ -418,7 +418,7 @@ static void setup_rt_frame(int signr, st
 	if (err)
 		goto badframe;
 
-	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
+	funct_desc_ptr = (func_descr_t *) ka_copy->sa.sa_handler;
 
 	/* Allocate a dummy caller frame for the signal handler. */
 	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
@@ -430,7 +430,7 @@ static void setup_rt_frame(int signr, st
 	regs->gpr[1] = newsp;
 	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
 	regs->gpr[3] = signr;
-	if (ka->sa.sa_flags & SA_SIGINFO) {
+	if (ka_copy->sa.sa_flags & SA_SIGINFO) {
 		err |= get_user(regs->gpr[4], (unsigned long *)&frame->pinfo);
 		err |= get_user(regs->gpr[5], (unsigned long *)&frame->puc);
 		regs->gpr[6] = (unsigned long) frame;
@@ -447,33 +447,33 @@ badframe:
 	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
-	do_exit(SIGSEGV);
+	if (signr == SIGSEGV)
+		current->sighand->action[SIGSEGV-1].sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 
 /*
  * 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 void handle_signal(unsigned long sig, struct k_sigaction *ka_copy,
+		siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
 	/* Set up Signal Frame */
-	setup_rt_frame(sig, ka, info, oldset, regs);
-
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+	setup_rt_frame(sig, ka_copy, info, oldset, regs);
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+	if (!(ka_copy->sa.sa_flags & SA_NODEFER)) {
 		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigorsets(&current->blocked, &current->blocked,
+			  &ka_copy->sa.sa_mask);
 		sigaddset(&current->blocked,sig);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
 	}
-	return;
 }
 
-static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+static inline void syscall_restart(struct pt_regs *regs,
+				   struct k_sigaction *ka_copy)
 {
 	switch ((int)regs->result) {
 	case -ERESTART_RESTARTBLOCK:
@@ -488,7 +488,7 @@ static inline void syscall_restart(struc
 		/* ERESTARTSYS means to restart the syscall if there is no
 		 * handler or the handler was registered with SA_RESTART
 		 */
-		if (!(ka->sa.sa_flags & SA_RESTART)) {
+		if (!(ka_copy->sa.sa_flags & SA_RESTART)) {
 			regs->result = -EINTR;
 			break;
 		}
@@ -513,6 +513,7 @@ int do_signal(sigset_t *oldset, struct p
 {
 	siginfo_t info;
 	int signr;
+	struct k_sigaction ka_copy;
 
 	/*
 	 * If the current thread is 32 bit - invoke the
@@ -524,14 +525,12 @@ int do_signal(sigset_t *oldset, struct p
 	if (!oldset)
 		oldset = &current->blocked;
 
-	signr = get_signal_to_deliver(&info, regs, NULL);
+	signr = get_signal_to_deliver(&info, &ka_copy, regs, NULL);
 	if (signr > 0) {
-		struct k_sigaction *ka = &current->sighand->action[signr-1];
-
 		/* Whee!  Actually deliver the signal.  */
 		if (regs->trap == 0x0C00)
-			syscall_restart(regs, ka);
-		handle_signal(signr, ka, &info, oldset, regs);
+			syscall_restart(regs, &ka_copy);
+		handle_signal(signr, &ka_copy, &info, oldset, regs);
 		return 1;
 	}
 
diff -puN arch/ppc/kernel/signal.c~signal-race-fixes-ppc arch/ppc/kernel/signal.c
--- 25/arch/ppc/kernel/signal.c~signal-race-fixes-ppc	2004-04-14 18:54:30.908251920 -0700
+++ 25-akpm/arch/ppc/kernel/signal.c	2004-04-14 18:54:30.915250856 -0700
@@ -311,7 +311,7 @@ restore_sigmask(sigset_t *set)
  * (one which gets siginfo).
  */
 static void
-handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
+handle_rt_signal(unsigned long sig, struct k_sigaction *ka_copy,
 		 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
 		 unsigned long newsp)
 {
@@ -354,7 +354,7 @@ handle_rt_signal(unsigned long sig, stru
 	regs->gpr[4] = (unsigned long) &rt_sf->info;
 	regs->gpr[5] = (unsigned long) &rt_sf->uc;
 	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->nip = (unsigned long) ka->sa.sa_handler;
+	regs->nip = (unsigned long) ka_copy->sa.sa_handler;
 	regs->link = (unsigned long) frame->tramp;
 	regs->trap = 0;
 
@@ -366,7 +366,7 @@ badframe:
 	       regs, frame, newsp);
 #endif
 	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
+		current->sighand->action[SIGSEGV-1].sa.sa_handler = SIG_DFL;
 	force_sig(SIGSEGV, current);
 }
 
@@ -466,7 +466,7 @@ int sys_rt_sigreturn(int r3, int r4, int
  * OK, we're invoking a handler
  */
 static void
-handle_signal(unsigned long sig, struct k_sigaction *ka,
+handle_signal(unsigned long sig, struct k_sigaction *ka_copy,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
 	      unsigned long newsp)
 {
@@ -491,7 +491,7 @@ handle_signal(unsigned long sig, struct 
 #if _NSIG != 64
 #error "Please adjust handle_signal()"
 #endif
-	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+	if (__put_user((unsigned long) ka_copy->sa.sa_handler, &sc->handler)
 	    || __put_user(oldset->sig[0], &sc->oldmask)
 	    || __put_user(oldset->sig[1], &sc->_unused[3])
 	    || __put_user((struct pt_regs *)frame, &sc->regs)
@@ -506,7 +506,7 @@ handle_signal(unsigned long sig, struct 
 	regs->gpr[1] = newsp;
 	regs->gpr[3] = sig;
 	regs->gpr[4] = (unsigned long) sc;
-	regs->nip = (unsigned long) ka->sa.sa_handler;
+	regs->nip = (unsigned long) ka_copy->sa.sa_handler;
 	regs->link = (unsigned long) frame->mctx.tramp;
 	regs->trap = 0;
 
@@ -518,7 +518,7 @@ badframe:
 	       regs, frame, *newspp);
 #endif
 	if (sig == SIGSEGV)
-		ka->sa.sa_handler = SIG_DFL;
+		current->sighand->action[SIGSEGV-1].sa.sa_handler = SIG_DFL;
 	force_sig(SIGSEGV, current);
 }
 
@@ -565,18 +565,16 @@ badframe:
 int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
 	unsigned long frame, newsp;
 	int signr, ret;
+	struct k_sigaction ka_copy;
 
 	if (!oldset)
 		oldset = &current->blocked;
 
 	newsp = frame = 0;
 
-	signr = get_signal_to_deliver(&info, regs, NULL);
-
-	ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
+	signr = get_signal_to_deliver(&info, &ka_copy, regs, NULL);
 
 	if (TRAP(regs) == 0x0C00		/* System Call! */
 	    && regs->ccr & 0x10000000		/* error signalled */
@@ -587,7 +585,7 @@ int do_signal(sigset_t *oldset, struct p
 		if (signr > 0
 		    && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
 			|| (ret == ERESTARTSYS
-			    && !(ka->sa.sa_flags & SA_RESTART)))) {
+			    && !(ka_copy.sa.sa_flags & SA_RESTART)))) {
 			/* make the system call return an EINTR error */
 			regs->result = -EINTR;
 			regs->gpr[3] = EINTR;
@@ -606,7 +604,7 @@ int do_signal(sigset_t *oldset, struct p
 	if (signr == 0)
 		return 0;		/* no signals delivered */
 
-	if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+	if ((ka_copy.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
 	    && !on_sig_stack(regs->gpr[1]))
 		newsp = current->sas_ss_sp + current->sas_ss_size;
 	else
@@ -614,17 +612,18 @@ int do_signal(sigset_t *oldset, struct p
 	newsp &= ~0xfUL;
 
 	/* Whee!  Actually deliver the signal.  */
-	if (ka->sa.sa_flags & SA_SIGINFO)
-		handle_rt_signal(signr, ka, &info, oldset, regs, newsp);
+	if (ka_copy.sa.sa_flags & SA_SIGINFO)
+		handle_rt_signal(signr, &ka_copy, &info, oldset, regs, newsp);
 	else
-		handle_signal(signr, ka, &info, oldset, regs, newsp);
+		handle_signal(signr, &ka_copy, &info, oldset, regs, newsp);
 
-	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = SIG_DFL;
+	if (ka_copy.sa.sa_flags & SA_ONESHOT)
+		ka_copy.sa.sa_handler = SIG_DFL;
 
-	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+	if (!(ka_copy.sa.sa_flags & SA_NODEFER)) {
 		spin_lock_irq(&current->sighand->siglock);
-		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigorsets(&current->blocked, &current->blocked,
+			  &ka_copy.sa.sa_mask);
 		sigaddset(&current->blocked, signr);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);

_