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>
This commit is contained in:
		
							parent
							
								
									b68e9d4581
								
							
						
					
					
						commit
						9a81c16b52
					
				| @ -138,6 +138,7 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) | ||||
| 			ti->local_flags &= ~_TLF_RESTORE_SIGMASK; | ||||
| 			sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||||
| 		} | ||||
| 		regs->trap = 0; | ||||
| 		return 0;               /* no signals delivered */ | ||||
| 	} | ||||
| 
 | ||||
| @ -164,6 +165,7 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) | ||||
| 		ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); | ||||
| 	} | ||||
| 
 | ||||
| 	regs->trap = 0; | ||||
| 	if (ret) { | ||||
| 		spin_lock_irq(¤t->sighand->siglock); | ||||
| 		sigorsets(¤t->blocked, ¤t->blocked, | ||||
|  | ||||
| @ -511,6 +511,7 @@ static long restore_user_regs(struct pt_regs *regs, | ||||
| 	if (!sig) | ||||
| 		save_r2 = (unsigned int)regs->gpr[2]; | ||||
| 	err = restore_general_regs(regs, sr); | ||||
| 	regs->trap = 0; | ||||
| 	err |= __get_user(msr, &sr->mc_gregs[PT_MSR]); | ||||
| 	if (!sig) | ||||
| 		regs->gpr[2] = (unsigned long) save_r2; | ||||
| @ -884,7 +885,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | ||||
| 	regs->nip = (unsigned long) ka->sa.sa_handler; | ||||
| 	/* enter the signal handler in big-endian mode */ | ||||
| 	regs->msr &= ~MSR_LE; | ||||
| 	regs->trap = 0; | ||||
| 	return 1; | ||||
| 
 | ||||
| badframe: | ||||
| @ -1228,7 +1228,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, | ||||
| 	regs->nip = (unsigned long) ka->sa.sa_handler; | ||||
| 	/* enter the signal handler in big-endian mode */ | ||||
| 	regs->msr &= ~MSR_LE; | ||||
| 	regs->trap = 0; | ||||
| 
 | ||||
| 	return 1; | ||||
| 
 | ||||
|  | ||||
| @ -178,7 +178,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | ||||
| 	err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]); | ||||
| 	err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]); | ||||
| 	/* skip SOFTE */ | ||||
| 	err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]); | ||||
| 	regs->trap = 0; | ||||
| 	err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); | ||||
| 	err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); | ||||
| 	err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user