@@ -, +, @@ --- .../linux/bpf_dsl/linux_syscall_ranges.h | 7 +++ .../sandbox/linux/bpf_dsl/seccomp_macros.h | 48 ++++++++++++++ .../sandbox/linux/seccomp-bpf/syscall.cc | 62 ++++++++++++++++++- .../sandbox/linux/seccomp-bpf/trap.cc | 14 +++++ .../linux/services/syscall_wrappers.cc | 2 +- .../linux/system_headers/linux_seccomp.h | 9 +++ .../linux/system_headers/linux_signal.h | 2 +- .../linux/system_headers/linux_syscalls.h | 4 ++ .../linux/system_headers/linux_ucontext.h | 2 + .../system_headers/ppc64_linux_syscalls.h | 12 ++++ .../system_headers/ppc64_linux_ucontext.h | 12 ++++ 11 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 security/sandbox/chromium/sandbox/linux/system_headers/ppc64_linux_syscalls.h create mode 100644 security/sandbox/chromium/sandbox/linux/system_headers/ppc64_linux_ucontext.h --- a/security/sandbox/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h +++ a/security/sandbox/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h @@ -50,6 +50,13 @@ #define MAX_PUBLIC_SYSCALL 279u #define MAX_SYSCALL MAX_PUBLIC_SYSCALL +#elif defined(__powerpc64__) + +#include +#define MIN_SYSCALL 0u +#define MAX_PUBLIC_SYSCALL 386u +#define MAX_SYSCALL MAX_PUBLIC_SYSCALL + #else #error "Unsupported architecture" #endif --- a/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h +++ a/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h @@ -16,6 +16,9 @@ #if defined(__mips__) // sys/user.h in eglibc misses size_t definition #include +#elif defined(__powerpc64__) +// Manually define greg_t on ppc64 +typedef unsigned long long greg_t; #endif #endif @@ -286,6 +289,51 @@ struct regs_struct { #define SECCOMP_PT_PARM4(_regs) (_regs).regs[3] #define SECCOMP_PT_PARM5(_regs) (_regs).regs[4] #define SECCOMP_PT_PARM6(_regs) (_regs).regs[5] + +#elif defined(__powerpc64__) +#include + +typedef struct pt_regs regs_struct; + +#ifdef ARCH_CPU_LITTLE_ENDIAN +#define SECCOMP_ARCH AUDIT_ARCH_PPC64LE +#else +#define SECCOMP_ARCH AUDIT_ARCH_PPC64 +#endif + +#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.regs->gpr[_reg]) + +#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 3) +#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 0) +#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.regs->nip +#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 3) +#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 4) +#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 5) +#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 6) +#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, 7) +#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, 8) + +#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr)) +#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch)) +#define SECCOMP_IP_MSB_IDX \ + (offsetof(struct arch_seccomp_data, instruction_pointer) + 4) +#define SECCOMP_IP_LSB_IDX \ + (offsetof(struct arch_seccomp_data, instruction_pointer) + 0) +#define SECCOMP_ARG_MSB_IDX(nr) \ + (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4) +#define SECCOMP_ARG_LSB_IDX(nr) \ + (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0) + +#define SECCOMP_PT_RESULT(_regs) (_regs).gpr[3] +#define SECCOMP_PT_SYSCALL(_regs) (_regs).gpr[0] +#define SECCOMP_PT_IP(_regs) (_regs).nip +#define SECCOMP_PT_PARM1(_regs) (_regs).gpr[3] +#define SECCOMP_PT_PARM2(_regs) (_regs).gpr[4] +#define SECCOMP_PT_PARM3(_regs) (_regs).gpr[5] +#define SECCOMP_PT_PARM4(_regs) (_regs).gpr[6] +#define SECCOMP_PT_PARM5(_regs) (_regs).gpr[7] +#define SECCOMP_PT_PARM6(_regs) (_regs).gpr[8] + #else #error Unsupported target platform --- a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.cc +++ a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.cc @@ -15,7 +15,7 @@ namespace sandbox { namespace { #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ - defined(ARCH_CPU_MIPS_FAMILY) + defined(ARCH_CPU_MIPS_FAMILY) || defined (ARCH_CPU_PPC64_FAMILY) // Number that's not currently used by any Linux kernel ABIs. const int kInvalidSyscallNumber = 0x351d3; #else @@ -260,12 +260,56 @@ asm(// We need to be able to tell the kernel exactly where we made a // Enter the kernel "svc 0\n" "2:ret\n" + ".cfi_endproc\n" + ".size SyscallAsm, .-SyscallAsm\n" +#elif defined(__powerpc64__) + ".text\n" + ".align 4\n" + ".type SyscallAsm @function\n" + "SyscallAsm:\n" + ".cfi_startproc\n" + + // Check if r3 is negative + "cmpdi 3, 0\n" + "bgt 2f\n" + + // Load address of 3f into r3 and return + "mflr 10\n" + "bl 1f\n" + "1: mflr 3\n" + "mtlr 10\n" + "addi 3, 3, 4*13\n" + "blr\n" + + // Load arguments from array into r3-8 + // save param 3 in r10 + "2:\n" + "mr 0, 3\n" + "ld 3, 0(4)\n" + "ld 5, 16(4)\n" + "ld 6, 24(4)\n" + "ld 7, 32(4)\n" + "ld 8, 40(4)\n" + "ld 4, 8(4)\n" + "li 9, 0\n" + + // Enter kernel + "sc\n" + + // Magic return address + "3:\n" + // Like MIPS, ppc64 return values are always positive. + // Check for error in cr0.SO and negate upon error + "bc 4, 3, 4f\n" + "neg 3, 3\n" + "4: blr\n" + ".cfi_endproc\n" ".size SyscallAsm, .-SyscallAsm\n" #endif ); // asm -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__powerpc64__) extern "C" { intptr_t SyscallAsm(intptr_t nr, const intptr_t args[6]); } @@ -379,6 +423,8 @@ intptr_t Syscall::Call(int nr, ret = inout; } +#elif defined(__powerpc64__) + intptr_t ret = SyscallAsm(nr, args); #else #error "Unimplemented architecture" #endif @@ -395,8 +441,18 @@ void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) { // needs to be changed back. ret_val = -ret_val; SECCOMP_PARM4(ctx) = 1; - } else + } else { SECCOMP_PARM4(ctx) = 0; + } +#endif +#if defined(__powerpc64__) + // Same as MIPS, need to invert ret and set error register (cr0.SO) + if (ret_val <= -1 && ret_val >= -4095) { + ret_val = -ret_val; + ctx->uc_mcontext.regs->ccr |= (1 << 28); + } else { + ctx->uc_mcontext.regs->ccr &= ~(1 << 28); + } #endif SECCOMP_RESULT(ctx) = static_cast(ret_val); } --- a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc +++ a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc @@ -229,6 +229,20 @@ void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) { SetIsInSigHandler(); } +#if defined(__powerpc64__) + // On ppc64+glibc, some syscalls seem to accidentally negate the first + // parameter which causes checks against it to fail. For now, manually + // negate them back. + // TODO(shawn@anastas.io): investigate this issue further + auto nr = SECCOMP_SYSCALL(ctx); + if (nr == __NR_openat || nr == __NR_mkdirat || nr == __NR_faccessat || nr == __NR_readlinkat || + nr == __NR_renameat || nr == __NR_renameat2 || nr == __NR_newfstatat || nr == __NR_unlinkat) { + if (static_cast(SECCOMP_PARM1(ctx)) > 0) { + SECCOMP_PARM1(ctx) = -SECCOMP_PARM1(ctx); + } + } +#endif + // Copy the seccomp-specific data into a arch_seccomp_data structure. This // is what we are showing to TrapFnc callbacks that the system call // evaluator registered with the sandbox. --- a/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.cc +++ a/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.cc @@ -59,7 +59,7 @@ long sys_clone(unsigned long flags, #if defined(ARCH_CPU_X86_64) return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls); #elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \ - defined(ARCH_CPU_MIPS_FAMILY) + defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_PPC64_FAMILY) // CONFIG_CLONE_BACKWARDS defined. return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid); #endif --- a/security/sandbox/chromium/sandbox/linux/system_headers/linux_seccomp.h +++ a/security/sandbox/chromium/sandbox/linux/system_headers/linux_seccomp.h @@ -29,6 +29,9 @@ #ifndef EM_AARCH64 #define EM_AARCH64 183 #endif +#ifndef EM_PPC64 +#define EM_PPC64 21 +#endif #ifndef __AUDIT_ARCH_64BIT #define __AUDIT_ARCH_64BIT 0x80000000 @@ -51,6 +54,12 @@ #ifndef AUDIT_ARCH_AARCH64 #define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) #endif +#ifndef AUDIT_ARCH_PPC64 +#define AUDIT_ARCH_PPC64 (EM_PPC64 | __AUDIT_ARCH_64BIT) +#endif +#ifndef AUDIT_ARCH_PPC64LE +#define AUDIT_ARCH_PPC64LE (EM_PPC64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) +#endif // For prctl.h #ifndef PR_SET_SECCOMP --- a/security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h +++ a/security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h @@ -11,7 +11,7 @@ // (not undefined, but defined different values and in different memory // layouts). So, fill the gap here. #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \ - defined(__aarch64__) + defined(__aarch64__) || defined(__powerpc64__) #define LINUX_SIGHUP 1 #define LINUX_SIGINT 2 --- a/security/sandbox/chromium/sandbox/linux/system_headers/linux_syscalls.h +++ a/security/sandbox/chromium/sandbox/linux/system_headers/linux_syscalls.h @@ -33,5 +33,9 @@ #include "sandbox/linux/system_headers/arm64_linux_syscalls.h" #endif +#if defined(__powerpc64__) +#include "sandbox/linux/system_headers/ppc64_linux_syscalls.h" +#endif + #endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_ --- a/security/sandbox/chromium/sandbox/linux/system_headers/linux_ucontext.h +++ a/security/sandbox/chromium/sandbox/linux/system_headers/linux_ucontext.h @@ -17,6 +17,8 @@ #include "sandbox/linux/system_headers/mips_linux_ucontext.h" #elif defined(__aarch64__) #include "sandbox/linux/system_headers/arm64_linux_ucontext.h" +#elif defined(__powerpc64__) +#include "sandbox/linux/system_headers/ppc64_linux_ucontext.h" #else #error "No support for your architecture in Android or PNaCl header" #endif --- a/security/sandbox/chromium/sandbox/linux/system_headers/ppc64_linux_syscalls.h +++ a/security/sandbox/chromium/sandbox/linux/system_headers/ppc64_linux_syscalls.h @@ -0,0 +1,12 @@ +// Copyright 2014 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. + +#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_PPC64_LINUX_SYSCALLS_H_ +#define SANDBOX_LINUX_SYSTEM_HEADERS_PPC64_LINUX_SYSCALLS_H_ + +#include + +//TODO: is it necessary to redefine syscall numbers for PPC64? + +#endif // SANDBOX_LINUX_SYSTEM_HEADERS_PPC64_LINUX_SYSCALLS_H_ --- a/security/sandbox/chromium/sandbox/linux/system_headers/ppc64_linux_ucontext.h +++ a/security/sandbox/chromium/sandbox/linux/system_headers/ppc64_linux_ucontext.h @@ -0,0 +1,12 @@ +// Copyright 2014 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. + +#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_PPC64_LINUX_UCONTEXT_H_ +#define SANDBOX_LINUX_SYSTEM_HEADERS_PPC64_LINUX_UCONTEXT_H_ + +#include + +//TODO: is it necessary to redefine ucontext on PPC64? + +#endif // SANDBOX_LINUX_SYSTEM_HEADERS_PPC64_LINUX_UCONTEXT_H_ -- --- .../chromium/sandbox/linux/bpf_dsl/seccomp_macros.h | 11 +++++++++++ 1 file changed, 11 insertions(+) --- a/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h +++ a/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h @@ -315,6 +315,7 @@ typedef struct pt_regs regs_struct; #define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr)) #define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch)) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define SECCOMP_IP_MSB_IDX \ (offsetof(struct arch_seccomp_data, instruction_pointer) + 4) #define SECCOMP_IP_LSB_IDX \ @@ -323,6 +324,16 @@ typedef struct pt_regs regs_struct; (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4) #define SECCOMP_ARG_LSB_IDX(nr) \ (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0) +#else +#define SECCOMP_IP_MSB_IDX \ + (offsetof(struct arch_seccomp_data, instruction_pointer) + 0) +#define SECCOMP_IP_LSB_IDX \ + (offsetof(struct arch_seccomp_data, instruction_pointer) + 4) +#define SECCOMP_ARG_MSB_IDX(nr) \ + (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0) +#define SECCOMP_ARG_LSB_IDX(nr) \ + (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4) +#endif #define SECCOMP_PT_RESULT(_regs) (_regs).gpr[3] #define SECCOMP_PT_SYSCALL(_regs) (_regs).gpr[0] -- --- security/sandbox/linux/reporter/SandboxReporter.cpp | 2 ++ 1 file changed, 2 insertions(+) --- a/security/sandbox/linux/reporter/SandboxReporter.cpp +++ a/security/sandbox/linux/reporter/SandboxReporter.cpp @@ -26,6 +26,8 @@ #define SANDBOX_ARCH_NAME "x86" #elif defined(__x86_64__) #define SANDBOX_ARCH_NAME "amd64" +#elif defined(__powerpc64__) +#define SANDBOX_ARCH_NAME "ppc64" #else #error "unrecognized architecture" #endif --