12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "sandbox/linux/seccomp-bpf/syscall.h" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <asm/unistd.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <errno.h> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/basictypes.h" 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/logging.h" 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace sandbox { 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace { 17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) defined(ARCH_CPU_MIPS_FAMILY) 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Number that's not currently used by any Linux kernel ABIs. 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kInvalidSyscallNumber = 0x351d3; 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#error Unrecognized architecture 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)asm(// We need to be able to tell the kernel exactly where we made a 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // system call. The C++ compiler likes to sometimes clone or 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // inline code, which would inadvertently end up duplicating 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the entry point. 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // "gcc" can suppress code duplication with suitable function 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // attributes, but "clang" doesn't have this ability. 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The "clang" developer mailing list suggested that the correct 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // and portable solution is a file-scope assembly block. 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // N.B. We do mark our code as a proper function so that backtraces 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // work correctly. But we make absolutely no attempt to use the 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // ABI's calling conventions for passing arguments. We will only 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // ever be called from assembly code and thus can pick more 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // suitable calling conventions. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__i386__) 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".text\n" 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".align 16, 0x90\n" 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".type SyscallAsm, @function\n" 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "SyscallAsm:.cfi_startproc\n" 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Check if "%eax" is negative. If so, do not attempt to make a 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // system call. Instead, compute the return address that is visible 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // to the kernel after we execute "int $0x80". This address can be 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // used as a marker that BPF code inspects. 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "test %eax, %eax\n" 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "jge 1f\n" 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Always, make sure that our code is position-independent, or 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // address space randomization might not work on i386. This means, 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // we can't use "lea", but instead have to rely on "call/pop". 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "call 0f; .cfi_adjust_cfa_offset 4\n" 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "0:pop %eax; .cfi_adjust_cfa_offset -4\n" 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "addl $2f-0b, %eax\n" 56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ret\n" 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Save register that we don't want to clobber. On i386, we need to 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // save relatively aggressively, as there are a couple or registers 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // that are used internally (e.g. %ebx for position-independent 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // code, and %ebp for the frame pointer), and as we need to keep at 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // least a few registers available for the register allocator. 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "1:push %esi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset esi, 0\n" 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "push %edi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset edi, 0\n" 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "push %ebx; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebx, 0\n" 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "push %ebp; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebp, 0\n" 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Copy entries from the array holding the arguments into the 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // correct CPU registers. 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movl 0(%edi), %ebx\n" 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movl 4(%edi), %ecx\n" 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movl 8(%edi), %edx\n" 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movl 12(%edi), %esi\n" 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movl 20(%edi), %ebp\n" 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movl 16(%edi), %edi\n" 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enter the kernel. 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "int $0x80\n" 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // This is our "magic" return address that the BPF filter sees. 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "2:" 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Restore any clobbered registers that we didn't declare to the 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // compiler. 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "pop %ebp; .cfi_restore ebp; .cfi_adjust_cfa_offset -4\n" 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "pop %ebx; .cfi_restore ebx; .cfi_adjust_cfa_offset -4\n" 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "pop %edi; .cfi_restore edi; .cfi_adjust_cfa_offset -4\n" 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "pop %esi; .cfi_restore esi; .cfi_adjust_cfa_offset -4\n" 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ret\n" 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_endproc\n" 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "9:.size SyscallAsm, 9b-SyscallAsm\n" 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__x86_64__) 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".text\n" 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".align 16, 0x90\n" 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".type SyscallAsm, @function\n" 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "SyscallAsm:.cfi_startproc\n" 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Check if "%rax" is negative. If so, do not attempt to make a 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // system call. Instead, compute the return address that is visible 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // to the kernel after we execute "syscall". This address can be 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // used as a marker that BPF code inspects. 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "test %rax, %rax\n" 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "jge 1f\n" 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Always make sure that our code is position-independent, or the 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // linker will throw a hissy fit on x86-64. 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "call 0f; .cfi_adjust_cfa_offset 8\n" 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "0:pop %rax; .cfi_adjust_cfa_offset -8\n" 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "addq $2f-0b, %rax\n" 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ret\n" 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // We declared all clobbered registers to the compiler. On x86-64, 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // there really isn't much of a problem with register pressure. So, 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // we can go ahead and directly copy the entries from the arguments 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // array into the appropriate CPU registers. 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "1:movq 0(%r12), %rdi\n" 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movq 8(%r12), %rsi\n" 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movq 16(%r12), %rdx\n" 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movq 24(%r12), %r10\n" 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movq 32(%r12), %r8\n" 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "movq 40(%r12), %r9\n" 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enter the kernel. 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "syscall\n" 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // This is our "magic" return address that the BPF filter sees. 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "2:ret\n" 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_endproc\n" 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "9:.size SyscallAsm, 9b-SyscallAsm\n" 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__arm__) 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Throughout this file, we use the same mode (ARM vs. thumb) 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // that the C++ compiler uses. This means, when transfering control 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // from C++ to assembly code, we do not need to switch modes (e.g. 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // by using the "bx" instruction). It also means that our assembly 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // code should not be invoked directly from code that lives in 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // other compilation units, as we don't bother implementing thumb 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // interworking. That's OK, as we don't make any of the assembly 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // symbols public. They are all local to this file. 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".text\n" 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".align 2\n" 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".type SyscallAsm, %function\n" 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__thumb__) 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".thumb_func\n" 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".arm\n" 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "SyscallAsm:.fnstart\n" 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "@ args = 0, pretend = 0, frame = 8\n" 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "@ frame_needed = 1, uses_anonymous_args = 0\n" 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__thumb__) 141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_startproc\n" 142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "push {r7, lr}\n" 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_offset 14, -4\n" 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_offset 7, -8\n" 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "mov r7, sp\n" 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_def_cfa_register 7\n" 147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_def_cfa_offset 8\n" 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "stmfd sp!, {fp, lr}\n" 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "add fp, sp, #4\n" 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Check if "r0" is negative. If so, do not attempt to make a 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // system call. Instead, compute the return address that is visible 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // to the kernel after we execute "swi 0". This address can be 155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // used as a marker that BPF code inspects. 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "cmp r0, #0\n" 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "bge 1f\n" 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "adr r0, 2f\n" 159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "b 2f\n" 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // We declared (almost) all clobbered registers to the compiler. On 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // ARM there is no particular register pressure. So, we can go 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // ahead and directly copy the entries from the arguments array 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // into the appropriate CPU registers. 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "1:ldr r5, [r6, #20]\n" 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ldr r4, [r6, #16]\n" 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ldr r3, [r6, #12]\n" 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ldr r2, [r6, #8]\n" 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ldr r1, [r6, #4]\n" 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "mov r7, r0\n" 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "ldr r0, [r6, #0]\n" 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enter the kernel 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "swi 0\n" 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Restore the frame pointer. Also restore the program counter from 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// the link register; this makes us return to the caller. 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__thumb__) 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "2:pop {r7, pc}\n" 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".cfi_endproc\n" 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "2:ldmfd sp!, {fp, pc}\n" 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ".fnend\n" 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "9:.size SyscallAsm, 9b-SyscallAsm\n" 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#elif defined(__mips__) 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".text\n" 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".align 4\n" 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".type SyscallAsm, @function\n" 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "SyscallAsm:.ent SyscallAsm\n" 1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".frame $sp, 40, $ra\n" 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".set push\n" 1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".set noreorder\n" 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "addiu $sp, $sp, -40\n" 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "sw $ra, 36($sp)\n" 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Check if "v0" is negative. If so, do not attempt to make a 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // system call. Instead, compute the return address that is visible 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // to the kernel after we execute "syscall". This address can be 1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // used as a marker that BPF code inspects. 1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "bgez $v0, 1f\n" 1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) " nop\n" 1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "la $v0, 2f\n" 2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "b 2f\n" 2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) " nop\n" 2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // On MIPS first four arguments go to registers a0 - a3 and any 2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // argument after that goes to stack. We can go ahead and directly 2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // copy the entries from the arguments array into the appropriate 2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // CPU registers and on the stack. 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "1:lw $a3, 28($a0)\n" 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $a2, 24($a0)\n" 2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $a1, 20($a0)\n" 2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $t0, 16($a0)\n" 2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "sw $a3, 28($sp)\n" 2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "sw $a2, 24($sp)\n" 2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "sw $a1, 20($sp)\n" 2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "sw $t0, 16($sp)\n" 2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $a3, 12($a0)\n" 2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $a2, 8($a0)\n" 2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $a1, 4($a0)\n" 2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "lw $a0, 0($a0)\n" 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Enter the kernel 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "syscall\n" 2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // This is our "magic" return address that the BPF filter sees. 2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Restore the return address from the stack. 2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "2:lw $ra, 36($sp)\n" 2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "jr $ra\n" 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) " addiu $sp, $sp, 40\n" 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".set pop\n" 2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".end SyscallAsm\n" 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ".size SyscallAsm,.-SyscallAsm\n" 2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#elif defined(__aarch64__) 2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ".text\n" 2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ".align 2\n" 2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ".type SyscallAsm, %function\n" 2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "SyscallAsm:\n" 2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ".cfi_startproc\n" 2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "cmp x0, #0\n" 2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "b.ge 1f\n" 2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "adr x0,2f\n" 2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "b 2f\n" 2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "1:ldr x5, [x6, #40]\n" 2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "ldr x4, [x6, #32]\n" 2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "ldr x3, [x6, #24]\n" 2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "ldr x2, [x6, #16]\n" 2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "ldr x1, [x6, #8]\n" 2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "mov x8, x0\n" 2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "ldr x0, [x6, #0]\n" 2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Enter the kernel 2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "svc 0\n" 2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "2:ret\n" 2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ".cfi_endproc\n" 2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ".size SyscallAsm, .-SyscallAsm\n" 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ); // asm 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)intptr_t Syscall::InvalidCall() { 2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Explicitly pass eight zero arguments just in case. 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Call(kInvalidSyscallNumber, 0, 0, 0, 0, 0, 0, 0, 0); 2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)intptr_t Syscall::Call(int nr, 261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) intptr_t p0, 262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) intptr_t p1, 263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) intptr_t p2, 264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) intptr_t p3, 265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) intptr_t p4, 266116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch intptr_t p5, 267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch intptr_t p6, 268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch intptr_t p7) { 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We rely on "intptr_t" to be the exact size as a "void *". This is 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // typically true, but just in case, we add a check. The language 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // specification allows platforms some leeway in cases, where 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // that this would only be an issue for IA64, which we are currently not 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // planning on supporting. And it is even possible that this would work 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // on IA64, but for lack of actual hardware, I cannot test. 276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) COMPILE_ASSERT(sizeof(void*) == sizeof(intptr_t), 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pointer_types_and_intptr_must_be_exactly_the_same_size); 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // TODO(nedeljko): Enable use of more than six parameters on architectures 280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // where that makes sense. 2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(__mips__) 2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7}; 2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else 284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not " 285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "added for this architecture"; 286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not " 287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "added for this architecture"; 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const intptr_t args[6] = {p0, p1, p2, p3, p4, p5}; 2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif // defined(__mips__) 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Invoke our file-scope assembly code. The constraints have been picked 292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// carefully to match what the rest of the assembly code expects in input, 293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// output, and clobbered registers. 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__i386__) 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) intptr_t ret = nr; 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) asm volatile( 297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "call SyscallAsm\n" 298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // N.B. These are not the calling conventions normally used by the ABI. 299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "=a"(ret) 300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "0"(ret), "D"(args) 301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "cc", "esp", "memory", "ecx", "edx"); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__x86_64__) 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) intptr_t ret = nr; 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) register const intptr_t* data __asm__("r12") = args; 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) asm volatile( 307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "lea -128(%%rsp), %%rsp\n" // Avoid red zone. 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "call SyscallAsm\n" 309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "lea 128(%%rsp), %%rsp\n" 310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // N.B. These are not the calling conventions normally used by the ABI. 311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "=a"(ret) 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "0"(ret), "r"(data) 313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "cc", 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "rsp", 315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "memory", 316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "rcx", 317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "rdi", 318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "rsi", 319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "rdx", 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r8", 321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r9", 322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r10", 323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r11"); 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(__arm__) 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) intptr_t ret; 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) register intptr_t inout __asm__("r0") = nr; 329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) register const intptr_t* data __asm__("r6") = args; 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) asm volatile( 331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "bl SyscallAsm\n" 332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // N.B. These are not the calling conventions normally used by the ABI. 333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "=r"(inout) 334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "0"(inout), "r"(data) 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : "cc", 336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "lr", 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "memory", 338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r1", 339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r2", 340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r3", 341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r4", 342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r5" 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if !defined(__thumb__) 344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // In thumb mode, we cannot use "r7" as a general purpose register, as 345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // it is our frame pointer. We have to manually manage and preserve 346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // it. 347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // In ARM mode, we have a dedicated frame pointer register and "r7" is 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // thus available as a general purpose register. We don't preserve it, 349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // but instead mark it as clobbered. 350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) , 351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) "r7" 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif // !defined(__thumb__) 353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ); 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = inout; 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#elif defined(__mips__) 3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int err_status; 3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status); 3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (err_status) { 3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // On error, MIPS returns errno from syscall instead of -errno. 3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The purpose of this negation is for SandboxSyscall() to behave 3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // more like it would on other architectures. 3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ret = -ret; 3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#elif defined(__aarch64__) 3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci intptr_t ret; 3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci { 3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci register intptr_t inout __asm__("x0") = nr; 3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci register const intptr_t* data __asm__("x6") = args; 3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci asm volatile("bl SyscallAsm\n" 3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : "=r"(inout) 3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : "0"(inout), "r"(data) 3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : "memory", "x1", "x2", "x3", "x4", "x5", "x8", "x30"); 3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ret = inout; 3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#error "Unimplemented architecture" 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ret; 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) { 3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(__mips__) 3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Mips ABI states that on error a3 CPU register has non zero value and if 3875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // there is no error, it should be zero. 3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ret_val <= -1 && ret_val >= -4095) { 3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |ret_val| followes the Syscall::Call() convention of being -errno on 3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // errors. In order to write correct value to return register this sign 3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // needs to be changed back. 3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ret_val = -ret_val; 3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SECCOMP_PARM4(ctx) = 1; 3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else 3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SECCOMP_PARM4(ctx) = 0; 3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif 3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val); 3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(__mips__) 4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)intptr_t Syscall::SandboxSyscallRaw(int nr, 4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const intptr_t* args, 4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) intptr_t* err_ret) { 4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) register intptr_t ret __asm__("v0") = nr; 4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // a3 register becomes non zero on error. 4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) register intptr_t err_stat __asm__("a3") = 0; 4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) { 4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) register const intptr_t* data __asm__("a0") = args; 4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) asm volatile( 4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "la $t9, SyscallAsm\n" 4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "jalr $t9\n" 4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) " nop\n" 4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : "=r"(ret), "=r"(err_stat) 4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : "0"(ret), 4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "r"(data) 4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // a2 is in the clober list so inline assembly can not change its 4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // value. 4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : "memory", "ra", "t9", "a2"); 4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Set an error status so it can be used outside of this function 4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *err_ret = err_stat; 4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return ret; 4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif // defined(__mips__) 4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace sandbox 429