| 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 } | 131 } |
| 132 if (HANDLE_EINTR(close(fds[0]))) { | 132 if (HANDLE_EINTR(close(fds[0]))) { |
| 133 die("close() failed"); | 133 die("close() failed"); |
| 134 } | 134 } |
| 135 | 135 |
| 136 return rc; | 136 return rc; |
| 137 | 137 |
| 138 } | 138 } |
| 139 | 139 |
| 140 bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { | 140 bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { |
| 141 #ifdef SECCOMP_BPF_VALGRIND_HACKS |
| 142 if (RUNNING_ON_VALGRIND) { |
| 143 // Valgrind doesn't like our run-time test. Disable testing and assume we |
| 144 // always support sandboxing. This feature should only ever be enabled when |
| 145 // debugging. |
| 146 return true; |
| 147 } |
| 148 #endif |
| 149 |
| 141 return RunFunctionInPolicy(probeProcess, Sandbox::probeEvaluator, proc_fd) && | 150 return RunFunctionInPolicy(probeProcess, Sandbox::probeEvaluator, proc_fd) && |
| 142 RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator, | 151 RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator, |
| 143 proc_fd); | 152 proc_fd); |
| 144 } | 153 } |
| 145 | 154 |
| 146 Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) { | 155 Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) { |
| 147 // It the sandbox is currently active, we clearly must have support for | 156 // It the sandbox is currently active, we clearly must have support for |
| 148 // sandboxing. | 157 // sandboxing. |
| 149 if (status_ == STATUS_ENABLED) { | 158 if (status_ == STATUS_ENABLED) { |
| 150 return status_; | 159 return status_; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 sb.st_nlink != 3 || | 251 sb.st_nlink != 3 || |
| 243 HANDLE_EINTR(close(task))) { | 252 HANDLE_EINTR(close(task))) { |
| 244 if (task >= 0) { | 253 if (task >= 0) { |
| 245 if (HANDLE_EINTR(close(task))) { } | 254 if (HANDLE_EINTR(close(task))) { } |
| 246 } | 255 } |
| 247 return false; | 256 return false; |
| 248 } | 257 } |
| 249 return true; | 258 return true; |
| 250 } | 259 } |
| 251 | 260 |
| 252 static bool isDenied(const Sandbox::ErrorCode& code) { | 261 bool Sandbox::isDenied(const ErrorCode& code) { |
| 253 return (code & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || | 262 return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || |
| 254 (code >= (SECCOMP_RET_ERRNO + 1) && | 263 (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) && |
| 255 code <= (SECCOMP_RET_ERRNO + 4095)); | 264 code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO)); |
| 256 } | 265 } |
| 257 | 266 |
| 258 void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, | 267 void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
| 259 EvaluateArguments) { | 268 EvaluateArguments) { |
| 260 // Do some sanity checks on the policy. This will warn users if they do | 269 // Do some sanity checks on the policy. This will warn users if they do |
| 261 // things that are likely unsafe and unintended. | 270 // things that are likely unsafe and unintended. |
| 262 // We also have similar checks later, when we actually compile the BPF | 271 // We also have similar checks later, when we actually compile the BPF |
| 263 // program. That catches problems with incorrectly stacked evaluators. | 272 // program. That catches problems with incorrectly stacked evaluators. |
| 264 if (!isDenied(syscallEvaluator(-1))) { | 273 if (!isDenied(syscallEvaluator(-1))) { |
| 265 die("Negative system calls should always be disallowed by policy"); | 274 die("Negative system calls should always be disallowed by policy"); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 | 355 |
| 347 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 356 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
| 348 // system call. | 357 // system call. |
| 349 program->push_back((struct sock_filter) | 358 program->push_back((struct sock_filter) |
| 350 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); | 359 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); |
| 351 program->push_back((struct sock_filter) | 360 program->push_back((struct sock_filter) |
| 352 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); | 361 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); |
| 353 | 362 |
| 354 program->push_back((struct sock_filter) | 363 program->push_back((struct sock_filter) |
| 355 BPF_STMT(BPF_RET+BPF_K, | 364 BPF_STMT(BPF_RET+BPF_K, |
| 356 ErrorCode(bpfFailure, | 365 Kill("Invalid audit architecture in BPF filter").err())); |
| 357 "Invalid audit architecture in BPF filter"))); | |
| 358 | 366 |
| 359 // Grab the system call number, so that we can implement jump tables. | 367 // Grab the system call number, so that we can implement jump tables. |
| 360 program->push_back((struct sock_filter) | 368 program->push_back((struct sock_filter) |
| 361 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); | 369 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); |
| 362 | 370 |
| 363 // On Intel architectures, verify that system call numbers are in the | 371 // On Intel architectures, verify that system call numbers are in the |
| 364 // expected number range. The older i386 and x86-64 APIs clear bit 30 | 372 // expected number range. The older i386 and x86-64 APIs clear bit 30 |
| 365 // on all system calls. The newer x86-32 API always sets bit 30. | 373 // on all system calls. The newer x86-32 API always sets bit 30. |
| 366 #if defined(__i386__) || defined(__x86_64__) | 374 #if defined(__i386__) || defined(__x86_64__) |
| 367 #if defined(__x86_64__) && defined(__ILP32__) | 375 #if defined(__x86_64__) && defined(__ILP32__) |
| 368 program->push_back((struct sock_filter) | 376 program->push_back((struct sock_filter) |
| 369 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); | 377 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); |
| 370 #else | 378 #else |
| 371 program->push_back((struct sock_filter) | 379 program->push_back((struct sock_filter) |
| 372 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); | 380 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); |
| 373 #endif | 381 #endif |
| 374 program->push_back((struct sock_filter) | 382 program->push_back((struct sock_filter) |
| 375 BPF_STMT(BPF_RET+BPF_K, | 383 BPF_STMT(BPF_RET+BPF_K, |
| 376 ErrorCode(bpfFailure, | 384 Kill("Illegal mixing of system call ABIs").err())); |
| 377 "Illegal mixing of system call ABIs"))); | |
| 378 #endif | 385 #endif |
| 379 | 386 |
| 380 | 387 |
| 381 { | 388 { |
| 382 // Evaluate all possible system calls and group their ErrorCodes into | 389 // Evaluate all possible system calls and group their ErrorCodes into |
| 383 // ranges of identical codes. | 390 // ranges of identical codes. |
| 384 Ranges ranges; | 391 Ranges ranges; |
| 385 findRanges(&ranges); | 392 findRanges(&ranges); |
| 386 | 393 |
| 387 // Compile the system call ranges to an optimized BPF program | 394 // Compile the system call ranges to an optimized BPF program |
| (...skipping 24 matching lines...) Expand all Loading... |
| 412 // system memory allocator that is in effect, these operators can result | 419 // system memory allocator that is in effect, these operators can result |
| 413 // in system calls to things like munmap() or brk(). | 420 // in system calls to things like munmap() or brk(). |
| 414 struct sock_filter bpf[program->size()]; | 421 struct sock_filter bpf[program->size()]; |
| 415 const struct sock_fprog prog = { | 422 const struct sock_fprog prog = { |
| 416 static_cast<unsigned short>(program->size()), bpf }; | 423 static_cast<unsigned short>(program->size()), bpf }; |
| 417 memcpy(bpf, &(*program)[0], sizeof(bpf)); | 424 memcpy(bpf, &(*program)[0], sizeof(bpf)); |
| 418 delete program; | 425 delete program; |
| 419 | 426 |
| 420 // Release memory that is no longer needed | 427 // Release memory that is no longer needed |
| 421 evaluators_.clear(); | 428 evaluators_.clear(); |
| 429 errMap_.clear(); |
| 422 | 430 |
| 423 // Install BPF filter program | 431 #ifdef SECCOMP_BPF_VALGRIND_HACKS |
| 424 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | 432 // Valgrind is really not happy about our sandbox. Disable it when running |
| 425 die(dryRun_ ? NULL : "Kernel refuses to enable no-new-privs"); | 433 // in Valgrind. This feature is dangerous and should never be enabled by |
| 426 } else { | 434 // default. We protect it behind a pre-processor option. |
| 427 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 435 if (!RUNNING_ON_VALGRIND) |
| 428 die(dryRun_ ? NULL : "Kernel refuses to turn on BPF filters"); | 436 #endif |
| 437 { |
| 438 // Install BPF filter program |
| 439 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
| 440 die(dryRun_ ? NULL : "Kernel refuses to enable no-new-privs"); |
| 441 } else { |
| 442 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
| 443 die(dryRun_ ? NULL : "Kernel refuses to turn on BPF filters"); |
| 444 } |
| 429 } | 445 } |
| 430 } | 446 } |
| 431 | 447 |
| 432 return; | 448 return; |
| 433 } | 449 } |
| 434 | 450 |
| 435 void Sandbox::findRanges(Ranges *ranges) { | 451 void Sandbox::findRanges(Ranges *ranges) { |
| 436 // Please note that "struct seccomp_data" defines system calls as a signed | 452 // Please note that "struct seccomp_data" defines system calls as a signed |
| 437 // int32_t, but BPF instructions always operate on unsigned quantities. We | 453 // int32_t, but BPF instructions always operate on unsigned quantities. We |
| 438 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, | 454 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, |
| 439 // and then verifying that the rest of the number range (both positive and | 455 // and then verifying that the rest of the number range (both positive and |
| 440 // negative) all return the same ErrorCode. | 456 // negative) all return the same ErrorCode. |
| 441 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; | 457 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; |
| 442 uint32_t oldSysnum = 0; | 458 uint32_t oldSysnum = 0; |
| 443 ErrorCode oldErr = evaluateSyscall(oldSysnum); | 459 ErrorCode oldErr = evaluateSyscall(oldSysnum); |
| 444 for (uint32_t sysnum = std::max(1u, MIN_SYSCALL); | 460 for (uint32_t sysnum = std::max(1u, MIN_SYSCALL); |
| 445 sysnum <= MAX_SYSCALL + 1; | 461 sysnum <= MAX_SYSCALL + 1; |
| 446 ++sysnum) { | 462 ++sysnum) { |
| 447 ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); | 463 ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); |
| 448 if (err != oldErr) { | 464 if (!err.Equals(oldErr)) { |
| 449 ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); | 465 ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); |
| 450 oldSysnum = sysnum; | 466 oldSysnum = sysnum; |
| 451 oldErr = err; | 467 oldErr = err; |
| 452 } | 468 } |
| 453 } | 469 } |
| 454 | 470 |
| 455 // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1), | 471 // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1), |
| 456 // "oldErr" should at this point be the "default" policy for all system call | 472 // "oldErr" should at this point be the "default" policy for all system call |
| 457 // numbers that don't have an explicit handler in the system call evaluator. | 473 // numbers that don't have an explicit handler in the system call evaluator. |
| 458 // But as we are quite paranoid, we perform some more sanity checks to verify | 474 // But as we are quite paranoid, we perform some more sanity checks to verify |
| 459 // that there actually is a consistent "default" policy in the first place. | 475 // that there actually is a consistent "default" policy in the first place. |
| 460 // We don't actually iterate over all possible 2^32 values, though. We just | 476 // We don't actually iterate over all possible 2^32 values, though. We just |
| 461 // perform spot checks at the boundaries. | 477 // perform spot checks at the boundaries. |
| 462 // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF. | 478 // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF. |
| 463 if (oldErr != evaluateSyscall(std::numeric_limits<int>::max()) || | 479 if (!oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::max())) || |
| 464 oldErr != evaluateSyscall(std::numeric_limits<int>::min()) || | 480 !oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::min())) || |
| 465 oldErr != evaluateSyscall(-1)) { | 481 !oldErr.Equals(evaluateSyscall(-1))) { |
| 466 die("Invalid seccomp policy"); | 482 die("Invalid seccomp policy"); |
| 467 } | 483 } |
| 468 ranges->push_back( | 484 ranges->push_back( |
| 469 Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); | 485 Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); |
| 470 } | 486 } |
| 471 | 487 |
| 472 void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, | 488 void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, |
| 473 Ranges::const_iterator start, | 489 Ranges::const_iterator start, |
| 474 Ranges::const_iterator stop) { | 490 Ranges::const_iterator stop) { |
| 475 // We convert the list of system call ranges into jump table that performs | 491 // We convert the list of system call ranges into jump table that performs |
| (...skipping 23 matching lines...) Expand all Loading... |
| 499 // less than the range object at the mid point of the list. | 515 // less than the range object at the mid point of the list. |
| 500 if (mid - start == 1) { | 516 if (mid - start == 1) { |
| 501 // If we have narrowed things down to a single range object, we can | 517 // If we have narrowed things down to a single range object, we can |
| 502 // return from the BPF filter program. | 518 // return from the BPF filter program. |
| 503 // Instead of emitting a BPF_RET statement, we want to coalesce all | 519 // Instead of emitting a BPF_RET statement, we want to coalesce all |
| 504 // identical BPF_RET statements into a single instance. This results in | 520 // identical BPF_RET statements into a single instance. This results in |
| 505 // a more efficient BPF program that uses less CPU cache. | 521 // a more efficient BPF program that uses less CPU cache. |
| 506 // Since all branches in BPF programs have to be forward branches, we | 522 // Since all branches in BPF programs have to be forward branches, we |
| 507 // keep track of our current instruction pointer and then fix up the | 523 // keep track of our current instruction pointer and then fix up the |
| 508 // branch when we emit the BPF_RET statement in emitReturnStatements(). | 524 // branch when we emit the BPF_RET statement in emitReturnStatements(). |
| 509 (*rets)[start->err].push_back(FixUp(jmp, false)); | 525 (*rets)[start->err.err()].push_back(FixUp(jmp, false)); |
| 510 } else { | 526 } else { |
| 511 // Sub-divide the list of ranges and continue recursively. | 527 // Sub-divide the list of ranges and continue recursively. |
| 512 emitJumpStatements(program, rets, start, mid); | 528 emitJumpStatements(program, rets, start, mid); |
| 513 } | 529 } |
| 514 | 530 |
| 515 // The comparison turned out to be true; i.e. our system call number is | 531 // The comparison turned out to be true; i.e. our system call number is |
| 516 // greater or equal to the range object at the mid point of the list. | 532 // greater or equal to the range object at the mid point of the list. |
| 517 if (stop - mid == 1) { | 533 if (stop - mid == 1) { |
| 518 // We narrowed things down to a single range object. Remember instruction | 534 // We narrowed things down to a single range object. Remember instruction |
| 519 // pointer and exit code, so that we can patch up the target of the jump | 535 // pointer and exit code, so that we can patch up the target of the jump |
| 520 // instruction in emitReturnStatements(). | 536 // instruction in emitReturnStatements(). |
| 521 (*rets)[mid->err].push_back(FixUp(jmp, true)); | 537 (*rets)[mid->err.err()].push_back(FixUp(jmp, true)); |
| 522 } else { | 538 } else { |
| 523 // We now know where the block of instructions for the "true" comparison | 539 // We now know where the block of instructions for the "true" comparison |
| 524 // starts. Patch up the jump target of the BPF_JMP instruction that we | 540 // starts. Patch up the jump target of the BPF_JMP instruction that we |
| 525 // emitted earlier. | 541 // emitted earlier. |
| 526 int distance = program->size() - jmp - 1; | 542 int distance = program->size() - jmp - 1; |
| 527 if (distance < 0 || distance > 255) { | 543 if (distance < 0 || distance > 255) { |
| 528 goto compiler_err; | 544 goto compiler_err; |
| 529 } | 545 } |
| 530 (*program)[jmp].jt = distance; | 546 (*program)[jmp].jt = distance; |
| 531 | 547 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 | 648 |
| 633 // Update the CPU register that stores the return code of the system call | 649 // Update the CPU register that stores the return code of the system call |
| 634 // that we just handled, and restore "errno" to the value that it had | 650 // that we just handled, and restore "errno" to the value that it had |
| 635 // before entering the signal handler. | 651 // before entering the signal handler. |
| 636 ctx->uc_mcontext.gregs[REG_RESULT] = static_cast<greg_t>(rc); | 652 ctx->uc_mcontext.gregs[REG_RESULT] = static_cast<greg_t>(rc); |
| 637 errno = old_errno; | 653 errno = old_errno; |
| 638 | 654 |
| 639 return; | 655 return; |
| 640 } | 656 } |
| 641 | 657 |
| 642 intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { | 658 ErrorCode Sandbox::Trap(ErrorCode::TrapFnc fnc, const void *aux) { |
| 643 die(static_cast<char *>(aux)); | |
| 644 } | |
| 645 | |
| 646 int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { | |
| 647 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance | 659 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance |
| 648 // of a SECCOMP_RET_TRAP. | 660 // of a SECCOMP_RET_TRAP. |
| 649 std::pair<TrapFnc, const void *> key(fnc, aux); | 661 std::pair<ErrorCode::TrapFnc, const void *> key(fnc, aux); |
| 650 TrapIds::const_iterator iter = trapIds_.find(key); | 662 TrapIds::const_iterator iter = trapIds_.find(key); |
| 663 uint16_t id; |
| 651 if (iter != trapIds_.end()) { | 664 if (iter != trapIds_.end()) { |
| 652 // We have seen this pair before. Return the same id that we assigned | 665 // We have seen this pair before. Return the same id that we assigned |
| 653 // earlier. | 666 // earlier. |
| 654 return iter->second; | 667 id = iter->second; |
| 655 } else { | 668 } else { |
| 656 // This is a new pair. Remember it and assign a new id. | 669 // This is a new pair. Remember it and assign a new id. |
| 657 // Please note that we have to store traps in memory that doesn't get | 670 // Please note that we have to store traps in memory that doesn't get |
| 658 // deallocated when the program is shutting down. A memory leak is | 671 // deallocated when the program is shutting down. A memory leak is |
| 659 // intentional, because we might otherwise not be able to execute | 672 // intentional, because we might otherwise not be able to execute |
| 660 // system calls part way through the program shutting down | 673 // system calls part way through the program shutting down |
| 661 if (!traps_) { | 674 if (!traps_) { |
| 662 traps_ = new Traps(); | 675 traps_ = new Traps(); |
| 663 } | 676 } |
| 664 Traps::size_type id = traps_->size() + 1; | 677 if (traps_->size() >= SECCOMP_RET_DATA) { |
| 665 if (id > SECCOMP_RET_DATA) { | |
| 666 // In practice, this is pretty much impossible to trigger, as there | 678 // In practice, this is pretty much impossible to trigger, as there |
| 667 // are other kernel limitations that restrict overall BPF program sizes. | 679 // are other kernel limitations that restrict overall BPF program sizes. |
| 668 die("Too many SECCOMP_RET_TRAP callback instances"); | 680 die("Too many SECCOMP_RET_TRAP callback instances"); |
| 669 } | 681 } |
| 682 id = traps_->size() + 1; |
| 670 | 683 |
| 671 traps_->push_back(ErrorCode(fnc, aux, id)); | 684 traps_->push_back(ErrorCode(fnc, aux, id)); |
| 672 trapIds_[key] = id; | 685 trapIds_[key] = id; |
| 673 | 686 |
| 674 // We want to access the traps_ vector from our signal handler. But | 687 // We want to access the traps_ vector from our signal handler. But |
| 675 // we are not assured that doing so is async-signal safe. On the other | 688 // we are not assured that doing so is async-signal safe. On the other |
| 676 // hand, C++ guarantees that the contents of a vector is stored in a | 689 // hand, C++ guarantees that the contents of a vector is stored in a |
| 677 // contiguous C-style array. | 690 // contiguous C-style array. |
| 678 // So, we look up the address and size of this array outside of the | 691 // So, we look up the address and size of this array outside of the |
| 679 // signal handler, where we can safely do so. | 692 // signal handler, where we can safely do so. |
| 680 trapArray_ = &(*traps_)[0]; | 693 trapArray_ = &(*traps_)[0]; |
| 681 trapArraySize_ = id; | 694 trapArraySize_ = id; |
| 682 return id; | |
| 683 } | 695 } |
| 696 |
| 697 ErrorCode err = ErrorCode(fnc, aux, id); |
| 698 return errMap_[err.err()] = err; |
| 699 } |
| 700 |
| 701 intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { |
| 702 die(static_cast<char *>(aux)); |
| 703 } |
| 704 |
| 705 ErrorCode Sandbox::Kill(const char *msg) { |
| 706 return Trap(bpfFailure, const_cast<char *>(msg)); |
| 684 } | 707 } |
| 685 | 708 |
| 686 bool Sandbox::dryRun_ = false; | 709 bool Sandbox::dryRun_ = false; |
| 687 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 710 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
| 688 int Sandbox::proc_fd_ = -1; | 711 int Sandbox::proc_fd_ = -1; |
| 689 Sandbox::Evaluators Sandbox::evaluators_; | 712 Sandbox::Evaluators Sandbox::evaluators_; |
| 713 Sandbox::ErrMap Sandbox::errMap_; |
| 690 Sandbox::Traps *Sandbox::traps_ = NULL; | 714 Sandbox::Traps *Sandbox::traps_ = NULL; |
| 691 Sandbox::TrapIds Sandbox::trapIds_; | 715 Sandbox::TrapIds Sandbox::trapIds_; |
| 692 Sandbox::ErrorCode *Sandbox::trapArray_ = NULL; | 716 ErrorCode *Sandbox::trapArray_ = NULL; |
| 693 size_t Sandbox::trapArraySize_ = 0; | 717 size_t Sandbox::trapArraySize_ = 0; |
| 694 | 718 |
| 695 } // namespace | 719 } // namespace |
| OLD | NEW |