summaryrefslogtreecommitdiff
path: root/sandbox/linux/seccomp-bpf/syscall.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/linux/seccomp-bpf/syscall.cc')
-rw-r--r--sandbox/linux/seccomp-bpf/syscall.cc421
1 files changed, 0 insertions, 421 deletions
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
deleted file mode 100644
index bc6461f117..0000000000
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sandbox/linux/seccomp-bpf/syscall.h"
-
-#include <errno.h>
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-
-namespace sandbox {
-
-namespace {
-
-#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
- defined(ARCH_CPU_MIPS_FAMILY)
-// Number that's not currently used by any Linux kernel ABIs.
-const int kInvalidSyscallNumber = 0x351d3;
-#else
-#error Unrecognized architecture
-#endif
-
-asm(// We need to be able to tell the kernel exactly where we made a
- // system call. The C++ compiler likes to sometimes clone or
- // inline code, which would inadvertently end up duplicating
- // the entry point.
- // "gcc" can suppress code duplication with suitable function
- // attributes, but "clang" doesn't have this ability.
- // The "clang" developer mailing list suggested that the correct
- // and portable solution is a file-scope assembly block.
- // N.B. We do mark our code as a proper function so that backtraces
- // work correctly. But we make absolutely no attempt to use the
- // ABI's calling conventions for passing arguments. We will only
- // ever be called from assembly code and thus can pick more
- // suitable calling conventions.
-#if defined(__i386__)
- ".text\n"
- ".align 16, 0x90\n"
- ".type SyscallAsm, @function\n"
- "SyscallAsm:.cfi_startproc\n"
- // Check if "%eax" is negative. If so, do not attempt to make a
- // system call. Instead, compute the return address that is visible
- // to the kernel after we execute "int $0x80". This address can be
- // used as a marker that BPF code inspects.
- "test %eax, %eax\n"
- "jge 1f\n"
- // Always, make sure that our code is position-independent, or
- // address space randomization might not work on i386. This means,
- // we can't use "lea", but instead have to rely on "call/pop".
- "call 0f; .cfi_adjust_cfa_offset 4\n"
- "0:pop %eax; .cfi_adjust_cfa_offset -4\n"
- "addl $2f-0b, %eax\n"
- "ret\n"
- // Save register that we don't want to clobber. On i386, we need to
- // save relatively aggressively, as there are a couple or registers
- // that are used internally (e.g. %ebx for position-independent
- // code, and %ebp for the frame pointer), and as we need to keep at
- // least a few registers available for the register allocator.
- "1:push %esi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset esi, 0\n"
- "push %edi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset edi, 0\n"
- "push %ebx; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebx, 0\n"
- "push %ebp; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebp, 0\n"
- // Copy entries from the array holding the arguments into the
- // correct CPU registers.
- "movl 0(%edi), %ebx\n"
- "movl 4(%edi), %ecx\n"
- "movl 8(%edi), %edx\n"
- "movl 12(%edi), %esi\n"
- "movl 20(%edi), %ebp\n"
- "movl 16(%edi), %edi\n"
- // Enter the kernel.
- "int $0x80\n"
- // This is our "magic" return address that the BPF filter sees.
- "2:"
- // Restore any clobbered registers that we didn't declare to the
- // compiler.
- "pop %ebp; .cfi_restore ebp; .cfi_adjust_cfa_offset -4\n"
- "pop %ebx; .cfi_restore ebx; .cfi_adjust_cfa_offset -4\n"
- "pop %edi; .cfi_restore edi; .cfi_adjust_cfa_offset -4\n"
- "pop %esi; .cfi_restore esi; .cfi_adjust_cfa_offset -4\n"
- "ret\n"
- ".cfi_endproc\n"
- "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#elif defined(__x86_64__)
- ".text\n"
- ".align 16, 0x90\n"
- ".type SyscallAsm, @function\n"
- "SyscallAsm:.cfi_startproc\n"
- // Check if "%rdi" is negative. If so, do not attempt to make a
- // system call. Instead, compute the return address that is visible
- // to the kernel after we execute "syscall". This address can be
- // used as a marker that BPF code inspects.
- "test %rdi, %rdi\n"
- "jge 1f\n"
- // Always make sure that our code is position-independent, or the
- // linker will throw a hissy fit on x86-64.
- "lea 2f(%rip), %rax\n"
- "ret\n"
- // Now we load the registers used to pass arguments to the system
- // call: system call number in %rax, and arguments in %rdi, %rsi,
- // %rdx, %r10, %r8, %r9. Note: These are all caller-save registers
- // (only %rbx, %rbp, %rsp, and %r12-%r15 are callee-save), so no
- // need to worry here about spilling registers or CFI directives.
- "1:movq %rdi, %rax\n"
- "movq 0(%rsi), %rdi\n"
- "movq 16(%rsi), %rdx\n"
- "movq 24(%rsi), %r10\n"
- "movq 32(%rsi), %r8\n"
- "movq 40(%rsi), %r9\n"
- "movq 8(%rsi), %rsi\n"
- // Enter the kernel.
- "syscall\n"
- // This is our "magic" return address that the BPF filter sees.
- "2:ret\n"
- ".cfi_endproc\n"
- "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#elif defined(__arm__)
- // Throughout this file, we use the same mode (ARM vs. thumb)
- // that the C++ compiler uses. This means, when transfering control
- // from C++ to assembly code, we do not need to switch modes (e.g.
- // by using the "bx" instruction). It also means that our assembly
- // code should not be invoked directly from code that lives in
- // other compilation units, as we don't bother implementing thumb
- // interworking. That's OK, as we don't make any of the assembly
- // symbols public. They are all local to this file.
- ".text\n"
- ".align 2\n"
- ".type SyscallAsm, %function\n"
-#if defined(__thumb__)
- ".thumb_func\n"
-#else
- ".arm\n"
-#endif
- "SyscallAsm:\n"
-#if !defined(__native_client_nonsfi__)
- // .fnstart and .fnend pseudo operations creates unwind table.
- // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
- // is not provided by PNaCl toolchain. Disable it.
- ".fnstart\n"
-#endif
- "@ args = 0, pretend = 0, frame = 8\n"
- "@ frame_needed = 1, uses_anonymous_args = 0\n"
-#if defined(__thumb__)
- ".cfi_startproc\n"
- "push {r7, lr}\n"
- ".save {r7, lr}\n"
- ".cfi_offset 14, -4\n"
- ".cfi_offset 7, -8\n"
- ".cfi_def_cfa_offset 8\n"
-#else
- "stmfd sp!, {fp, lr}\n"
- "add fp, sp, #4\n"
-#endif
- // Check if "r0" is negative. If so, do not attempt to make a
- // system call. Instead, compute the return address that is visible
- // to the kernel after we execute "swi 0". This address can be
- // used as a marker that BPF code inspects.
- "cmp r0, #0\n"
- "bge 1f\n"
- "adr r0, 2f\n"
- "b 2f\n"
- // We declared (almost) all clobbered registers to the compiler. On
- // ARM there is no particular register pressure. So, we can go
- // ahead and directly copy the entries from the arguments array
- // into the appropriate CPU registers.
- "1:ldr r5, [r6, #20]\n"
- "ldr r4, [r6, #16]\n"
- "ldr r3, [r6, #12]\n"
- "ldr r2, [r6, #8]\n"
- "ldr r1, [r6, #4]\n"
- "mov r7, r0\n"
- "ldr r0, [r6, #0]\n"
- // Enter the kernel
- "swi 0\n"
-// Restore the frame pointer. Also restore the program counter from
-// the link register; this makes us return to the caller.
-#if defined(__thumb__)
- "2:pop {r7, pc}\n"
- ".cfi_endproc\n"
-#else
- "2:ldmfd sp!, {fp, pc}\n"
-#endif
-#if !defined(__native_client_nonsfi__)
- // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
- // for more details.
- ".fnend\n"
-#endif
- "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#elif defined(__mips__)
- ".text\n"
- ".align 4\n"
- ".type SyscallAsm, @function\n"
- "SyscallAsm:.ent SyscallAsm\n"
- ".frame $sp, 40, $ra\n"
- ".set push\n"
- ".set noreorder\n"
- "addiu $sp, $sp, -40\n"
- "sw $ra, 36($sp)\n"
- // Check if "v0" is negative. If so, do not attempt to make a
- // system call. Instead, compute the return address that is visible
- // to the kernel after we execute "syscall". This address can be
- // used as a marker that BPF code inspects.
- "bgez $v0, 1f\n"
- " nop\n"
- "la $v0, 2f\n"
- "b 2f\n"
- " nop\n"
- // On MIPS first four arguments go to registers a0 - a3 and any
- // argument after that goes to stack. We can go ahead and directly
- // copy the entries from the arguments array into the appropriate
- // CPU registers and on the stack.
- "1:lw $a3, 28($a0)\n"
- "lw $a2, 24($a0)\n"
- "lw $a1, 20($a0)\n"
- "lw $t0, 16($a0)\n"
- "sw $a3, 28($sp)\n"
- "sw $a2, 24($sp)\n"
- "sw $a1, 20($sp)\n"
- "sw $t0, 16($sp)\n"
- "lw $a3, 12($a0)\n"
- "lw $a2, 8($a0)\n"
- "lw $a1, 4($a0)\n"
- "lw $a0, 0($a0)\n"
- // Enter the kernel
- "syscall\n"
- // This is our "magic" return address that the BPF filter sees.
- // Restore the return address from the stack.
- "2:lw $ra, 36($sp)\n"
- "jr $ra\n"
- " addiu $sp, $sp, 40\n"
- ".set pop\n"
- ".end SyscallAsm\n"
- ".size SyscallAsm,.-SyscallAsm\n"
-#elif defined(__aarch64__)
- ".text\n"
- ".align 2\n"
- ".type SyscallAsm, %function\n"
- "SyscallAsm:\n"
- ".cfi_startproc\n"
- "cmp x0, #0\n"
- "b.ge 1f\n"
- "adr x0,2f\n"
- "b 2f\n"
- "1:ldr x5, [x6, #40]\n"
- "ldr x4, [x6, #32]\n"
- "ldr x3, [x6, #24]\n"
- "ldr x2, [x6, #16]\n"
- "ldr x1, [x6, #8]\n"
- "mov x8, x0\n"
- "ldr x0, [x6, #0]\n"
- // Enter the kernel
- "svc 0\n"
- "2:ret\n"
- ".cfi_endproc\n"
- ".size SyscallAsm, .-SyscallAsm\n"
-#endif
- ); // asm
-
-#if defined(__x86_64__)
-extern "C" {
-intptr_t SyscallAsm(intptr_t nr, const intptr_t args[6]);
-}
-#endif
-
-} // namespace
-
-intptr_t Syscall::InvalidCall() {
- // Explicitly pass eight zero arguments just in case.
- return Call(kInvalidSyscallNumber, 0, 0, 0, 0, 0, 0, 0, 0);
-}
-
-intptr_t Syscall::Call(int nr,
- intptr_t p0,
- intptr_t p1,
- intptr_t p2,
- intptr_t p3,
- intptr_t p4,
- intptr_t p5,
- intptr_t p6,
- intptr_t p7) {
- // We rely on "intptr_t" to be the exact size as a "void *". This is
- // typically true, but just in case, we add a check. The language
- // specification allows platforms some leeway in cases, where
- // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect
- // that this would only be an issue for IA64, which we are currently not
- // planning on supporting. And it is even possible that this would work
- // on IA64, but for lack of actual hardware, I cannot test.
- static_assert(sizeof(void*) == sizeof(intptr_t),
- "pointer types and intptr_t must be exactly the same size");
-
- // TODO(nedeljko): Enable use of more than six parameters on architectures
- // where that makes sense.
-#if defined(__mips__)
- const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7};
-#else
- DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not "
- "added for this architecture";
- DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not "
- "added for this architecture";
- const intptr_t args[6] = {p0, p1, p2, p3, p4, p5};
-#endif // defined(__mips__)
-
-// Invoke our file-scope assembly code. The constraints have been picked
-// carefully to match what the rest of the assembly code expects in input,
-// output, and clobbered registers.
-#if defined(__i386__)
- intptr_t ret = nr;
- asm volatile(
- "call SyscallAsm\n"
- // N.B. These are not the calling conventions normally used by the ABI.
- : "=a"(ret)
- : "0"(ret), "D"(args)
- : "cc", "esp", "memory", "ecx", "edx");
-#elif defined(__x86_64__)
- intptr_t ret = SyscallAsm(nr, args);
-#elif defined(__arm__)
- intptr_t ret;
- {
- register intptr_t inout __asm__("r0") = nr;
- register const intptr_t* data __asm__("r6") = args;
- asm volatile(
- "bl SyscallAsm\n"
- // N.B. These are not the calling conventions normally used by the ABI.
- : "=r"(inout)
- : "0"(inout), "r"(data)
- : "cc",
- "lr",
- "memory",
- "r1",
- "r2",
- "r3",
- "r4",
- "r5"
-#if !defined(__thumb__)
- // In thumb mode, we cannot use "r7" as a general purpose register, as
- // it is our frame pointer. We have to manually manage and preserve
- // it.
- // In ARM mode, we have a dedicated frame pointer register and "r7" is
- // thus available as a general purpose register. We don't preserve it,
- // but instead mark it as clobbered.
- ,
- "r7"
-#endif // !defined(__thumb__)
- );
- ret = inout;
- }
-#elif defined(__mips__)
- int err_status;
- intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status);
-
- if (err_status) {
- // On error, MIPS returns errno from syscall instead of -errno.
- // The purpose of this negation is for SandboxSyscall() to behave
- // more like it would on other architectures.
- ret = -ret;
- }
-#elif defined(__aarch64__)
- intptr_t ret;
- {
- register intptr_t inout __asm__("x0") = nr;
- register const intptr_t* data __asm__("x6") = args;
- asm volatile("bl SyscallAsm\n"
- : "=r"(inout)
- : "0"(inout), "r"(data)
- : "memory", "x1", "x2", "x3", "x4", "x5", "x8", "x30");
- ret = inout;
- }
-
-#else
-#error "Unimplemented architecture"
-#endif
- return ret;
-}
-
-void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) {
-#if defined(__mips__)
- // Mips ABI states that on error a3 CPU register has non zero value and if
- // there is no error, it should be zero.
- if (ret_val <= -1 && ret_val >= -4095) {
- // |ret_val| followes the Syscall::Call() convention of being -errno on
- // errors. In order to write correct value to return register this sign
- // needs to be changed back.
- ret_val = -ret_val;
- SECCOMP_PARM4(ctx) = 1;
- } else
- SECCOMP_PARM4(ctx) = 0;
-#endif
- SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val);
-}
-
-#if defined(__mips__)
-intptr_t Syscall::SandboxSyscallRaw(int nr,
- const intptr_t* args,
- intptr_t* err_ret) {
- register intptr_t ret __asm__("v0") = nr;
- // a3 register becomes non zero on error.
- register intptr_t err_stat __asm__("a3") = 0;
- {
- register const intptr_t* data __asm__("a0") = args;
- asm volatile(
- "la $t9, SyscallAsm\n"
- "jalr $t9\n"
- " nop\n"
- : "=r"(ret), "=r"(err_stat)
- : "0"(ret),
- "r"(data)
- // a2 is in the clober list so inline assembly can not change its
- // value.
- : "memory", "ra", "t9", "a2");
- }
-
- // Set an error status so it can be used outside of this function
- *err_ret = err_stat;
-
- return ret;
-}
-#endif // defined(__mips__)
-
-} // namespace sandbox