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 <string.h> 6 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 8 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 9 #include "sandbox/linux/seccomp-bpf/verifier.h" 10 11 12 namespace { 13 14 using playground2::ErrorCode; 15 using playground2::Sandbox; 16 using playground2::Verifier; 17 using playground2::arch_seccomp_data; 18 19 struct State { 20 State(const std::vector<struct sock_filter>& p, 21 const struct arch_seccomp_data& d) : 22 program(p), 23 data(d), 24 ip(0), 25 accumulator(0), 26 acc_is_valid(false) { 27 } 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(Sandbox *sandbox, const ErrorCode& code, 39 const struct arch_seccomp_data& data) { 40 if (code.error_type() == ErrorCode::ET_SIMPLE || 41 code.error_type() == ErrorCode::ET_TRAP) { 42 return code.err(); 43 } else if (code.error_type() == ErrorCode::ET_COND) { 44 if (code.width() == ErrorCode::TP_32BIT && 45 (data.args[code.argno()] >> 32) && 46 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) != 47 0xFFFFFFFF80000000ull) { 48 return sandbox->Unexpected64bitArgument().err(); 49 } 50 switch (code.op()) { 51 case ErrorCode::OP_EQUAL: 52 return EvaluateErrorCode(sandbox, 53 (code.width() == ErrorCode::TP_32BIT 54 ? uint32_t(data.args[code.argno()]) 55 : data.args[code.argno()]) == code.value() 56 ? *code.passed() 57 : *code.failed(), 58 data); 59 case ErrorCode::OP_HAS_ALL_BITS: 60 return EvaluateErrorCode(sandbox, 61 ((code.width() == ErrorCode::TP_32BIT 62 ? uint32_t(data.args[code.argno()]) 63 : data.args[code.argno()]) & code.value()) 64 == code.value() 65 ? *code.passed() 66 : *code.failed(), 67 data); 68 case ErrorCode::OP_HAS_ANY_BITS: 69 return EvaluateErrorCode(sandbox, 70 (code.width() == ErrorCode::TP_32BIT 71 ? uint32_t(data.args[code.argno()]) 72 : data.args[code.argno()]) & code.value() 73 ? *code.passed() 74 : *code.failed(), 75 data); 76 default: 77 return SECCOMP_RET_INVALID; 78 } 79 } else { 80 return SECCOMP_RET_INVALID; 81 } 82 } 83 84 bool VerifyErrorCode(Sandbox *sandbox, 85 const std::vector<struct sock_filter>& program, 86 struct arch_seccomp_data *data, 87 const ErrorCode& root_code, 88 const ErrorCode& code, 89 const char **err) { 90 if (code.error_type() == ErrorCode::ET_SIMPLE || 91 code.error_type() == ErrorCode::ET_TRAP) { 92 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err); 93 if (*err) { 94 return false; 95 } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) { 96 // For efficiency's sake, we'd much rather compare "computed_ret" 97 // against "code.err()". This works most of the time, but it doesn't 98 // always work for nested conditional expressions. The test values 99 // that we generate on the fly to probe expressions can trigger 100 // code flow decisions in multiple nodes of the decision tree, and the 101 // only way to compute the correct error code in that situation is by 102 // calling EvaluateErrorCode(). 103 *err = "Exit code from BPF program doesn't match"; 104 return false; 105 } 106 } else if (code.error_type() == ErrorCode::ET_COND) { 107 if (code.argno() < 0 || code.argno() >= 6) { 108 *err = "Invalid argument number in error code"; 109 return false; 110 } 111 switch (code.op()) { 112 case ErrorCode::OP_EQUAL: 113 // Verify that we can check a 32bit value (or the LSB of a 64bit value) 114 // for equality. 115 data->args[code.argno()] = code.value(); 116 if (!VerifyErrorCode(sandbox, program, data, root_code, 117 *code.passed(), err)) { 118 return false; 119 } 120 121 // Change the value to no longer match and verify that this is detected 122 // as an inequality. 123 data->args[code.argno()] = code.value() ^ 0x55AA55AA; 124 if (!VerifyErrorCode(sandbox, program, data, root_code, 125 *code.failed(), err)) { 126 return false; 127 } 128 129 // BPF programs can only ever operate on 32bit values. So, we have 130 // generated additional BPF instructions that inspect the MSB. Verify 131 // that they behave as intended. 132 if (code.width() == ErrorCode::TP_32BIT) { 133 if (code.value() >> 32) { 134 SANDBOX_DIE("Invalid comparison of a 32bit system call argument " 135 "against a 64bit constant; this test is always false."); 136 } 137 138 // If the system call argument was intended to be a 32bit parameter, 139 // verify that it is a fatal error if a 64bit value is ever passed 140 // here. 141 data->args[code.argno()] = 0x100000000ull; 142 if (!VerifyErrorCode(sandbox, program, data, root_code, 143 sandbox->Unexpected64bitArgument(), 144 err)) { 145 return false; 146 } 147 } else { 148 // If the system call argument was intended to be a 64bit parameter, 149 // verify that we can handle (in-)equality for the MSB. This is 150 // essentially the same test that we did earlier for the LSB. 151 // We only need to verify the behavior of the inequality test. We 152 // know that the equality test already passed, as unlike the kernel 153 // the Verifier does operate on 64bit quantities. 154 data->args[code.argno()] = code.value() ^ 0x55AA55AA00000000ull; 155 if (!VerifyErrorCode(sandbox, program, data, root_code, 156 *code.failed(), err)) { 157 return false; 158 } 159 } 160 break; 161 case ErrorCode::OP_HAS_ALL_BITS: 162 case ErrorCode::OP_HAS_ANY_BITS: 163 // A comprehensive test of bit values is difficult and potentially rather 164 // time-expensive. We avoid doing so at run-time and instead rely on the 165 // unittest for full testing. The test that we have here covers just the 166 // common cases. We test against the bitmask itself, all zeros and all 167 // ones. 168 { 169 // Testing "any" bits against a zero mask is always false. So, there 170 // are some cases, where we expect tests to take the "failed()" branch 171 // even though this is a test that normally should take "passed()". 172 const ErrorCode& passed = 173 (!code.value() && code.op() == ErrorCode::OP_HAS_ANY_BITS) || 174 175 // On a 32bit system, it is impossible to pass a 64bit value as a 176 // system call argument. So, some additional tests always evaluate 177 // as false. 178 ((code.value() & ~uint64_t(uintptr_t(-1))) && 179 code.op() == ErrorCode::OP_HAS_ALL_BITS) || 180 (code.value() && !(code.value() & uintptr_t(-1)) && 181 code.op() == ErrorCode::OP_HAS_ANY_BITS) 182 183 ? *code.failed() : *code.passed(); 184 185 // Similary, testing for "all" bits in a zero mask is always true. So, 186 // some cases pass despite them normally failing. 187 const ErrorCode& failed = 188 !code.value() && code.op() == ErrorCode::OP_HAS_ALL_BITS 189 ? *code.passed() : *code.failed(); 190 191 data->args[code.argno()] = code.value() & uintptr_t(-1); 192 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) { 193 return false; 194 } 195 data->args[code.argno()] = uintptr_t(-1); 196 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) { 197 return false; 198 } 199 data->args[code.argno()] = 0; 200 if (!VerifyErrorCode(sandbox, program, data, root_code, failed, err)) { 201 return false; 202 } 203 } 204 break; 205 default: // TODO(markus): Need to add support for OP_GREATER 206 *err = "Unsupported operation in conditional error code"; 207 return false; 208 } 209 } else { 210 *err = "Attempting to return invalid error code from BPF program"; 211 return false; 212 } 213 return true; 214 } 215 216 void Ld(State *state, const struct sock_filter& insn, const char **err) { 217 if (BPF_SIZE(insn.code) != BPF_W || 218 BPF_MODE(insn.code) != BPF_ABS) { 219 *err = "Invalid BPF_LD instruction"; 220 return; 221 } 222 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { 223 // We only allow loading of properly aligned 32bit quantities. 224 memcpy(&state->accumulator, 225 reinterpret_cast<const char *>(&state->data) + insn.k, 226 4); 227 } else { 228 *err = "Invalid operand in BPF_LD instruction"; 229 return; 230 } 231 state->acc_is_valid = true; 232 return; 233 } 234 235 void Jmp(State *state, const struct sock_filter& insn, const char **err) { 236 if (BPF_OP(insn.code) == BPF_JA) { 237 if (state->ip + insn.k + 1 >= state->program.size() || 238 state->ip + insn.k + 1 <= state->ip) { 239 compilation_failure: 240 *err = "Invalid BPF_JMP instruction"; 241 return; 242 } 243 state->ip += insn.k; 244 } else { 245 if (BPF_SRC(insn.code) != BPF_K || 246 !state->acc_is_valid || 247 state->ip + insn.jt + 1 >= state->program.size() || 248 state->ip + insn.jf + 1 >= state->program.size()) { 249 goto compilation_failure; 250 } 251 switch (BPF_OP(insn.code)) { 252 case BPF_JEQ: 253 if (state->accumulator == insn.k) { 254 state->ip += insn.jt; 255 } else { 256 state->ip += insn.jf; 257 } 258 break; 259 case BPF_JGT: 260 if (state->accumulator > insn.k) { 261 state->ip += insn.jt; 262 } else { 263 state->ip += insn.jf; 264 } 265 break; 266 case BPF_JGE: 267 if (state->accumulator >= insn.k) { 268 state->ip += insn.jt; 269 } else { 270 state->ip += insn.jf; 271 } 272 break; 273 case BPF_JSET: 274 if (state->accumulator & insn.k) { 275 state->ip += insn.jt; 276 } else { 277 state->ip += insn.jf; 278 } 279 break; 280 default: 281 goto compilation_failure; 282 } 283 } 284 } 285 286 uint32_t Ret(State *, const struct sock_filter& insn, const char **err) { 287 if (BPF_SRC(insn.code) != BPF_K) { 288 *err = "Invalid BPF_RET instruction"; 289 return 0; 290 } 291 return insn.k; 292 } 293 294 void Alu(State *state, const struct sock_filter& insn, const char **err) { 295 if (BPF_OP(insn.code) == BPF_NEG) { 296 state->accumulator = -state->accumulator; 297 return; 298 } else { 299 if (BPF_SRC(insn.code) != BPF_K) { 300 *err = "Unexpected source operand in arithmetic operation"; 301 return; 302 } 303 switch (BPF_OP(insn.code)) { 304 case BPF_ADD: 305 state->accumulator += insn.k; 306 break; 307 case BPF_SUB: 308 state->accumulator -= insn.k; 309 break; 310 case BPF_MUL: 311 state->accumulator *= insn.k; 312 break; 313 case BPF_DIV: 314 if (!insn.k) { 315 *err = "Illegal division by zero"; 316 break; 317 } 318 state->accumulator /= insn.k; 319 break; 320 case BPF_MOD: 321 if (!insn.k) { 322 *err = "Illegal division by zero"; 323 break; 324 } 325 state->accumulator %= insn.k; 326 break; 327 case BPF_OR: 328 state->accumulator |= insn.k; 329 break; 330 case BPF_XOR: 331 state->accumulator ^= insn.k; 332 break; 333 case BPF_AND: 334 state->accumulator &= insn.k; 335 break; 336 case BPF_LSH: 337 if (insn.k > 32) { 338 *err = "Illegal shift operation"; 339 break; 340 } 341 state->accumulator <<= insn.k; 342 break; 343 case BPF_RSH: 344 if (insn.k > 32) { 345 *err = "Illegal shift operation"; 346 break; 347 } 348 state->accumulator >>= insn.k; 349 break; 350 default: 351 *err = "Invalid operator in arithmetic operation"; 352 break; 353 } 354 } 355 } 356 357 } // namespace 358 359 namespace playground2 { 360 361 bool Verifier::VerifyBPF(Sandbox *sandbox, 362 const std::vector<struct sock_filter>& program, 363 const Sandbox::Evaluators& evaluators, 364 const char **err) { 365 *err = NULL; 366 if (evaluators.size() != 1) { 367 *err = "Not implemented"; 368 return false; 369 } 370 Sandbox::EvaluateSyscall evaluate_syscall = evaluators.begin()->first; 371 void *aux = evaluators.begin()->second; 372 for (SyscallIterator iter(false); !iter.Done(); ) { 373 uint32_t sysnum = iter.Next(); 374 // We ideally want to iterate over the full system call range and values 375 // just above and just below this range. This gives us the full result set 376 // of the "evaluators". 377 // On Intel systems, this can fail in a surprising way, as a cleared bit 30 378 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And 379 // unless we pay attention to setting this bit correctly, an early check in 380 // our BPF program will make us fail with a misleading error code. 381 struct arch_seccomp_data data = { static_cast<int>(sysnum), 382 static_cast<uint32_t>(SECCOMP_ARCH) }; 383 #if defined(__i386__) || defined(__x86_64__) 384 #if defined(__x86_64__) && defined(__ILP32__) 385 if (!(sysnum & 0x40000000u)) { 386 continue; 387 } 388 #else 389 if (sysnum & 0x40000000u) { 390 continue; 391 } 392 #endif 393 #endif 394 ErrorCode code = evaluate_syscall(sandbox, sysnum, aux); 395 if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) { 396 return false; 397 } 398 } 399 return true; 400 } 401 402 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, 403 const struct arch_seccomp_data& data, 404 const char **err) { 405 *err = NULL; 406 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { 407 *err = "Invalid program length"; 408 return 0; 409 } 410 for (State state(program, data); !*err; ++state.ip) { 411 if (state.ip >= program.size()) { 412 *err = "Invalid instruction pointer in BPF program"; 413 break; 414 } 415 const struct sock_filter& insn = program[state.ip]; 416 switch (BPF_CLASS(insn.code)) { 417 case BPF_LD: 418 Ld(&state, insn, err); 419 break; 420 case BPF_JMP: 421 Jmp(&state, insn, err); 422 break; 423 case BPF_RET: { 424 uint32_t r = Ret(&state, insn, err); 425 switch (r & SECCOMP_RET_ACTION) { 426 case SECCOMP_RET_TRAP: 427 case SECCOMP_RET_ERRNO: 428 case SECCOMP_RET_ALLOW: 429 break; 430 case SECCOMP_RET_KILL: // We don't ever generate this 431 case SECCOMP_RET_TRACE: // We don't ever generate this 432 case SECCOMP_RET_INVALID: // Should never show up in BPF program 433 default: 434 *err = "Unexpected return code found in BPF program"; 435 return 0; 436 } 437 return r; } 438 case BPF_ALU: 439 Alu(&state, insn, err); 440 break; 441 default: 442 *err = "Unexpected instruction in BPF program"; 443 break; 444 } 445 } 446 return 0; 447 } 448 449 } // namespace 450