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/seccomp-bpf/verifier.h" 6 7 #include <string.h> 8 9 #include <limits> 10 11 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 12 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 13 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 14 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 15 16 namespace sandbox { 17 18 namespace { 19 20 const uint64_t kLower32Bits = std::numeric_limits<uint32_t>::max(); 21 const uint64_t kUpper32Bits = static_cast<uint64_t>(kLower32Bits) << 32; 22 const uint64_t kFull64Bits = std::numeric_limits<uint64_t>::max(); 23 24 struct State { 25 State(const std::vector<struct sock_filter>& p, 26 const struct arch_seccomp_data& d) 27 : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {} 28 const std::vector<struct sock_filter>& program; 29 const struct arch_seccomp_data& data; 30 unsigned int ip; 31 uint32_t accumulator; 32 bool acc_is_valid; 33 34 private: 35 DISALLOW_IMPLICIT_CONSTRUCTORS(State); 36 }; 37 38 uint32_t EvaluateErrorCode(SandboxBPF* sandbox, 39 const ErrorCode& code, 40 const struct arch_seccomp_data& data) { 41 if (code.error_type() == ErrorCode::ET_SIMPLE || 42 code.error_type() == ErrorCode::ET_TRAP) { 43 return code.err(); 44 } else if (code.error_type() == ErrorCode::ET_COND) { 45 if (code.width() == ErrorCode::TP_32BIT && 46 (data.args[code.argno()] >> 32) && 47 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) != 48 0xFFFFFFFF80000000ull) { 49 return sandbox->Unexpected64bitArgument().err(); 50 } 51 bool equal = (data.args[code.argno()] & code.mask()) == code.value(); 52 return EvaluateErrorCode( 53 sandbox, equal ? *code.passed() : *code.failed(), data); 54 } else { 55 return SECCOMP_RET_INVALID; 56 } 57 } 58 59 bool VerifyErrorCode(SandboxBPF* sandbox, 60 const std::vector<struct sock_filter>& program, 61 struct arch_seccomp_data* data, 62 const ErrorCode& root_code, 63 const ErrorCode& code, 64 const char** err) { 65 if (code.error_type() == ErrorCode::ET_SIMPLE || 66 code.error_type() == ErrorCode::ET_TRAP) { 67 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err); 68 if (*err) { 69 return false; 70 } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) { 71 // For efficiency's sake, we'd much rather compare "computed_ret" 72 // against "code.err()". This works most of the time, but it doesn't 73 // always work for nested conditional expressions. The test values 74 // that we generate on the fly to probe expressions can trigger 75 // code flow decisions in multiple nodes of the decision tree, and the 76 // only way to compute the correct error code in that situation is by 77 // calling EvaluateErrorCode(). 78 *err = "Exit code from BPF program doesn't match"; 79 return false; 80 } 81 } else if (code.error_type() == ErrorCode::ET_COND) { 82 if (code.argno() < 0 || code.argno() >= 6) { 83 *err = "Invalid argument number in error code"; 84 return false; 85 } 86 87 // TODO(mdempsky): The test values generated here try to provide good 88 // coverage for generated BPF instructions while avoiding combinatorial 89 // explosion on large policies. Ideally we would instead take a fuzzing-like 90 // approach and generate a bounded number of test cases regardless of policy 91 // size. 92 93 // Verify that we can check a value for simple equality. 94 data->args[code.argno()] = code.value(); 95 if (!VerifyErrorCode( 96 sandbox, program, data, root_code, *code.passed(), err)) { 97 return false; 98 } 99 100 // If mask ignores any bits, verify that setting those bits is still 101 // detected as equality. 102 uint64_t ignored_bits = ~code.mask(); 103 if (code.width() == ErrorCode::TP_32BIT) { 104 ignored_bits = static_cast<uint32_t>(ignored_bits); 105 } 106 if ((ignored_bits & kLower32Bits) != 0) { 107 data->args[code.argno()] = code.value() | (ignored_bits & kLower32Bits); 108 if (!VerifyErrorCode( 109 sandbox, program, data, root_code, *code.passed(), err)) { 110 return false; 111 } 112 } 113 if ((ignored_bits & kUpper32Bits) != 0) { 114 data->args[code.argno()] = code.value() | (ignored_bits & kUpper32Bits); 115 if (!VerifyErrorCode( 116 sandbox, program, data, root_code, *code.passed(), err)) { 117 return false; 118 } 119 } 120 121 // Verify that changing bits included in the mask is detected as inequality. 122 if ((code.mask() & kLower32Bits) != 0) { 123 data->args[code.argno()] = code.value() ^ (code.mask() & kLower32Bits); 124 if (!VerifyErrorCode( 125 sandbox, program, data, root_code, *code.failed(), err)) { 126 return false; 127 } 128 } 129 if ((code.mask() & kUpper32Bits) != 0) { 130 data->args[code.argno()] = code.value() ^ (code.mask() & kUpper32Bits); 131 if (!VerifyErrorCode( 132 sandbox, program, data, root_code, *code.failed(), err)) { 133 return false; 134 } 135 } 136 137 if (code.width() == ErrorCode::TP_32BIT) { 138 // For 32-bit system call arguments, we emit additional instructions to 139 // validate the upper 32-bits. Here we test that validation. 140 141 // Arbitrary 64-bit values should be rejected. 142 data->args[code.argno()] = 1ULL << 32; 143 if (!VerifyErrorCode(sandbox, 144 program, 145 data, 146 root_code, 147 sandbox->Unexpected64bitArgument(), 148 err)) { 149 return false; 150 } 151 152 // Upper 32-bits set without the MSB of the lower 32-bits set should be 153 // rejected too. 154 data->args[code.argno()] = kUpper32Bits; 155 if (!VerifyErrorCode(sandbox, 156 program, 157 data, 158 root_code, 159 sandbox->Unexpected64bitArgument(), 160 err)) { 161 return false; 162 } 163 } 164 } else { 165 *err = "Attempting to return invalid error code from BPF program"; 166 return false; 167 } 168 return true; 169 } 170 171 void Ld(State* state, const struct sock_filter& insn, const char** err) { 172 if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS) { 173 *err = "Invalid BPF_LD instruction"; 174 return; 175 } 176 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { 177 // We only allow loading of properly aligned 32bit quantities. 178 memcpy(&state->accumulator, 179 reinterpret_cast<const char*>(&state->data) + insn.k, 180 4); 181 } else { 182 *err = "Invalid operand in BPF_LD instruction"; 183 return; 184 } 185 state->acc_is_valid = true; 186 return; 187 } 188 189 void Jmp(State* state, const struct sock_filter& insn, const char** err) { 190 if (BPF_OP(insn.code) == BPF_JA) { 191 if (state->ip + insn.k + 1 >= state->program.size() || 192 state->ip + insn.k + 1 <= state->ip) { 193 compilation_failure: 194 *err = "Invalid BPF_JMP instruction"; 195 return; 196 } 197 state->ip += insn.k; 198 } else { 199 if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid || 200 state->ip + insn.jt + 1 >= state->program.size() || 201 state->ip + insn.jf + 1 >= state->program.size()) { 202 goto compilation_failure; 203 } 204 switch (BPF_OP(insn.code)) { 205 case BPF_JEQ: 206 if (state->accumulator == insn.k) { 207 state->ip += insn.jt; 208 } else { 209 state->ip += insn.jf; 210 } 211 break; 212 case BPF_JGT: 213 if (state->accumulator > insn.k) { 214 state->ip += insn.jt; 215 } else { 216 state->ip += insn.jf; 217 } 218 break; 219 case BPF_JGE: 220 if (state->accumulator >= insn.k) { 221 state->ip += insn.jt; 222 } else { 223 state->ip += insn.jf; 224 } 225 break; 226 case BPF_JSET: 227 if (state->accumulator & insn.k) { 228 state->ip += insn.jt; 229 } else { 230 state->ip += insn.jf; 231 } 232 break; 233 default: 234 goto compilation_failure; 235 } 236 } 237 } 238 239 uint32_t Ret(State*, const struct sock_filter& insn, const char** err) { 240 if (BPF_SRC(insn.code) != BPF_K) { 241 *err = "Invalid BPF_RET instruction"; 242 return 0; 243 } 244 return insn.k; 245 } 246 247 void Alu(State* state, const struct sock_filter& insn, const char** err) { 248 if (BPF_OP(insn.code) == BPF_NEG) { 249 state->accumulator = -state->accumulator; 250 return; 251 } else { 252 if (BPF_SRC(insn.code) != BPF_K) { 253 *err = "Unexpected source operand in arithmetic operation"; 254 return; 255 } 256 switch (BPF_OP(insn.code)) { 257 case BPF_ADD: 258 state->accumulator += insn.k; 259 break; 260 case BPF_SUB: 261 state->accumulator -= insn.k; 262 break; 263 case BPF_MUL: 264 state->accumulator *= insn.k; 265 break; 266 case BPF_DIV: 267 if (!insn.k) { 268 *err = "Illegal division by zero"; 269 break; 270 } 271 state->accumulator /= insn.k; 272 break; 273 case BPF_MOD: 274 if (!insn.k) { 275 *err = "Illegal division by zero"; 276 break; 277 } 278 state->accumulator %= insn.k; 279 break; 280 case BPF_OR: 281 state->accumulator |= insn.k; 282 break; 283 case BPF_XOR: 284 state->accumulator ^= insn.k; 285 break; 286 case BPF_AND: 287 state->accumulator &= insn.k; 288 break; 289 case BPF_LSH: 290 if (insn.k > 32) { 291 *err = "Illegal shift operation"; 292 break; 293 } 294 state->accumulator <<= insn.k; 295 break; 296 case BPF_RSH: 297 if (insn.k > 32) { 298 *err = "Illegal shift operation"; 299 break; 300 } 301 state->accumulator >>= insn.k; 302 break; 303 default: 304 *err = "Invalid operator in arithmetic operation"; 305 break; 306 } 307 } 308 } 309 310 } // namespace 311 312 bool Verifier::VerifyBPF(SandboxBPF* sandbox, 313 const std::vector<struct sock_filter>& program, 314 const SandboxBPFPolicy& policy, 315 const char** err) { 316 *err = NULL; 317 for (SyscallIterator iter(false); !iter.Done();) { 318 uint32_t sysnum = iter.Next(); 319 // We ideally want to iterate over the full system call range and values 320 // just above and just below this range. This gives us the full result set 321 // of the "evaluators". 322 // On Intel systems, this can fail in a surprising way, as a cleared bit 30 323 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And 324 // unless we pay attention to setting this bit correctly, an early check in 325 // our BPF program will make us fail with a misleading error code. 326 struct arch_seccomp_data data = {static_cast<int>(sysnum), 327 static_cast<uint32_t>(SECCOMP_ARCH)}; 328 #if defined(__i386__) || defined(__x86_64__) 329 #if defined(__x86_64__) && defined(__ILP32__) 330 if (!(sysnum & 0x40000000u)) { 331 continue; 332 } 333 #else 334 if (sysnum & 0x40000000u) { 335 continue; 336 } 337 #endif 338 #endif 339 ErrorCode code = iter.IsValid(sysnum) 340 ? policy.EvaluateSyscall(sandbox, sysnum) 341 : policy.InvalidSyscall(sandbox); 342 if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) { 343 return false; 344 } 345 } 346 return true; 347 } 348 349 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, 350 const struct arch_seccomp_data& data, 351 const char** err) { 352 *err = NULL; 353 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { 354 *err = "Invalid program length"; 355 return 0; 356 } 357 for (State state(program, data); !*err; ++state.ip) { 358 if (state.ip >= program.size()) { 359 *err = "Invalid instruction pointer in BPF program"; 360 break; 361 } 362 const struct sock_filter& insn = program[state.ip]; 363 switch (BPF_CLASS(insn.code)) { 364 case BPF_LD: 365 Ld(&state, insn, err); 366 break; 367 case BPF_JMP: 368 Jmp(&state, insn, err); 369 break; 370 case BPF_RET: { 371 uint32_t r = Ret(&state, insn, err); 372 switch (r & SECCOMP_RET_ACTION) { 373 case SECCOMP_RET_TRAP: 374 case SECCOMP_RET_ERRNO: 375 case SECCOMP_RET_TRACE: 376 case SECCOMP_RET_ALLOW: 377 break; 378 case SECCOMP_RET_KILL: // We don't ever generate this 379 case SECCOMP_RET_INVALID: // Should never show up in BPF program 380 default: 381 *err = "Unexpected return code found in BPF program"; 382 return 0; 383 } 384 return r; 385 } 386 case BPF_ALU: 387 Alu(&state, insn, err); 388 break; 389 default: 390 *err = "Unexpected instruction in BPF program"; 391 break; 392 } 393 } 394 return 0; 395 } 396 397 } // namespace sandbox 398