Commit 9a81c16b527528ad307843be5571111aa8d35a80

Authored by Al Viro
Committed by Linus Torvalds
1 parent b68e9d4581

powerpc: fix double syscall restarts

Make sigreturn zero regs->trap, make do_signal() do the same on all
paths.  As it is, signal interrupting e.g. read() from fd 512 (==
ERESTARTSYS) with another signal getting unblocked when the first
handler finishes will lead to restart one insn earlier than it ought
to.  Same for multiple signals with in-kernel handlers interrupting
that sucker at the same time.  Same for multiple signals of any kind
interrupting that sucker on 64bit...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 4 additions and 3 deletions Side-by-side Diff

arch/powerpc/kernel/signal.c
... ... @@ -138,6 +138,7 @@
138 138 ti->local_flags &= ~_TLF_RESTORE_SIGMASK;
139 139 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
140 140 }
  141 + regs->trap = 0;
141 142 return 0; /* no signals delivered */
142 143 }
143 144  
... ... @@ -164,6 +165,7 @@
164 165 ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
165 166 }
166 167  
  168 + regs->trap = 0;
167 169 if (ret) {
168 170 spin_lock_irq(&current->sighand->siglock);
169 171 sigorsets(&current->blocked, &current->blocked,
arch/powerpc/kernel/signal_32.c
... ... @@ -511,6 +511,7 @@
511 511 if (!sig)
512 512 save_r2 = (unsigned int)regs->gpr[2];
513 513 err = restore_general_regs(regs, sr);
  514 + regs->trap = 0;
514 515 err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
515 516 if (!sig)
516 517 regs->gpr[2] = (unsigned long) save_r2;
... ... @@ -884,7 +885,6 @@
884 885 regs->nip = (unsigned long) ka->sa.sa_handler;
885 886 /* enter the signal handler in big-endian mode */
886 887 regs->msr &= ~MSR_LE;
887   - regs->trap = 0;
888 888 return 1;
889 889  
890 890 badframe:
... ... @@ -1228,7 +1228,6 @@
1228 1228 regs->nip = (unsigned long) ka->sa.sa_handler;
1229 1229 /* enter the signal handler in big-endian mode */
1230 1230 regs->msr &= ~MSR_LE;
1231   - regs->trap = 0;
1232 1231  
1233 1232 return 1;
1234 1233  
arch/powerpc/kernel/signal_64.c
... ... @@ -178,7 +178,7 @@
178 178 err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]);
179 179 err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]);
180 180 /* skip SOFTE */
181   - err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]);
  181 + regs->trap = 0;
182 182 err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]);
183 183 err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]);
184 184 err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);