/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "seccomp.h" #include #include #include #include #include #include #include "log.h" #include "seccomp_policy.h" #define syscall_nr (offsetof(struct seccomp_data, nr)) #define arch_nr (offsetof(struct seccomp_data, arch)) #if defined __arm__ #define AUDIT_ARCH_NR AUDIT_ARCH_ARM #elif defined __aarch64__ #define AUDIT_ARCH_NR AUDIT_ARCH_AARCH64 #define AUDIT_ARCH_NR32 AUDIT_ARCH_ARM #elif defined __i386__ #define AUDIT_ARCH_NR AUDIT_ARCH_I386 #elif defined __x86_64__ #define AUDIT_ARCH_NR AUDIT_ARCH_X86_64 #define AUDIT_ARCH_NR32 AUDIT_ARCH_I386 #elif defined __mips64__ #define AUDIT_ARCH_NR AUDIT_ARCH_MIPS64 #define AUDIT_ARCH_NR32 AUDIT_ARCH_MIPS #elif defined __mips__ && !defined __mips64__ #define AUDIT_ARCH_NR AUDIT_ARCH_MIPS #else #error "Could not determine AUDIT_ARCH_NR for this architecture" #endif typedef std::vector filter; // We want to keep the below inline functions for debugging and future // development even though they are not used currently. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" static inline void Kill(filter& f) { f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL)); } static inline void Trap(filter& f) { f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP)); } static inline void Error(filter& f, __u16 retcode) { f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode)); } inline static void Trace(filter& f) { f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE)); } inline static void Allow(filter& f) { f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)); } inline static void AllowSyscall(filter& f, __u32 num) { f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1)); f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)); } inline static void ExamineSyscall(filter& f) { f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr)); } #ifdef AUDIT_ARCH_NR32 inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) { auto jump_length = f.size() - offset - 1; auto u8_jump_length = (__u8) jump_length; if (u8_jump_length != jump_length) { LOG(ERROR) << "Can't set jump greater than 255 - actual jump is " << jump_length; return -1; } f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, u8_jump_length, 0); return 0; } #endif inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) { f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr)); #ifdef AUDIT_ARCH_NR32 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 2, 0)); f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, 1, 0)); Kill(f); return f.size() - 2; #else f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 1, 0)); Kill(f); return 0; #endif } #pragma clang diagnostic pop static bool install_filter(filter const& f) { struct sock_fprog prog = { (unsigned short) f.size(), (struct sock_filter*) &f[0], }; if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) { PLOG(ERROR) << "SECCOMP: Could not set seccomp filter"; return false; } LOG(INFO) << "SECCOMP: Global filter installed"; return true; } bool set_seccomp_filter() { filter f; // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a // jump that must be changed to point to the start of the 32-bit policy // 32 bit syscalls will not hit the policy between here and the call to SetJump #ifdef AUDIT_ARCH_NR32 auto offset_to_32bit_filter = #endif ValidateArchitectureAndJumpIfNeeded(f); // Native filter ExamineSyscall(f); #ifdef __aarch64__ // Syscalls needed to boot Android AllowSyscall(f, __NR_pivot_root); AllowSyscall(f, __NR_ioprio_get); AllowSyscall(f, __NR_ioprio_set); AllowSyscall(f, __NR_gettid); AllowSyscall(f, __NR_futex); AllowSyscall(f, __NR_clone); AllowSyscall(f, __NR_rt_sigreturn); AllowSyscall(f, __NR_rt_tgsigqueueinfo); AllowSyscall(f, __NR_add_key); AllowSyscall(f, __NR_request_key); AllowSyscall(f, __NR_keyctl); AllowSyscall(f, __NR_restart_syscall); AllowSyscall(f, __NR_getrandom); // Needed for performance tools AllowSyscall(f, __NR_perf_event_open); // Needed for treble AllowSyscall(f, __NR_finit_module); // Needed for trusty AllowSyscall(f, __NR_syncfs); // arm64-only filter - autogenerated from bionic syscall usage for (size_t i = 0; i < arm64_filter_size; ++i) f.push_back(arm64_filter[i]); #else // Generic policy Allow(f); #endif #ifdef AUDIT_ARCH_NR32 if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0) return -1; // 32-bit filter for 64-bit platforms ExamineSyscall(f); #ifdef __aarch64__ // Syscalls needed to boot android AllowSyscall(f, 120); // __NR_clone AllowSyscall(f, 240); // __NR_futex AllowSyscall(f, 119); // __NR_sigreturn AllowSyscall(f, 173); // __NR_rt_sigreturn AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo AllowSyscall(f, 224); // __NR_gettid // Syscalls needed to run Chrome AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome // Syscalls needed to run GFXBenchmark AllowSyscall(f, 190); // __NR_vfork // arm32-on-arm64 only filter - autogenerated from bionic syscall usage for (size_t i = 0; i < arm_filter_size; ++i) f.push_back(arm_filter[i]); #else // Generic policy Allow(f); #endif #endif return install_filter(f); }