1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sandbox/linux/bpf_dsl/verifier.h" 6 7 #include <stdint.h> 8 #include <string.h> 9 10 #include "base/macros.h" 11 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" 12 #include "sandbox/linux/bpf_dsl/trap_registry.h" 13 #include "sandbox/linux/system_headers/linux_filter.h" 14 #include "sandbox/linux/system_headers/linux_seccomp.h" 15 16 namespace sandbox { 17 namespace bpf_dsl { 18 19 namespace { 20 21 struct State { 22 State(const std::vector<struct sock_filter>& p, 23 const struct arch_seccomp_data& d) 24 : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {} 25 const std::vector<struct sock_filter>& program; 26 const struct arch_seccomp_data& data; 27 unsigned int ip; 28 uint32_t accumulator; 29 bool acc_is_valid; 30 31 private: 32 DISALLOW_IMPLICIT_CONSTRUCTORS(State); 33 }; 34 35 void Ld(State* state, const struct sock_filter& insn, const char** err) { 36 if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS || 37 insn.jt != 0 || insn.jf != 0) { 38 *err = "Invalid BPF_LD instruction"; 39 return; 40 } 41 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { 42 // We only allow loading of properly aligned 32bit quantities. 43 memcpy(&state->accumulator, 44 reinterpret_cast<const char*>(&state->data) + insn.k, 4); 45 } else { 46 *err = "Invalid operand in BPF_LD instruction"; 47 return; 48 } 49 state->acc_is_valid = true; 50 return; 51 } 52 53 void Jmp(State* state, const struct sock_filter& insn, const char** err) { 54 if (BPF_OP(insn.code) == BPF_JA) { 55 if (state->ip + insn.k + 1 >= state->program.size() || 56 state->ip + insn.k + 1 <= state->ip) { 57 compilation_failure: 58 *err = "Invalid BPF_JMP instruction"; 59 return; 60 } 61 state->ip += insn.k; 62 } else { 63 if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid || 64 state->ip + insn.jt + 1 >= state->program.size() || 65 state->ip + insn.jf + 1 >= state->program.size()) { 66 goto compilation_failure; 67 } 68 switch (BPF_OP(insn.code)) { 69 case BPF_JEQ: 70 if (state->accumulator == insn.k) { 71 state->ip += insn.jt; 72 } else { 73 state->ip += insn.jf; 74 } 75 break; 76 case BPF_JGT: 77 if (state->accumulator > insn.k) { 78 state->ip += insn.jt; 79 } else { 80 state->ip += insn.jf; 81 } 82 break; 83 case BPF_JGE: 84 if (state->accumulator >= insn.k) { 85 state->ip += insn.jt; 86 } else { 87 state->ip += insn.jf; 88 } 89 break; 90 case BPF_JSET: 91 if (state->accumulator & insn.k) { 92 state->ip += insn.jt; 93 } else { 94 state->ip += insn.jf; 95 } 96 break; 97 default: 98 goto compilation_failure; 99 } 100 } 101 } 102 103 uint32_t Ret(State*, const struct sock_filter& insn, const char** err) { 104 if (BPF_SRC(insn.code) != BPF_K) { 105 *err = "Invalid BPF_RET instruction"; 106 return 0; 107 } 108 return insn.k; 109 } 110 111 void Alu(State* state, const struct sock_filter& insn, const char** err) { 112 if (BPF_OP(insn.code) == BPF_NEG) { 113 state->accumulator = -state->accumulator; 114 return; 115 } else { 116 if (BPF_SRC(insn.code) != BPF_K) { 117 *err = "Unexpected source operand in arithmetic operation"; 118 return; 119 } 120 switch (BPF_OP(insn.code)) { 121 case BPF_ADD: 122 state->accumulator += insn.k; 123 break; 124 case BPF_SUB: 125 state->accumulator -= insn.k; 126 break; 127 case BPF_MUL: 128 state->accumulator *= insn.k; 129 break; 130 case BPF_DIV: 131 if (!insn.k) { 132 *err = "Illegal division by zero"; 133 break; 134 } 135 state->accumulator /= insn.k; 136 break; 137 case BPF_MOD: 138 if (!insn.k) { 139 *err = "Illegal division by zero"; 140 break; 141 } 142 state->accumulator %= insn.k; 143 break; 144 case BPF_OR: 145 state->accumulator |= insn.k; 146 break; 147 case BPF_XOR: 148 state->accumulator ^= insn.k; 149 break; 150 case BPF_AND: 151 state->accumulator &= insn.k; 152 break; 153 case BPF_LSH: 154 if (insn.k > 32) { 155 *err = "Illegal shift operation"; 156 break; 157 } 158 state->accumulator <<= insn.k; 159 break; 160 case BPF_RSH: 161 if (insn.k > 32) { 162 *err = "Illegal shift operation"; 163 break; 164 } 165 state->accumulator >>= insn.k; 166 break; 167 default: 168 *err = "Invalid operator in arithmetic operation"; 169 break; 170 } 171 } 172 } 173 174 } // namespace 175 176 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, 177 const struct arch_seccomp_data& data, 178 const char** err) { 179 *err = NULL; 180 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { 181 *err = "Invalid program length"; 182 return 0; 183 } 184 for (State state(program, data); !*err; ++state.ip) { 185 if (state.ip >= program.size()) { 186 *err = "Invalid instruction pointer in BPF program"; 187 break; 188 } 189 const struct sock_filter& insn = program[state.ip]; 190 switch (BPF_CLASS(insn.code)) { 191 case BPF_LD: 192 Ld(&state, insn, err); 193 break; 194 case BPF_JMP: 195 Jmp(&state, insn, err); 196 break; 197 case BPF_RET: { 198 uint32_t r = Ret(&state, insn, err); 199 switch (r & SECCOMP_RET_ACTION) { 200 case SECCOMP_RET_ALLOW: 201 case SECCOMP_RET_ERRNO: 202 case SECCOMP_RET_KILL: 203 case SECCOMP_RET_TRACE: 204 case SECCOMP_RET_TRAP: 205 break; 206 case SECCOMP_RET_INVALID: // Should never show up in BPF program 207 default: 208 *err = "Unexpected return code found in BPF program"; 209 return 0; 210 } 211 return r; 212 } 213 case BPF_ALU: 214 Alu(&state, insn, err); 215 break; 216 default: 217 *err = "Unexpected instruction in BPF program"; 218 break; 219 } 220 } 221 return 0; 222 } 223 224 } // namespace bpf_dsl 225 } // namespace sandbox 226