X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fsandbox%2Flinux%2Fseccomp-bpf%2Fsyscall.cc;h=b0a41b04769436a2ba1ba5e8b6b06b8399f6c1ac;hb=4a1a0bdd01eef90b0826a0e761d3379d3715c10f;hp=64c0b8eb9b41b708482571febc4d417b3e1110c4;hpb=b1be5ca53587d23e7aeb77b26861fdc0a181ffd8;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/sandbox/linux/seccomp-bpf/syscall.cc b/src/sandbox/linux/seccomp-bpf/syscall.cc index 64c0b8e..b0a41b0 100644 --- a/src/sandbox/linux/seccomp-bpf/syscall.cc +++ b/src/sandbox/linux/seccomp-bpf/syscall.cc @@ -8,11 +8,21 @@ #include #include "base/basictypes.h" +#include "base/logging.h" +#include "sandbox/linux/seccomp-bpf/linux_seccomp.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 @@ -49,10 +59,10 @@ asm(// We need to be able to tell the kernel exactly where we made a // 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\n" - "push %edi; .cfi_adjust_cfa_offset 4\n" - "push %ebx; .cfi_adjust_cfa_offset 4\n" - "push %ebp; .cfi_adjust_cfa_offset 4\n" + "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" @@ -67,10 +77,10 @@ asm(// We need to be able to tell the kernel exactly where we made a "2:" // Restore any clobbered registers that we didn't declare to the // compiler. - "pop %ebp; .cfi_adjust_cfa_offset -4\n" - "pop %ebx; .cfi_adjust_cfa_offset -4\n" - "pop %edi; .cfi_adjust_cfa_offset -4\n" - "pop %esi; .cfi_adjust_cfa_offset -4\n" + "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" @@ -170,18 +180,70 @@ asm(// We need to be able to tell the kernel exactly where we made a #endif ".fnend\n" "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" #endif ); // asm } // 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 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 @@ -192,7 +254,17 @@ intptr_t Syscall::Call(int nr, COMPILE_ASSERT(sizeof(void*) == sizeof(intptr_t), pointer_types_and_intptr_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, @@ -259,10 +331,64 @@ intptr_t Syscall::Call(int nr, ); 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; + } #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(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