From: Paul Mackerras 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-03-28 23:20:55.842429680 -0800 +++ 25-akpm/arch/ppc64/kernel/signal32.c 2004-03-28 23:20:55.848428768 -0800 @@ -657,7 +657,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) { @@ -703,7 +703,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; @@ -715,7 +715,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); } @@ -828,7 +828,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) { @@ -853,7 +853,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) @@ -868,7 +868,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; @@ -880,7 +880,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); } @@ -944,18 +944,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 = ¤t->blocked; newsp = frame = 0; - signr = get_signal_to_deliver(&info, regs, NULL); - - ka = (signr == 0)? NULL: ¤t->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 */ @@ -966,7 +964,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; @@ -985,7 +983,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 @@ -993,17 +991,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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, + &ka_copy.sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->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-03-28 23:20:55.844429376 -0800 +++ 25-akpm/arch/ppc64/kernel/signal.c 2004-03-28 23:20:55.850428464 -0800 @@ -216,15 +216,15 @@ static int 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); } @@ -361,8 +361,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 @@ -374,7 +374,7 @@ static void setup_rt_frame(int signr, st unsigned long newsp = 0; int 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; @@ -393,7 +393,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; @@ -403,7 +403,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; @@ -415,7 +415,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; @@ -432,33 +432,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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, + &ka_copy->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->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: @@ -473,7 +473,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; } @@ -498,6 +498,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 @@ -509,14 +510,12 @@ int do_signal(sigset_t *oldset, struct p if (!oldset) oldset = ¤t->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 = ¤t->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-03-28 23:20:55.845429224 -0800 +++ 25-akpm/arch/ppc/kernel/signal.c 2004-03-28 23:20:55.851428312 -0800 @@ -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 = ¤t->blocked; newsp = frame = 0; - signr = get_signal_to_deliver(&info, regs, NULL); - - ka = (signr == 0)? NULL: ¤t->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(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked, ¤t->blocked, + &ka_copy.sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); _