MIPS: scall: Handle seccomp filters which redirect syscalls
authorMatt Redfearn <matt.redfearn@imgtec.com>
Tue, 29 Mar 2016 08:35:31 +0000 (09:35 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 13 May 2016 12:02:00 +0000 (14:02 +0200)
Commit d218af78492a ("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: d218af78492a ("MIPS: scall: Always run the seccomp syscall filters")
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
Acked-by: Kees 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: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S

index d01fe53a663850bccbea14e30208357df5aa074b..c8e43e0c4066b599fd24b1135eebac0129252d17 100644 (file)
@@ -35,7 +35,6 @@ NESTED(handle_sys, PT_SIZE, sp)
 
        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
        sw      t1, PT_EPC(sp)
 
@@ -89,6 +88,7 @@ loads_done:
        and     t0, t1
        bnez    t0, syscall_trace_entry # -> yes
 syscall_common:
+       subu    v0, v0, __NR_O32_Linux  # check syscall number
        sltiu   t0, v0, __NR_O32_Linux_syscalls + 1
        beqz    t0, illegal_syscall
 
@@ -118,24 +118,23 @@ o32_syscall_exit:
 
 syscall_trace_entry:
        SAVE_STATIC
-       move    s0, v0
        move    a0, sp
 
        /*
         * syscall number is in v0 unless we called syscall(__NR_###)
         * where the real syscall number is in a0
         */
-       addiu   a1, v0,  __NR_O32_Linux
-       bnez    v0, 1f /* __NR_syscall at offset 0 */
+       move    a1, v0
+       subu    t2, v0,  __NR_O32_Linux
+       bnez    t2, 1f /* __NR_syscall at offset 0 */
        lw      a1, PT_R4(sp)
 
 1:     jal     syscall_trace_enter
 
        bltz    v0, 1f                  # seccomp failed? Skip syscall
 
-       move    v0, s0                  # restore syscall
-
        RESTORE_STATIC
+       lw      v0, PT_R2(sp)           # Restore syscall (maybe modified)
        lw      a0, PT_R4(sp)           # Restore argument registers
        lw      a1, PT_R5(sp)
        lw      a2, PT_R6(sp)
index 6b73ecc02597c008c0025a89b4ebf252f73c8a38..e6ede125059fe87253edb0bd5a5d9e46c8ef0fff 100644 (file)
@@ -82,15 +82,14 @@ n64_syscall_exit:
 
 syscall_trace_entry:
        SAVE_STATIC
-       move    s0, v0
        move    a0, sp
        move    a1, v0
        jal     syscall_trace_enter
 
        bltz    v0, 1f                  # seccomp failed? Skip syscall
 
-       move    v0, s0
        RESTORE_STATIC
+       ld      v0, PT_R2(sp)           # Restore syscall (maybe modified)
        ld      a0, PT_R4(sp)           # Restore argument registers
        ld      a1, PT_R5(sp)
        ld      a2, PT_R6(sp)
index 71f99d5f7a068220c17c9ab4da4cd6419f356b67..9c0b387d6427b1f06d2cd15f3d4e6e9444389fb9 100644 (file)
@@ -42,9 +42,6 @@ NESTED(handle_sysn32, PT_SIZE, sp)
 #endif
        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
 
        li      t1, _TIF_WORK_SYSCALL_ENTRY
@@ -53,6 +50,9 @@ NESTED(handle_sysn32, PT_SIZE, sp)
        bnez    t0, n32_syscall_trace_entry
 
 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)
 
        li      t0, -EMAXERRNO - 1      # error?
@@ -71,21 +71,25 @@ syscall_common:
 
 n32_syscall_trace_entry:
        SAVE_STATIC
-       move    s0, t2
        move    a0, sp
        move    a1, v0
        jal     syscall_trace_enter
 
        bltz    v0, 1f                  # seccomp failed? Skip syscall
 
-       move    t2, s0
        RESTORE_STATIC
+       ld      v0, PT_R2(sp)           # Restore syscall (maybe modified)
        ld      a0, PT_R4(sp)           # Restore argument registers
        ld      a1, PT_R5(sp)
        ld      a2, PT_R6(sp)
        ld      a3, PT_R7(sp)
        ld      a4, PT_R8(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
 
 1:     j       syscall_exit
index 91b43eea2d5a073026ef8f4928d74e41ca0bfb07..f4f28b1580ded57d4dc5b0a7e49e289004680590 100644 (file)
@@ -52,9 +52,6 @@ NESTED(handle_sys, PT_SIZE, sp)
        sll     a2, a2, 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
 
        /*
@@ -88,6 +85,9 @@ loads_done:
        bnez    t0, trace_a_syscall
 
 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)
 
        li      t0, -EMAXERRNO - 1      # error?
@@ -112,7 +112,6 @@ trace_a_syscall:
        sd      a6, PT_R10(sp)
        sd      a7, PT_R11(sp)          # For indirect syscalls
 
-       move    s0, t2                  # Save syscall pointer
        move    a0, sp
        /*
         * 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
 
-       move    t2, s0
        RESTORE_STATIC
+       ld      v0, PT_R2(sp)           # Restore syscall (maybe modified)
        ld      a0, PT_R4(sp)           # Restore argument registers
        ld      a1, PT_R5(sp)
        ld      a2, PT_R6(sp)
@@ -143,6 +142,11 @@ trace_a_syscall:
        ld      a5, PT_R9(sp)
        ld      a6, PT_R10(sp)
        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
 
 1:     j       syscall_exit