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_filter = arm64_filter;
     36 static const size_t primary_filter_size = arm64_filter_size;
     37 #define SECONDARY_ARCH AUDIT_ARCH_ARM
     38 static const struct sock_filter* secondary_filter = arm_filter;
     39 static const size_t secondary_filter_size = arm_filter_size;
     40 
     41 #elif defined __i386__ || defined __x86_64__
     42 
     43 #define DUAL_ARCH
     44 #define PRIMARY_ARCH AUDIT_ARCH_X86_64
     45 static const struct sock_filter* primary_filter = x86_64_filter;
     46 static const size_t primary_filter_size = x86_64_filter_size;
     47 #define SECONDARY_ARCH AUDIT_ARCH_I386
     48 static const struct sock_filter* secondary_filter = x86_filter;
     49 static const size_t secondary_filter_size = x86_filter_size;
     50 
     51 #elif defined __mips__ || defined __mips64__
     52 
     53 #define DUAL_ARCH
     54 #define PRIMARY_ARCH AUDIT_ARCH_MIPS64
     55 static const struct sock_filter* primary_filter = mips64_filter;
     56 static const size_t primary_filter_size = mips64_filter_size;
     57 #define SECONDARY_ARCH AUDIT_ARCH_MIPS
     58 static const struct sock_filter* secondary_filter = mips_filter;
     59 static const size_t secondary_filter_size = mips_filter_size;
     60 
     61 #else
     62 #error No architecture was defined!
     63 #endif
     64 
     65 
     66 #define syscall_nr (offsetof(struct seccomp_data, nr))
     67 #define arch_nr (offsetof(struct seccomp_data, arch))
     68 
     69 typedef std::vector<sock_filter> filter;
     70 
     71 inline void Disallow(filter& f) {
     72     f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
     73 }
     74 
     75 static void ExamineSyscall(filter& f) {
     76     f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
     77 }
     78 
     79 #ifdef DUAL_ARCH
     80 static bool SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
     81     size_t jump_length = f.size() - offset - 1;
     82     auto u8_jump_length = (__u8) jump_length;
     83     if (u8_jump_length != jump_length) {
     84         LOG(FATAL)
     85             << "Can't set jump greater than 255 - actual jump is " <<  jump_length;
     86         return false;
     87     }
     88     f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, u8_jump_length, 0);
     89     return true;
     90 }
     91 
     92 static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
     93     f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
     94     f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 2, 0));
     95     f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, 1, 0));
     96     Disallow(f);
     97     return f.size() - 2;
     98 }
     99 #else
    100 static void ValidateArchitecture(filter& f) {
    101     f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
    102     f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 1, 0));
    103     Disallow(f);
    104 }
    105 #endif
    106 
    107 static bool install_filter(filter const& f) {
    108     struct sock_fprog prog = {
    109         static_cast<unsigned short>(f.size()),
    110         const_cast<struct sock_filter*>(&f[0]),
    111     };
    112 
    113     if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
    114         PLOG(FATAL) << "Could not set seccomp filter of size " << f.size();
    115         return false;
    116     }
    117 
    118     LOG(INFO) << "Global filter of size " << f.size() << " installed";
    119     return true;
    120 }
    121 
    122 bool set_seccomp_filter() {
    123     filter f;
    124 
    125 #ifdef DUAL_ARCH
    126     // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
    127     // jump that must be changed to point to the start of the 32-bit policy
    128     // 32 bit syscalls will not hit the policy between here and the call to SetJump
    129     auto offset_to_secondary_filter = ValidateArchitectureAndJumpIfNeeded(f);
    130 #else
    131     ValidateArchitecture(f);
    132 #endif
    133 
    134     ExamineSyscall(f);
    135 
    136     for (size_t i = 0; i < primary_filter_size; ++i) {
    137         f.push_back(primary_filter[i]);
    138     }
    139     Disallow(f);
    140 
    141 #ifdef DUAL_ARCH
    142     if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
    143         return false;
    144     }
    145 
    146     ExamineSyscall(f);
    147 
    148     for (size_t i = 0; i < secondary_filter_size; ++i) {
    149         f.push_back(secondary_filter[i]);
    150     }
    151     Disallow(f);
    152 #endif
    153 
    154     return install_filter(f);
    155 }
    156 
    157 void get_seccomp_filter(const sock_filter*& filter, size_t& filter_size) {
    158 #if defined __aarch64__ || defined __x86_64__ || defined __mips64__
    159     filter = primary_filter;
    160     filter_size = primary_filter_size;
    161 #else
    162     filter = secondary_filter;
    163     filter_size = secondary_filter_size;
    164 #endif
    165 }
    166