Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+5 −6
Original line number Original line Diff line number Diff line
@@ -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:
	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:


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)
+1 −2
Original line number Original line Diff line number Diff line
@@ -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)
+9 −5
Original line number Original line Diff line number Diff line
@@ -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)
	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:


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
+9 −5
Original line number Original line Diff line number Diff line
@@ -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:
	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:
	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:


	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:
	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