summaryrefslogtreecommitdiff
path: root/arch/s390/kernel/syscall.c
diff options
context:
space:
mode:
authorSven Schnelle <svens@linux.ibm.com>2021-06-25 15:02:08 +0200
committerVasily Gorbik <gor@linux.ibm.com>2021-07-08 22:09:47 +0200
commitdf29a7440c4b5c65765c8f60396b3b13063e24e9 (patch)
treeeb0c060e0678fb18fa4eeadd2d9b2000757f6913 /arch/s390/kernel/syscall.c
parent779df2248739b6308c03b354c99e4c352141e3bc (diff)
s390/signal: switch to using vdso for sigreturn and syscall restart
with generic entry, there's a bug when it comes to restarting of signals. The failing sequence is: a) a signal is coming in, and no handler is registered, so the lower part of arch_do_signal_or_restart() in arch/s390/kernel/signal.c sets PIF_SYSCALL_RESTART. b) a second signal gets pending while the kernel is still in the exit loop, and for that one, a handler exists. c) The first part of arch_do_signal_or_restart() is called. That part calls handle_signal(), which sets up stack + registers for handling the signal. d) __do_syscall() in arch/s390/kernel/syscall.c checks for PIF_SYSCALL_RESTART right before leaving to userspace. If it is set, it restart's the syscall. However, the registers are already setup for handling a signal from c). The syscall is now restarted with the wrong arguments. Change the code to: - use vdso for syscall_restart() instead of PIF_SYSCALL_RESTART because we cannot rewind and go back to userspace on s390 because the system call number might be encoded in the svc instruction. - for all other syscalls we rewind the PSW and return to userspace. Cc: <stable@kernel.org> # v5.12+ d57778feb987: s390/vdso: always enable vdso Cc: <stable@kernel.org> # v5.12+ 686341f2548b: s390/vdso64: add sigreturn,rt_sigreturn and restart_syscall Cc: <stable@kernel.org> # v5.12+ 43e1f76b0b69: s390/vdso: rename VDSO64_LBASE to VDSO_LBASE Cc: <stable@kernel.org> # v5.12+ 779df2248739: s390/vdso: add minimal compat vdso Cc: <stable@kernel.org> # v5.12+ Signed-off-by: Sven Schnelle <svens@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390/kernel/syscall.c')
-rw-r--r--arch/s390/kernel/syscall.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/arch/s390/kernel/syscall.c b/arch/s390/kernel/syscall.c
index 76f7916cc30f..c6b99da0738b 100644
--- a/arch/s390/kernel/syscall.c
+++ b/arch/s390/kernel/syscall.c
@@ -121,6 +121,10 @@ void do_syscall(struct pt_regs *regs)
regs->gprs[2] = nr;
+ if (nr == __NR_restart_syscall && !(current->restart_block.arch_data & 1)) {
+ regs->psw.addr = current->restart_block.arch_data;
+ current->restart_block.arch_data = 1;
+ }
nr = syscall_enter_from_user_mode_work(regs, nr);
/*