summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Swierk <eswierk@skyportsystems.com>2015-01-12 21:10:30 -0800
committerWilly Tarreau <w@1wt.eu>2016-01-29 22:12:56 +0100
commit912fcae9d4986486aa4d866d7c119a7a8ad37053 (patch)
treee3bf2fb72b0dcc99b5167b03c6cf2acaf64c06fc
parent533030ca4271aea2f1fc95a3c64840654feebafe (diff)
downloadlinux-912fcae9d4986486aa4d866d7c119a7a8ad37053.tar.gz
linux-912fcae9d4986486aa4d866d7c119a7a8ad37053.tar.bz2
linux-912fcae9d4986486aa4d866d7c119a7a8ad37053.zip
MIPS: Fix restart of indirect syscalls
commit e967ef022e00bb7c2e5b1a42007abfdd52055050 upstream. When 32-bit MIPS userspace invokes a syscall indirectly via syscall(number, arg1, ..., arg7), the kernel looks up the actual syscall based on the given number, shifts the other arguments to the left, and jumps to the syscall. If the syscall is interrupted by a signal and indicates it needs to be restarted by the kernel (by returning ERESTARTNOINTR for example), the syscall must be called directly, since the number is no longer the first argument, and the other arguments are now staged for a direct call. Before shifting the arguments, store the syscall number in pt_regs->regs[2]. This gets copied temporarily into pt_regs->regs[0] after the syscall returns. If the syscall needs to be restarted, handle_signal()/do_signal() copies the number back to pt_regs->reg[2], which ends up in $v0 once control returns to userspace. Signed-off-by: Ed Swierk <eswierk@skyportsystems.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8929/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org> [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk> (cherry picked from commit 08f865bba9c705aef95268a33393698e5385587e) Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--arch/mips/kernel/scall32-o32.S1
-rw-r--r--arch/mips/kernel/scall64-o32.S1
2 files changed, 2 insertions, 0 deletions
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index b72c55484840..44194c162637 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -194,6 +194,7 @@ illegal_syscall:
sll t1, t0, 3
beqz v0, einval
lw t2, sys_call_table(t1) # syscall routine
+ sw a0, PT_R2(sp) # call routine directly on restart
/* Some syscalls like execve get their arguments from struct pt_regs
and claim zero arguments in the syscall table. Thus we have to
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 33ed571ae78a..1f7c01f6a125 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -180,6 +180,7 @@ LEAF(sys32_syscall)
dsll t1, t0, 3
beqz v0, einval
ld t2, sys_call_table(t1) # syscall routine
+ sd a0, PT_R2(sp) # call routine directly on restart
move a0, a1 # shift argument registers
move a1, a2