summaryrefslogtreecommitdiff
path: root/arch/mips/include/asm/syscall.h
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2014-01-22 18:40:03 +0400
committerRalf Baechle <ralf@linux-mips.org>2014-03-27 02:09:08 +0400
commit4c21b8fd8f146a22e1eaf92833a32e51f560e82a (patch)
tree4d784859ce5b207837ddb574e26264d78db33c74 /arch/mips/include/asm/syscall.h
parent9d37c405ed7e4bb10798c37ef4e642b682425c4e (diff)
downloadlinux-4c21b8fd8f146a22e1eaf92833a32e51f560e82a.tar.xz
MIPS: seccomp: Handle indirect system calls (o32)
When userland uses syscall() to perform an indirect system call the actually system call that needs to be checked by the filter is on the first argument. The kernel code needs to handle this case by looking at the original syscall number in v0 and if it's NR_syscall, then it needs to examine the first argument to identify the real system call that will be executed. Similarly, we need to 'virtually' shift the syscall() arguments so the syscall_get_arguments() function can fetch the correct arguments for the indirect system call. Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Reviewed-by: James Hogan <james.hogan@imgtec.com> Reviewed-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6404/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/include/asm/syscall.h')
-rw-r--r--arch/mips/include/asm/syscall.h20
1 files changed, 19 insertions, 1 deletions
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
index 08b639b1ca78..9031745cec1b 100644
--- a/arch/mips/include/asm/syscall.h
+++ b/arch/mips/include/asm/syscall.h
@@ -19,11 +19,22 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+#ifndef __NR_syscall /* Only defined if _MIPS_SIM == _MIPS_SIM_ABI32 */
+#define __NR_syscall 4000
+#endif
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
- return regs->regs[2];
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ if ((config_enabled(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall))
+ return regs->regs[4];
+ else
+ return regs->regs[2];
}
static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
@@ -91,6 +102,13 @@ static inline void syscall_get_arguments(struct task_struct *task,
{
unsigned long arg;
int ret;
+ /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
+ if ((config_enabled(CONFIG_32BIT) ||
+ test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
+ (regs->regs[2] == __NR_syscall)) {
+ i++;
+ n++;
+ }
while (n--)
ret |= mips_get_syscall_arg(&arg, task, regs, i++);