Home | History | Annotate | Download | only in seccomp
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "seccomp_policy.h"
     18 
     19 #include <assert.h>
     20 #include <linux/audit.h>
     21 #include <linux/seccomp.h>
     22 #include <sys/prctl.h>
     23 
     24 #include <vector>
     25 
     26 #include <android-base/logging.h>
     27 
     28 #include "seccomp_bpfs.h"
     29 
     30 
     31 #if defined __arm__ || defined __aarch64__
     32 
     33 #define DUAL_ARCH
     34 #define PRIMARY_ARCH AUDIT_ARCH_AARCH64
     35 static const struct sock_filter* primary_app_filter = arm64_app_filter;
     36 static const size_t primary_app_filter_size = arm64_app_filter_size;
     37 static const struct sock_filter* primary_system_filter = arm64_system_filter;
     38 static const size_t primary_system_filter_size = arm64_system_filter_size;
     39 static const struct sock_filter* primary_global_filter = arm64_global_filter;
     40 static const size_t primary_global_filter_size = arm64_global_filter_size;
     41 #define SECONDARY_ARCH AUDIT_ARCH_ARM
     42 static const struct sock_filter* secondary_app_filter = arm_app_filter;
     43 static const size_t secondary_app_filter_size = arm_app_filter_size;
     44 static const struct sock_filter* secondary_system_filter = arm_system_filter;
     45 static const size_t secondary_system_filter_size = arm_system_filter_size;
     46 static const struct sock_filter* secondary_global_filter = arm_global_filter;
     47 static const size_t secondary_global_filter_size = arm_global_filter_size;
     48 
     49 #elif defined __i386__ || defined __x86_64__
     50 
     51 #define DUAL_ARCH
     52 #define PRIMARY_ARCH AUDIT_ARCH_X86_64
     53 static const struct sock_filter* primary_app_filter = x86_64_app_filter;
     54 static const size_t primary_app_filter_size = x86_64_app_filter_size;
     55 static const struct sock_filter* primary_system_filter = x86_64_system_filter;
     56 static const size_t primary_system_filter_size = x86_64_system_filter_size;
     57 static const struct sock_filter* primary_global_filter = x86_64_global_filter;
     58 static const size_t primary_global_filter_size = x86_64_global_filter_size;
     59 #define SECONDARY_ARCH AUDIT_ARCH_I386
     60 static const struct sock_filter* secondary_app_filter = x86_app_filter;
     61 static const size_t secondary_app_filter_size = x86_app_filter_size;
     62 static const struct sock_filter* secondary_system_filter = x86_system_filter;
     63 static const size_t secondary_system_filter_size = x86_system_filter_size;
     64 static const struct sock_filter* secondary_global_filter = x86_global_filter;
     65 static const size_t secondary_global_filter_size = x86_global_filter_size;
     66 
     67 #elif defined __mips__ || defined __mips64__
     68 
     69 #define DUAL_ARCH
     70 #define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
     71 static const struct sock_filter* primary_app_filter = mips64_app_filter;
     72 static const size_t primary_app_filter_size = mips64_app_filter_size;
     73 static const struct sock_filter* primary_system_filter = mips64_system_filter;
     74 static const size_t primary_system_filter_size = mips64_system_filter_size;
     75 static const struct sock_filter* primary_global_filter = mips64_global_filter;
     76 static const size_t primary_global_filter_size = mips64_global_filter_size;
     77 #define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
     78 static const struct sock_filter* secondary_app_filter = mips_app_filter;
     79 static const size_t secondary_app_filter_size = mips_app_filter_size;
     80 static const struct sock_filter* secondary_system_filter = mips_system_filter;
     81 static const size_t secondary_system_filter_size = mips_system_filter_size;
     82 static const struct sock_filter* secondary_global_filter = mips_global_filter;
     83 static const size_t secondary_global_filter_size = mips_global_filter_size;
     84 
     85 #else
     86 #error No architecture was defined!
     87 #endif
     88 
     89 
     90 #define syscall_nr (offsetof(struct seccomp_data, nr))
     91 #define arch_nr (offsetof(struct seccomp_data, arch))
     92 
     93 typedef std::vector<sock_filter> filter;
     94 
     95 inline void Disallow(filter& f) {
     96     f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
     97 }
     98 
     99 static void ExamineSyscall(filter& f) {
    100     f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
    101 }
    102 
    103 #ifdef DUAL_ARCH
    104 static bool SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
    105     size_t jump_length = f.size() - offset - 1;
    106     auto u8_jump_length = (__u8) jump_length;
    107     if (u8_jump_length != jump_length) {
    108         LOG(FATAL)
    109             << "Can't set jump greater than 255 - actual jump is " <<  jump_length;
    110         return false;
    111     }
    112     f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, u8_jump_length, 0);
    113     return true;
    114 }
    115 
    116 static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
    117     f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
    118     f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 2, 0));
    119     f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, 1, 0));
    120     Disallow(f);
    121     return f.size() - 2;
    122 }
    123 #else
    124 static void ValidateArchitecture(filter& f) {
    125     f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
    126     f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 1, 0));
    127     Disallow(f);
    128 }
    129 #endif
    130 
    131 static bool install_filter(filter const& f) {
    132     struct sock_fprog prog = {
    133         static_cast<unsigned short>(f.size()),
    134         const_cast<struct sock_filter*>(&f[0]),
    135     };
    136     // This assumes either the current process has CAP_SYS_ADMIN, or PR_SET_NO_NEW_PRIVS bit is set.
    137     if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
    138         PLOG(FATAL) << "Could not set seccomp filter of size " << f.size();
    139         return false;
    140     }
    141     return true;
    142 }
    143 
    144 enum FilterType {
    145   APP,
    146   SYSTEM,
    147   GLOBAL
    148 };
    149 
    150 bool _set_seccomp_filter(FilterType type) {
    151     const sock_filter *p, *s;
    152     size_t p_size, s_size;
    153     filter f;
    154 
    155     switch (type) {
    156       case APP:
    157         p = primary_app_filter;
    158         p_size = primary_app_filter_size;
    159         s = secondary_app_filter;
    160         s_size = secondary_app_filter_size;
    161         break;
    162       case SYSTEM:
    163         p = primary_system_filter;
    164         p_size = primary_system_filter_size;
    165         s = secondary_system_filter;
    166         s_size = secondary_system_filter_size;
    167         break;
    168       case GLOBAL:
    169         p = primary_global_filter;
    170         p_size = primary_global_filter_size;
    171         s = secondary_global_filter;
    172         s_size = secondary_global_filter_size;
    173         break;
    174 
    175     }
    176 
    177 #ifdef DUAL_ARCH
    178     // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
    179     // jump that must be changed to point to the start of the 32-bit policy
    180     // 32 bit syscalls will not hit the policy between here and the call to SetJump
    181     auto offset_to_secondary_filter = ValidateArchitectureAndJumpIfNeeded(f);
    182 #else
    183     ValidateArchitecture(f);
    184 #endif
    185 
    186     ExamineSyscall(f);
    187 
    188     for (size_t i = 0; i < p_size; ++i) {
    189         f.push_back(p[i]);
    190     }
    191     Disallow(f);
    192 
    193 #ifdef DUAL_ARCH
    194     if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
    195         return false;
    196     }
    197 
    198     ExamineSyscall(f);
    199 
    200     for (size_t i = 0; i < s_size; ++i) {
    201         f.push_back(s[i]);
    202     }
    203     Disallow(f);
    204 #endif
    205 
    206     return install_filter(f);
    207 }
    208 
    209 bool set_app_seccomp_filter() {
    210     return _set_seccomp_filter(FilterType::APP);
    211 }
    212 
    213 bool set_system_seccomp_filter() {
    214     return _set_seccomp_filter(FilterType::SYSTEM);
    215 }
    216 
    217 bool set_global_seccomp_filter() {
    218     return _set_seccomp_filter(FilterType::GLOBAL);
    219 }
    220