aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-09-20 16:48:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-09-22 12:33:50 -0400
commit9a81c16b527528ad307843be5571111aa8d35a80 (patch)
tree4fea21edefa32d8e8e997f3db63f9cefaddff28c /arch
parentb68e9d4581cbb211be3e174d3445b4917aacbcf6 (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/signal.c2
-rw-r--r--arch/powerpc/kernel/signal_32.c3
-rw-r--r--arch/powerpc/kernel/signal_64.c2
3 files changed, 4 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 7109f5b1baa8..2300426e531a 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -138,6 +138,7 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs)
138 ti->local_flags &= ~_TLF_RESTORE_SIGMASK; 138 ti->local_flags &= ~_TLF_RESTORE_SIGMASK;
139 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL); 139 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
140 } 140 }
141 regs->trap = 0;
141 return 0; /* no signals delivered */ 142 return 0; /* no signals delivered */
142 } 143 }
143 144
@@ -164,6 +165,7 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs)
164 ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); 165 ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
165 } 166 }
166 167
168 regs->trap = 0;
167 if (ret) { 169 if (ret) {
168 spin_lock_irq(&current->sighand->siglock); 170 spin_lock_irq(&current->sighand->siglock);
169 sigorsets(&current->blocked, &current->blocked, 171 sigorsets(&current->blocked, &current->blocked,
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 266610119f66..b96a3a010c26 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -511,6 +511,7 @@ static long restore_user_regs(struct pt_regs *regs,
511 if (!sig) 511 if (!sig)
512 save_r2 = (unsigned int)regs->gpr[2]; 512 save_r2 = (unsigned int)regs->gpr[2];
513 err = restore_general_regs(regs, sr); 513 err = restore_general_regs(regs, sr);
514 regs->trap = 0;
514 err |= __get_user(msr, &sr->mc_gregs[PT_MSR]); 515 err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
515 if (!sig) 516 if (!sig)
516 regs->gpr[2] = (unsigned long) save_r2; 517 regs->gpr[2] = (unsigned long) save_r2;
@@ -884,7 +885,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
884 regs->nip = (unsigned long) ka->sa.sa_handler; 885 regs->nip = (unsigned long) ka->sa.sa_handler;
885 /* enter the signal handler in big-endian mode */ 886 /* enter the signal handler in big-endian mode */
886 regs->msr &= ~MSR_LE; 887 regs->msr &= ~MSR_LE;
887 regs->trap = 0;
888 return 1; 888 return 1;
889 889
890badframe: 890badframe:
@@ -1228,7 +1228,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
1228 regs->nip = (unsigned long) ka->sa.sa_handler; 1228 regs->nip = (unsigned long) ka->sa.sa_handler;
1229 /* enter the signal handler in big-endian mode */ 1229 /* enter the signal handler in big-endian mode */
1230 regs->msr &= ~MSR_LE; 1230 regs->msr &= ~MSR_LE;
1231 regs->trap = 0;
1232 1231
1233 return 1; 1232 return 1;
1234 1233
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 2fe6fc64b614..27c4a4584f80 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -178,7 +178,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
178 err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]); 178 err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]);
179 err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]); 179 err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]);
180 /* skip SOFTE */ 180 /* skip SOFTE */
181 err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]); 181 regs->trap = 0;
182 err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); 182 err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]);
183 err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); 183 err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]);
184 err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]); 184 err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);