Commit a400bed6 authored by Matt Redfearn's avatar Matt Redfearn Committed by Ralf Baechle

MIPS: scall: Handle seccomp filters which redirect syscalls

Commit d218af78 ("MIPS: scall: Always run the seccomp syscall
filters") modified the syscall code to always call the seccomp filters,
but missed the case where a filter may redirect the syscall, as
revealed by the seccomp_bpf self test.

The syscall path now restores the syscall from the stack after the
filter rather than saving it locally. Syscall number checking and
syscall function table lookup is done after the filter may have run such
that redirected syscalls are also checked, and executed.

The regular path of syscall number checking and pointer lookup is also
made more consistent between ABIs with scall64-64.S being the reference.

With this patch in place, the seccomp_bpf self test now passes
TRACE_syscall.syscall_redirected and TRACE_syscall.syscall_dropped on
all MIPS ABIs.

Fixes: d218af78 ("MIPS: scall: Always run the seccomp syscall filters")
Signed-off-by: default avatarMatt Redfearn <matt.redfearn@imgtec.com>
Acked-by: default avatarKees Cook <keescook@chromium.org>
Cc: Eric B Munson <emunson@akamai.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mips@linux-mips.org
Cc: IMG-MIPSLinuxKerneldevelopers@imgtec.com
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/12916/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 5050e91f
...@@ -35,7 +35,6 @@ NESTED(handle_sys, PT_SIZE, sp) ...@@ -35,7 +35,6 @@ NESTED(handle_sys, PT_SIZE, sp)
lw t1, PT_EPC(sp) # skip syscall on return lw t1, PT_EPC(sp) # skip syscall on return
subu v0, v0, __NR_O32_Linux # check syscall number
addiu t1, 4 # skip to next instruction addiu t1, 4 # skip to next instruction
sw t1, PT_EPC(sp) sw t1, PT_EPC(sp)
...@@ -89,6 +88,7 @@ loads_done: ...@@ -89,6 +88,7 @@ loads_done:
and t0, t1 and t0, t1
bnez t0, syscall_trace_entry # -> yes bnez t0, syscall_trace_entry # -> yes
syscall_common: syscall_common:
subu v0, v0, __NR_O32_Linux # check syscall number
sltiu t0, v0, __NR_O32_Linux_syscalls + 1 sltiu t0, v0, __NR_O32_Linux_syscalls + 1
beqz t0, illegal_syscall beqz t0, illegal_syscall
...@@ -118,24 +118,23 @@ o32_syscall_exit: ...@@ -118,24 +118,23 @@ o32_syscall_exit:
syscall_trace_entry: syscall_trace_entry:
SAVE_STATIC SAVE_STATIC
move s0, v0
move a0, sp move a0, sp
/* /*
* syscall number is in v0 unless we called syscall(__NR_###) * syscall number is in v0 unless we called syscall(__NR_###)
* where the real syscall number is in a0 * where the real syscall number is in a0
*/ */
addiu a1, v0, __NR_O32_Linux move a1, v0
bnez v0, 1f /* __NR_syscall at offset 0 */ subu t2, v0, __NR_O32_Linux
bnez t2, 1f /* __NR_syscall at offset 0 */
lw a1, PT_R4(sp) lw a1, PT_R4(sp)
1: jal syscall_trace_enter 1: jal syscall_trace_enter
bltz v0, 1f # seccomp failed? Skip syscall bltz v0, 1f # seccomp failed? Skip syscall
move v0, s0 # restore syscall
RESTORE_STATIC RESTORE_STATIC
lw v0, PT_R2(sp) # Restore syscall (maybe modified)
lw a0, PT_R4(sp) # Restore argument registers lw a0, PT_R4(sp) # Restore argument registers
lw a1, PT_R5(sp) lw a1, PT_R5(sp)
lw a2, PT_R6(sp) lw a2, PT_R6(sp)
......
...@@ -82,15 +82,14 @@ n64_syscall_exit: ...@@ -82,15 +82,14 @@ n64_syscall_exit:
syscall_trace_entry: syscall_trace_entry:
SAVE_STATIC SAVE_STATIC
move s0, v0
move a0, sp move a0, sp
move a1, v0 move a1, v0
jal syscall_trace_enter jal syscall_trace_enter
bltz v0, 1f # seccomp failed? Skip syscall bltz v0, 1f # seccomp failed? Skip syscall
move v0, s0
RESTORE_STATIC RESTORE_STATIC
ld v0, PT_R2(sp) # Restore syscall (maybe modified)
ld a0, PT_R4(sp) # Restore argument registers ld a0, PT_R4(sp) # Restore argument registers
ld a1, PT_R5(sp) ld a1, PT_R5(sp)
ld a2, PT_R6(sp) ld a2, PT_R6(sp)
......
...@@ -42,9 +42,6 @@ NESTED(handle_sysn32, PT_SIZE, sp) ...@@ -42,9 +42,6 @@ NESTED(handle_sysn32, PT_SIZE, sp)
#endif #endif
beqz t0, not_n32_scall beqz t0, not_n32_scall
dsll t0, v0, 3 # offset into table
ld t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
sd a3, PT_R26(sp) # save a3 for syscall restarting sd a3, PT_R26(sp) # save a3 for syscall restarting
li t1, _TIF_WORK_SYSCALL_ENTRY li t1, _TIF_WORK_SYSCALL_ENTRY
...@@ -53,6 +50,9 @@ NESTED(handle_sysn32, PT_SIZE, sp) ...@@ -53,6 +50,9 @@ NESTED(handle_sysn32, PT_SIZE, sp)
bnez t0, n32_syscall_trace_entry bnez t0, n32_syscall_trace_entry
syscall_common: syscall_common:
dsll t0, v0, 3 # offset into table
ld t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
jalr t2 # Do The Real Thing (TM) jalr t2 # Do The Real Thing (TM)
li t0, -EMAXERRNO - 1 # error? li t0, -EMAXERRNO - 1 # error?
...@@ -71,21 +71,25 @@ syscall_common: ...@@ -71,21 +71,25 @@ syscall_common:
n32_syscall_trace_entry: n32_syscall_trace_entry:
SAVE_STATIC SAVE_STATIC
move s0, t2
move a0, sp move a0, sp
move a1, v0 move a1, v0
jal syscall_trace_enter jal syscall_trace_enter
bltz v0, 1f # seccomp failed? Skip syscall bltz v0, 1f # seccomp failed? Skip syscall
move t2, s0
RESTORE_STATIC RESTORE_STATIC
ld v0, PT_R2(sp) # Restore syscall (maybe modified)
ld a0, PT_R4(sp) # Restore argument registers ld a0, PT_R4(sp) # Restore argument registers
ld a1, PT_R5(sp) ld a1, PT_R5(sp)
ld a2, PT_R6(sp) ld a2, PT_R6(sp)
ld a3, PT_R7(sp) ld a3, PT_R7(sp)
ld a4, PT_R8(sp) ld a4, PT_R8(sp)
ld a5, PT_R9(sp) ld a5, PT_R9(sp)
dsubu t2, v0, __NR_N32_Linux # check (new) syscall number
sltiu t0, t2, __NR_N32_Linux_syscalls + 1
beqz t0, not_n32_scall
j syscall_common j syscall_common
1: j syscall_exit 1: j syscall_exit
......
...@@ -52,9 +52,6 @@ NESTED(handle_sys, PT_SIZE, sp) ...@@ -52,9 +52,6 @@ NESTED(handle_sys, PT_SIZE, sp)
sll a2, a2, 0 sll a2, a2, 0
sll a3, a3, 0 sll a3, a3, 0
dsll t0, v0, 3 # offset into table
ld t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0)
sd a3, PT_R26(sp) # save a3 for syscall restarting sd a3, PT_R26(sp) # save a3 for syscall restarting
/* /*
...@@ -88,6 +85,9 @@ loads_done: ...@@ -88,6 +85,9 @@ loads_done:
bnez t0, trace_a_syscall bnez t0, trace_a_syscall
syscall_common: syscall_common:
dsll t0, v0, 3 # offset into table
ld t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0)
jalr t2 # Do The Real Thing (TM) jalr t2 # Do The Real Thing (TM)
li t0, -EMAXERRNO - 1 # error? li t0, -EMAXERRNO - 1 # error?
...@@ -112,7 +112,6 @@ trace_a_syscall: ...@@ -112,7 +112,6 @@ trace_a_syscall:
sd a6, PT_R10(sp) sd a6, PT_R10(sp)
sd a7, PT_R11(sp) # For indirect syscalls sd a7, PT_R11(sp) # For indirect syscalls
move s0, t2 # Save syscall pointer
move a0, sp move a0, sp
/* /*
* absolute syscall number is in v0 unless we called syscall(__NR_###) * absolute syscall number is in v0 unless we called syscall(__NR_###)
...@@ -133,8 +132,8 @@ trace_a_syscall: ...@@ -133,8 +132,8 @@ trace_a_syscall:
bltz v0, 1f # seccomp failed? Skip syscall bltz v0, 1f # seccomp failed? Skip syscall
move t2, s0
RESTORE_STATIC RESTORE_STATIC
ld v0, PT_R2(sp) # Restore syscall (maybe modified)
ld a0, PT_R4(sp) # Restore argument registers ld a0, PT_R4(sp) # Restore argument registers
ld a1, PT_R5(sp) ld a1, PT_R5(sp)
ld a2, PT_R6(sp) ld a2, PT_R6(sp)
...@@ -143,6 +142,11 @@ trace_a_syscall: ...@@ -143,6 +142,11 @@ trace_a_syscall:
ld a5, PT_R9(sp) ld a5, PT_R9(sp)
ld a6, PT_R10(sp) ld a6, PT_R10(sp)
ld a7, PT_R11(sp) # For indirect syscalls ld a7, PT_R11(sp) # For indirect syscalls
dsubu t0, v0, __NR_O32_Linux # check (new) syscall number
sltiu t0, t0, __NR_O32_Linux_syscalls + 1
beqz t0, not_o32_scall
j syscall_common j syscall_common
1: j syscall_exit 1: j syscall_exit
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment