| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <time.h> | 5 #include <time.h> |
| 6 | 6 |
| 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 8 #include "sandbox/linux/seccomp-bpf/verifier.h" | 8 #include "sandbox/linux/seccomp-bpf/verifier.h" |
| 9 | 9 |
| 10 // The kernel gives us a sandbox, we turn it into a playground :-) | 10 // The kernel gives us a sandbox, we turn it into a playground :-) |
| 11 // This is version 2 of the playground; version 1 was built on top of | 11 // This is version 2 of the playground; version 1 was built on top of |
| 12 // pre-BPF seccomp mode. | 12 // pre-BPF seccomp mode. |
| 13 namespace playground2 { | 13 namespace playground2 { |
| 14 | 14 |
| 15 // We define a really simple sandbox policy. It is just good enough for us | 15 // We define a really simple sandbox policy. It is just good enough for us |
| 16 // to tell that the sandbox has actually been activated. | 16 // to tell that the sandbox has actually been activated. |
| 17 Sandbox::ErrorCode Sandbox::probeEvaluator(int signo) { | 17 ErrorCode Sandbox::probeEvaluator(int signo) { |
| 18 switch (signo) { | 18 switch (signo) { |
| 19 case __NR_getpid: | 19 case __NR_getpid: |
| 20 // Return EPERM so that we can check that the filter actually ran. | 20 // Return EPERM so that we can check that the filter actually ran. |
| 21 return EPERM; | 21 return ErrorCode(EPERM); |
| 22 case __NR_exit_group: | 22 case __NR_exit_group: |
| 23 // Allow exit() with a non-default return code. | 23 // Allow exit() with a non-default return code. |
| 24 return SB_ALLOWED; | 24 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 25 default: | 25 default: |
| 26 // Make everything else fail in an easily recognizable way. | 26 // Make everything else fail in an easily recognizable way. |
| 27 return EINVAL; | 27 return ErrorCode(EINVAL); |
| 28 } | 28 } |
| 29 } | 29 } |
| 30 | 30 |
| 31 void Sandbox::probeProcess(void) { | 31 void Sandbox::probeProcess(void) { |
| 32 if (syscall(__NR_getpid) < 0 && errno == EPERM) { | 32 if (syscall(__NR_getpid) < 0 && errno == EPERM) { |
| 33 syscall(__NR_exit_group, (intptr_t)100); | 33 syscall(__NR_exit_group, (intptr_t)100); |
| 34 } | 34 } |
| 35 } | 35 } |
| 36 | 36 |
| 37 Sandbox::ErrorCode Sandbox::allowAllEvaluator(int signo) { | 37 ErrorCode Sandbox::allowAllEvaluator(int signo) { |
| 38 if (signo < static_cast<int>(MIN_SYSCALL) || | 38 if (signo < static_cast<int>(MIN_SYSCALL) || |
| 39 signo > static_cast<int>(MAX_SYSCALL)) { | 39 signo > static_cast<int>(MAX_SYSCALL)) { |
| 40 return ENOSYS; | 40 return ErrorCode(ENOSYS); |
| 41 } | 41 } |
| 42 return Sandbox::SB_ALLOWED; | 42 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 43 } | 43 } |
| 44 | 44 |
| 45 void Sandbox::tryVsyscallProcess(void) { | 45 void Sandbox::tryVsyscallProcess(void) { |
| 46 time_t current_time; | 46 time_t current_time; |
| 47 // time() is implemented as a vsyscall. With an older glibc, with | 47 // time() is implemented as a vsyscall. With an older glibc, with |
| 48 // vsyscall=emulate and some versions of the seccomp BPF patch | 48 // vsyscall=emulate and some versions of the seccomp BPF patch |
| 49 // we may get SIGKILL-ed. Detect this! | 49 // we may get SIGKILL-ed. Detect this! |
| 50 if (time(¤t_time) != static_cast<time_t>(-1)) { | 50 if (time(¤t_time) != static_cast<time_t>(-1)) { |
| 51 syscall(__NR_exit_group, (intptr_t)100); | 51 syscall(__NR_exit_group, (intptr_t)100); |
| 52 } | 52 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 } | 136 } |
| 137 if (HANDLE_EINTR(close(fds[0]))) { | 137 if (HANDLE_EINTR(close(fds[0]))) { |
| 138 SANDBOX_DIE("close() failed"); | 138 SANDBOX_DIE("close() failed"); |
| 139 } | 139 } |
| 140 | 140 |
| 141 return rc; | 141 return rc; |
| 142 | 142 |
| 143 } | 143 } |
| 144 | 144 |
| 145 bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { | 145 bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { |
| 146 #if defined(SECCOMP_BPF_VALGRIND_HACKS) |
| 147 if (RUNNING_ON_VALGRIND) { |
| 148 // Valgrind doesn't like our run-time test. Disable testing and assume we |
| 149 // always support sandboxing. This feature should only ever be enabled when |
| 150 // debugging. |
| 151 return true; |
| 152 } |
| 153 #endif |
| 154 |
| 146 return RunFunctionInPolicy(probeProcess, Sandbox::probeEvaluator, proc_fd) && | 155 return RunFunctionInPolicy(probeProcess, Sandbox::probeEvaluator, proc_fd) && |
| 147 RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator, | 156 RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator, |
| 148 proc_fd); | 157 proc_fd); |
| 149 } | 158 } |
| 150 | 159 |
| 151 Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) { | 160 Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) { |
| 152 // It the sandbox is currently active, we clearly must have support for | 161 // It the sandbox is currently active, we clearly must have support for |
| 153 // sandboxing. | 162 // sandboxing. |
| 154 if (status_ == STATUS_ENABLED) { | 163 if (status_ == STATUS_ENABLED) { |
| 155 return status_; | 164 return status_; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 sb.st_nlink != 3 || | 257 sb.st_nlink != 3 || |
| 249 HANDLE_EINTR(close(task))) { | 258 HANDLE_EINTR(close(task))) { |
| 250 if (task >= 0) { | 259 if (task >= 0) { |
| 251 if (HANDLE_EINTR(close(task))) { } | 260 if (HANDLE_EINTR(close(task))) { } |
| 252 } | 261 } |
| 253 return false; | 262 return false; |
| 254 } | 263 } |
| 255 return true; | 264 return true; |
| 256 } | 265 } |
| 257 | 266 |
| 258 static bool isDenied(const Sandbox::ErrorCode& code) { | 267 bool Sandbox::isDenied(const ErrorCode& code) { |
| 259 return (code & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || | 268 return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || |
| 260 (code >= (SECCOMP_RET_ERRNO + 1) && | 269 (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) && |
| 261 code <= (SECCOMP_RET_ERRNO + 4095)); | 270 code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO)); |
| 262 } | 271 } |
| 263 | 272 |
| 264 void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, | 273 void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
| 265 EvaluateArguments) { | 274 EvaluateArguments) { |
| 266 // Do some sanity checks on the policy. This will warn users if they do | 275 // Do some sanity checks on the policy. This will warn users if they do |
| 267 // things that are likely unsafe and unintended. | 276 // things that are likely unsafe and unintended. |
| 268 // We also have similar checks later, when we actually compile the BPF | 277 // We also have similar checks later, when we actually compile the BPF |
| 269 // program. That catches problems with incorrectly stacked evaluators. | 278 // program. That catches problems with incorrectly stacked evaluators. |
| 270 if (!isDenied(syscallEvaluator(-1))) { | 279 if (!isDenied(syscallEvaluator(-1))) { |
| 271 SANDBOX_DIE("Negative system calls should always be disallowed by policy"); | 280 SANDBOX_DIE("Negative system calls should always be disallowed by policy"); |
| 272 } | 281 } |
| 273 #ifndef NDEBUG | 282 #ifndef NDEBUG |
| 274 #if defined(__i386__) || defined(__x86_64__) | 283 #if defined(__i386__) || defined(__x86_64__) |
| 275 #if defined(__x86_64__) && defined(__ILP32__) | 284 #if defined(__x86_64__) && defined(__ILP32__) |
| 276 for (unsigned int sysnum = MIN_SYSCALL & ~0x40000000u; | 285 for (unsigned int sysnum = MIN_SYSCALL & ~0x40000000u; |
| 277 sysnum <= (MAX_SYSCALL & ~0x40000000u); | 286 sysnum <= (MAX_SYSCALL & ~0x40000000u); |
| 278 ++sysnum) { | 287 ++sysnum) { |
| 279 if (!isDenied(syscallEvaluator(sysnum))) { | 288 if (!isDenied(syscallEvaluator(sysnum))) { |
| 280 SANDBOX_DIE("In x32 mode, you should not allow any non-x32 system calls"); | 289 SANDBOX_DIE("In x32 mode, you should not allow any non-x32 " |
| 290 "system calls"); |
| 281 } | 291 } |
| 282 } | 292 } |
| 283 #else | 293 #else |
| 284 for (unsigned int sysnum = MIN_SYSCALL | 0x40000000u; | 294 for (unsigned int sysnum = MIN_SYSCALL | 0x40000000u; |
| 285 sysnum <= (MAX_SYSCALL | 0x40000000u); | 295 sysnum <= (MAX_SYSCALL | 0x40000000u); |
| 286 ++sysnum) { | 296 ++sysnum) { |
| 287 if (!isDenied(syscallEvaluator(sysnum))) { | 297 if (!isDenied(syscallEvaluator(sysnum))) { |
| 288 SANDBOX_DIE("x32 system calls should be explicitly disallowed"); | 298 SANDBOX_DIE("x32 system calls should be explicitly disallowed"); |
| 289 } | 299 } |
| 290 } | 300 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 | 362 |
| 353 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 363 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
| 354 // system call. | 364 // system call. |
| 355 program->push_back((struct sock_filter) | 365 program->push_back((struct sock_filter) |
| 356 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); | 366 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); |
| 357 program->push_back((struct sock_filter) | 367 program->push_back((struct sock_filter) |
| 358 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); | 368 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); |
| 359 | 369 |
| 360 program->push_back((struct sock_filter) | 370 program->push_back((struct sock_filter) |
| 361 BPF_STMT(BPF_RET+BPF_K, | 371 BPF_STMT(BPF_RET+BPF_K, |
| 362 ErrorCode(bpfFailure, | 372 Kill("Invalid audit architecture in BPF filter").err())); |
| 363 "Invalid audit architecture in BPF filter"))); | |
| 364 | 373 |
| 365 // Grab the system call number, so that we can implement jump tables. | 374 // Grab the system call number, so that we can implement jump tables. |
| 366 program->push_back((struct sock_filter) | 375 program->push_back((struct sock_filter) |
| 367 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); | 376 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); |
| 368 | 377 |
| 369 // On Intel architectures, verify that system call numbers are in the | 378 // On Intel architectures, verify that system call numbers are in the |
| 370 // expected number range. The older i386 and x86-64 APIs clear bit 30 | 379 // expected number range. The older i386 and x86-64 APIs clear bit 30 |
| 371 // on all system calls. The newer x86-32 API always sets bit 30. | 380 // on all system calls. The newer x86-32 API always sets bit 30. |
| 372 #if defined(__i386__) || defined(__x86_64__) | 381 #if defined(__i386__) || defined(__x86_64__) |
| 373 #if defined(__x86_64__) && defined(__ILP32__) | 382 #if defined(__x86_64__) && defined(__ILP32__) |
| 374 program->push_back((struct sock_filter) | 383 program->push_back((struct sock_filter) |
| 375 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); | 384 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); |
| 376 #else | 385 #else |
| 377 program->push_back((struct sock_filter) | 386 program->push_back((struct sock_filter) |
| 378 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); | 387 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); |
| 379 #endif | 388 #endif |
| 380 program->push_back((struct sock_filter) | 389 program->push_back((struct sock_filter) |
| 381 BPF_STMT(BPF_RET+BPF_K, | 390 BPF_STMT(BPF_RET+BPF_K, |
| 382 ErrorCode(bpfFailure, | 391 Kill("Illegal mixing of system call ABIs").err())); |
| 383 "Illegal mixing of system call ABIs"))); | |
| 384 #endif | 392 #endif |
| 385 | 393 |
| 386 | 394 |
| 387 { | 395 { |
| 388 // Evaluate all possible system calls and group their ErrorCodes into | 396 // Evaluate all possible system calls and group their ErrorCodes into |
| 389 // ranges of identical codes. | 397 // ranges of identical codes. |
| 390 Ranges ranges; | 398 Ranges ranges; |
| 391 findRanges(&ranges); | 399 findRanges(&ranges); |
| 392 | 400 |
| 393 // Compile the system call ranges to an optimized BPF program | 401 // Compile the system call ranges to an optimized BPF program |
| (...skipping 24 matching lines...) Expand all Loading... |
| 418 // system memory allocator that is in effect, these operators can result | 426 // system memory allocator that is in effect, these operators can result |
| 419 // in system calls to things like munmap() or brk(). | 427 // in system calls to things like munmap() or brk(). |
| 420 struct sock_filter bpf[program->size()]; | 428 struct sock_filter bpf[program->size()]; |
| 421 const struct sock_fprog prog = { | 429 const struct sock_fprog prog = { |
| 422 static_cast<unsigned short>(program->size()), bpf }; | 430 static_cast<unsigned short>(program->size()), bpf }; |
| 423 memcpy(bpf, &(*program)[0], sizeof(bpf)); | 431 memcpy(bpf, &(*program)[0], sizeof(bpf)); |
| 424 delete program; | 432 delete program; |
| 425 | 433 |
| 426 // Release memory that is no longer needed | 434 // Release memory that is no longer needed |
| 427 evaluators_.clear(); | 435 evaluators_.clear(); |
| 436 errMap_.clear(); |
| 428 | 437 |
| 429 // Install BPF filter program | 438 #if defined(SECCOMP_BPF_VALGRIND_HACKS) |
| 430 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | 439 // Valgrind is really not happy about our sandbox. Disable it when running |
| 431 SANDBOX_DIE(quiet | 440 // in Valgrind. This feature is dangerous and should never be enabled by |
| 432 ? NULL : "Kernel refuses to enable no-new-privs"); | 441 // default. We protect it behind a pre-processor option. |
| 433 } else { | 442 if (!RUNNING_ON_VALGRIND) |
| 434 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 443 #endif |
| 435 SANDBOX_DIE(quiet | 444 { |
| 436 ? NULL : "Kernel refuses to turn on BPF filters"); | 445 // Install BPF filter program |
| 446 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
| 447 SANDBOX_DIE(quiet ? NULL : "Kernel refuses to enable no-new-privs"); |
| 448 } else { |
| 449 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
| 450 SANDBOX_DIE(quiet ? NULL : "Kernel refuses to turn on BPF filters"); |
| 451 } |
| 437 } | 452 } |
| 438 } | 453 } |
| 439 | 454 |
| 440 return; | 455 return; |
| 441 } | 456 } |
| 442 | 457 |
| 443 void Sandbox::findRanges(Ranges *ranges) { | 458 void Sandbox::findRanges(Ranges *ranges) { |
| 444 // Please note that "struct seccomp_data" defines system calls as a signed | 459 // Please note that "struct seccomp_data" defines system calls as a signed |
| 445 // int32_t, but BPF instructions always operate on unsigned quantities. We | 460 // int32_t, but BPF instructions always operate on unsigned quantities. We |
| 446 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, | 461 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, |
| 447 // and then verifying that the rest of the number range (both positive and | 462 // and then verifying that the rest of the number range (both positive and |
| 448 // negative) all return the same ErrorCode. | 463 // negative) all return the same ErrorCode. |
| 449 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; | 464 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; |
| 450 uint32_t oldSysnum = 0; | 465 uint32_t oldSysnum = 0; |
| 451 ErrorCode oldErr = evaluateSyscall(oldSysnum); | 466 ErrorCode oldErr = evaluateSyscall(oldSysnum); |
| 452 for (uint32_t sysnum = std::max(1u, MIN_SYSCALL); | 467 for (uint32_t sysnum = std::max(1u, MIN_SYSCALL); |
| 453 sysnum <= MAX_SYSCALL + 1; | 468 sysnum <= MAX_SYSCALL + 1; |
| 454 ++sysnum) { | 469 ++sysnum) { |
| 455 ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); | 470 ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); |
| 456 if (err != oldErr) { | 471 if (!err.Equals(oldErr)) { |
| 457 ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); | 472 ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); |
| 458 oldSysnum = sysnum; | 473 oldSysnum = sysnum; |
| 459 oldErr = err; | 474 oldErr = err; |
| 460 } | 475 } |
| 461 } | 476 } |
| 462 | 477 |
| 463 // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1), | 478 // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1), |
| 464 // "oldErr" should at this point be the "default" policy for all system call | 479 // "oldErr" should at this point be the "default" policy for all system call |
| 465 // numbers that don't have an explicit handler in the system call evaluator. | 480 // numbers that don't have an explicit handler in the system call evaluator. |
| 466 // But as we are quite paranoid, we perform some more sanity checks to verify | 481 // But as we are quite paranoid, we perform some more sanity checks to verify |
| 467 // that there actually is a consistent "default" policy in the first place. | 482 // that there actually is a consistent "default" policy in the first place. |
| 468 // We don't actually iterate over all possible 2^32 values, though. We just | 483 // We don't actually iterate over all possible 2^32 values, though. We just |
| 469 // perform spot checks at the boundaries. | 484 // perform spot checks at the boundaries. |
| 470 // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF. | 485 // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF. |
| 471 if (oldErr != evaluateSyscall(std::numeric_limits<int>::max()) || | 486 if (!oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::max())) || |
| 472 oldErr != evaluateSyscall(std::numeric_limits<int>::min()) || | 487 !oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::min())) || |
| 473 oldErr != evaluateSyscall(-1)) { | 488 !oldErr.Equals(evaluateSyscall(-1))) { |
| 474 SANDBOX_DIE("Invalid seccomp policy"); | 489 SANDBOX_DIE("Invalid seccomp policy"); |
| 475 } | 490 } |
| 476 ranges->push_back( | 491 ranges->push_back( |
| 477 Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); | 492 Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); |
| 478 } | 493 } |
| 479 | 494 |
| 480 void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, | 495 void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, |
| 481 Ranges::const_iterator start, | 496 Ranges::const_iterator start, |
| 482 Ranges::const_iterator stop) { | 497 Ranges::const_iterator stop) { |
| 483 // We convert the list of system call ranges into jump table that performs | 498 // We convert the list of system call ranges into jump table that performs |
| (...skipping 23 matching lines...) Expand all Loading... |
| 507 // less than the range object at the mid point of the list. | 522 // less than the range object at the mid point of the list. |
| 508 if (mid - start == 1) { | 523 if (mid - start == 1) { |
| 509 // If we have narrowed things down to a single range object, we can | 524 // If we have narrowed things down to a single range object, we can |
| 510 // return from the BPF filter program. | 525 // return from the BPF filter program. |
| 511 // Instead of emitting a BPF_RET statement, we want to coalesce all | 526 // Instead of emitting a BPF_RET statement, we want to coalesce all |
| 512 // identical BPF_RET statements into a single instance. This results in | 527 // identical BPF_RET statements into a single instance. This results in |
| 513 // a more efficient BPF program that uses less CPU cache. | 528 // a more efficient BPF program that uses less CPU cache. |
| 514 // Since all branches in BPF programs have to be forward branches, we | 529 // Since all branches in BPF programs have to be forward branches, we |
| 515 // keep track of our current instruction pointer and then fix up the | 530 // keep track of our current instruction pointer and then fix up the |
| 516 // branch when we emit the BPF_RET statement in emitReturnStatements(). | 531 // branch when we emit the BPF_RET statement in emitReturnStatements(). |
| 517 (*rets)[start->err].push_back(FixUp(jmp, false)); | 532 (*rets)[start->err.err()].push_back(FixUp(jmp, false)); |
| 518 } else { | 533 } else { |
| 519 // Sub-divide the list of ranges and continue recursively. | 534 // Sub-divide the list of ranges and continue recursively. |
| 520 emitJumpStatements(program, rets, start, mid); | 535 emitJumpStatements(program, rets, start, mid); |
| 521 } | 536 } |
| 522 | 537 |
| 523 // The comparison turned out to be true; i.e. our system call number is | 538 // The comparison turned out to be true; i.e. our system call number is |
| 524 // greater or equal to the range object at the mid point of the list. | 539 // greater or equal to the range object at the mid point of the list. |
| 525 if (stop - mid == 1) { | 540 if (stop - mid == 1) { |
| 526 // We narrowed things down to a single range object. Remember instruction | 541 // We narrowed things down to a single range object. Remember instruction |
| 527 // pointer and exit code, so that we can patch up the target of the jump | 542 // pointer and exit code, so that we can patch up the target of the jump |
| 528 // instruction in emitReturnStatements(). | 543 // instruction in emitReturnStatements(). |
| 529 (*rets)[mid->err].push_back(FixUp(jmp, true)); | 544 (*rets)[mid->err.err()].push_back(FixUp(jmp, true)); |
| 530 } else { | 545 } else { |
| 531 // We now know where the block of instructions for the "true" comparison | 546 // We now know where the block of instructions for the "true" comparison |
| 532 // starts. Patch up the jump target of the BPF_JMP instruction that we | 547 // starts. Patch up the jump target of the BPF_JMP instruction that we |
| 533 // emitted earlier. | 548 // emitted earlier. |
| 534 int distance = program->size() - jmp - 1; | 549 int distance = program->size() - jmp - 1; |
| 535 if (distance < 0 || distance > 255) { | 550 if (distance < 0 || distance > 255) { |
| 536 goto compiler_err; | 551 goto compiler_err; |
| 537 } | 552 } |
| 538 (*program)[jmp].jt = distance; | 553 (*program)[jmp].jt = distance; |
| 539 | 554 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 } | 592 } |
| 578 } | 593 } |
| 579 | 594 |
| 580 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { | 595 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { |
| 581 // Various sanity checks to make sure we actually received a signal | 596 // Various sanity checks to make sure we actually received a signal |
| 582 // triggered by a BPF filter. If something else triggered SIGSYS | 597 // triggered by a BPF filter. If something else triggered SIGSYS |
| 583 // (e.g. kill()), there is really nothing we can do with this signal. | 598 // (e.g. kill()), there is really nothing we can do with this signal. |
| 584 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context || | 599 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context || |
| 585 info->si_errno <= 0 || | 600 info->si_errno <= 0 || |
| 586 static_cast<size_t>(info->si_errno) > trapArraySize_) { | 601 static_cast<size_t>(info->si_errno) > trapArraySize_) { |
| 587 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal safe | 602 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal |
| 588 // and can lead to bugs. We should eventually implement a different | 603 // safe and can lead to bugs. We should eventually implement a different |
| 589 // logging and reporting mechanism that is safe to be called from | 604 // logging and reporting mechanism that is safe to be called from |
| 590 // the sigSys() handler. | 605 // the sigSys() handler. |
| 591 // TODO: If we feel confident that our code otherwise works correctly, we | 606 // TODO: If we feel confident that our code otherwise works correctly, we |
| 592 // could actually make an argument that spurious SIGSYS should | 607 // could actually make an argument that spurious SIGSYS should |
| 593 // just get silently ignored. TBD | 608 // just get silently ignored. TBD |
| 594 sigsys_err: | 609 sigsys_err: |
| 595 SANDBOX_DIE("Unexpected SIGSYS received"); | 610 SANDBOX_DIE("Unexpected SIGSYS received"); |
| 596 } | 611 } |
| 597 | 612 |
| 598 // Signal handlers should always preserve "errno". Otherwise, we could | 613 // Signal handlers should always preserve "errno". Otherwise, we could |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 | 655 |
| 641 // Update the CPU register that stores the return code of the system call | 656 // Update the CPU register that stores the return code of the system call |
| 642 // that we just handled, and restore "errno" to the value that it had | 657 // that we just handled, and restore "errno" to the value that it had |
| 643 // before entering the signal handler. | 658 // before entering the signal handler. |
| 644 SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc); | 659 SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc); |
| 645 errno = old_errno; | 660 errno = old_errno; |
| 646 | 661 |
| 647 return; | 662 return; |
| 648 } | 663 } |
| 649 | 664 |
| 650 intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { | 665 ErrorCode Sandbox::Trap(ErrorCode::TrapFnc fnc, const void *aux) { |
| 651 SANDBOX_DIE(static_cast<char *>(aux)); | |
| 652 } | |
| 653 | |
| 654 int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { | |
| 655 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance | 666 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance |
| 656 // of a SECCOMP_RET_TRAP. | 667 // of a SECCOMP_RET_TRAP. |
| 657 std::pair<TrapFnc, const void *> key(fnc, aux); | 668 std::pair<ErrorCode::TrapFnc, const void *> key(fnc, aux); |
| 658 TrapIds::const_iterator iter = trapIds_.find(key); | 669 TrapIds::const_iterator iter = trapIds_.find(key); |
| 670 uint16_t id; |
| 659 if (iter != trapIds_.end()) { | 671 if (iter != trapIds_.end()) { |
| 660 // We have seen this pair before. Return the same id that we assigned | 672 // We have seen this pair before. Return the same id that we assigned |
| 661 // earlier. | 673 // earlier. |
| 662 return iter->second; | 674 id = iter->second; |
| 663 } else { | 675 } else { |
| 664 // This is a new pair. Remember it and assign a new id. | 676 // This is a new pair. Remember it and assign a new id. |
| 665 // Please note that we have to store traps in memory that doesn't get | 677 // Please note that we have to store traps in memory that doesn't get |
| 666 // deallocated when the program is shutting down. A memory leak is | 678 // deallocated when the program is shutting down. A memory leak is |
| 667 // intentional, because we might otherwise not be able to execute | 679 // intentional, because we might otherwise not be able to execute |
| 668 // system calls part way through the program shutting down | 680 // system calls part way through the program shutting down |
| 669 if (!traps_) { | 681 if (!traps_) { |
| 670 traps_ = new Traps(); | 682 traps_ = new Traps(); |
| 671 } | 683 } |
| 672 Traps::size_type id = traps_->size() + 1; | 684 if (traps_->size() >= SECCOMP_RET_DATA) { |
| 673 if (id > SECCOMP_RET_DATA) { | |
| 674 // In practice, this is pretty much impossible to trigger, as there | 685 // In practice, this is pretty much impossible to trigger, as there |
| 675 // are other kernel limitations that restrict overall BPF program sizes. | 686 // are other kernel limitations that restrict overall BPF program sizes. |
| 676 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); | 687 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); |
| 677 } | 688 } |
| 689 id = traps_->size() + 1; |
| 678 | 690 |
| 679 traps_->push_back(ErrorCode(fnc, aux, id)); | 691 traps_->push_back(ErrorCode(fnc, aux, id)); |
| 680 trapIds_[key] = id; | 692 trapIds_[key] = id; |
| 681 | 693 |
| 682 // We want to access the traps_ vector from our signal handler. But | 694 // We want to access the traps_ vector from our signal handler. But |
| 683 // we are not assured that doing so is async-signal safe. On the other | 695 // we are not assured that doing so is async-signal safe. On the other |
| 684 // hand, C++ guarantees that the contents of a vector is stored in a | 696 // hand, C++ guarantees that the contents of a vector is stored in a |
| 685 // contiguous C-style array. | 697 // contiguous C-style array. |
| 686 // So, we look up the address and size of this array outside of the | 698 // So, we look up the address and size of this array outside of the |
| 687 // signal handler, where we can safely do so. | 699 // signal handler, where we can safely do so. |
| 688 trapArray_ = &(*traps_)[0]; | 700 trapArray_ = &(*traps_)[0]; |
| 689 trapArraySize_ = id; | 701 trapArraySize_ = id; |
| 690 return id; | |
| 691 } | 702 } |
| 703 |
| 704 ErrorCode err = ErrorCode(fnc, aux, id); |
| 705 return errMap_[err.err()] = err; |
| 706 } |
| 707 |
| 708 intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { |
| 709 SANDBOX_DIE(static_cast<char *>(aux)); |
| 710 } |
| 711 |
| 712 ErrorCode Sandbox::Kill(const char *msg) { |
| 713 return Trap(bpfFailure, const_cast<char *>(msg)); |
| 692 } | 714 } |
| 693 | 715 |
| 694 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 716 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
| 695 int Sandbox::proc_fd_ = -1; | 717 int Sandbox::proc_fd_ = -1; |
| 696 Sandbox::Evaluators Sandbox::evaluators_; | 718 Sandbox::Evaluators Sandbox::evaluators_; |
| 719 Sandbox::ErrMap Sandbox::errMap_; |
| 697 Sandbox::Traps *Sandbox::traps_ = NULL; | 720 Sandbox::Traps *Sandbox::traps_ = NULL; |
| 698 Sandbox::TrapIds Sandbox::trapIds_; | 721 Sandbox::TrapIds Sandbox::trapIds_; |
| 699 Sandbox::ErrorCode *Sandbox::trapArray_ = NULL; | 722 ErrorCode *Sandbox::trapArray_ = NULL; |
| 700 size_t Sandbox::trapArraySize_ = 0; | 723 size_t Sandbox::trapArraySize_ = 0; |
| 701 | 724 |
| 702 } // namespace | 725 } // namespace |
| OLD | NEW |