| 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 "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 6 | 6 |
| 7 // Some headers on Android are missing cdefs: crbug.com/172337. | 7 // Some headers on Android are missing cdefs: crbug.com/172337. |
| 8 // (We can't use OS_ANDROID here since build_config.h is not included). | 8 // (We can't use OS_ANDROID here since build_config.h is not included). |
| 9 #if defined(ANDROID) | 9 #if defined(ANDROID) |
| 10 #include <sys/cdefs.h> | 10 #include <sys/cdefs.h> |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 } | 169 } |
| 170 return true; | 170 return true; |
| 171 } | 171 } |
| 172 | 172 |
| 173 bool IsDenied(const ErrorCode& code) { | 173 bool IsDenied(const ErrorCode& code) { |
| 174 return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || | 174 return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || |
| 175 (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) && | 175 (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) && |
| 176 code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO)); | 176 code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO)); |
| 177 } | 177 } |
| 178 | 178 |
| 179 // Function that can be passed as a callback function to CodeGen::Traverse(). | |
| 180 // Checks whether the "insn" returns an UnsafeTrap() ErrorCode. If so, it | |
| 181 // sets the "bool" variable pointed to by "aux". | |
| 182 void CheckForUnsafeErrorCodes(Instruction* insn, void* aux) { | |
| 183 bool* is_unsafe = static_cast<bool*>(aux); | |
| 184 if (!*is_unsafe) { | |
| 185 if (BPF_CLASS(insn->code) == BPF_RET && insn->k > SECCOMP_RET_TRAP && | |
| 186 insn->k - SECCOMP_RET_TRAP <= SECCOMP_RET_DATA) { | |
| 187 if (!Trap::IsSafeTrapId(insn->k & SECCOMP_RET_DATA)) { | |
| 188 *is_unsafe = true; | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 // A Trap() handler that returns an "errno" value. The value is encoded | 179 // A Trap() handler that returns an "errno" value. The value is encoded |
| 195 // in the "aux" parameter. | 180 // in the "aux" parameter. |
| 196 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) { | 181 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) { |
| 197 // TrapFnc functions report error by following the native kernel convention | 182 // TrapFnc functions report error by following the native kernel convention |
| 198 // of returning an exit code in the range of -1..-4096. They do not try to | 183 // of returning an exit code in the range of -1..-4096. They do not try to |
| 199 // set errno themselves. The glibc wrapper that triggered the SIGSYS will | 184 // set errno themselves. The glibc wrapper that triggered the SIGSYS will |
| 200 // ultimately do so for us. | 185 // ultimately do so for us. |
| 201 int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA; | 186 int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA; |
| 202 return -err; | 187 return -err; |
| 203 } | 188 } |
| 204 | 189 |
| 205 // Function that can be passed as a callback function to CodeGen::Traverse(). | |
| 206 // Checks whether the "insn" returns an errno value from a BPF filter. If so, | |
| 207 // it rewrites the instruction to instead call a Trap() handler that does | |
| 208 // the same thing. "aux" is ignored. | |
| 209 void RedirectToUserspace(Instruction* insn, void* aux) { | |
| 210 // When inside an UnsafeTrap() callback, we want to allow all system calls. | |
| 211 // This means, we must conditionally disable the sandbox -- and that's not | |
| 212 // something that kernel-side BPF filters can do, as they cannot inspect | |
| 213 // any state other than the syscall arguments. | |
| 214 // But if we redirect all error handlers to user-space, then we can easily | |
| 215 // make this decision. | |
| 216 // The performance penalty for this extra round-trip to user-space is not | |
| 217 // actually that bad, as we only ever pay it for denied system calls; and a | |
| 218 // typical program has very few of these. | |
| 219 SandboxBPF* sandbox = static_cast<SandboxBPF*>(aux); | |
| 220 if (BPF_CLASS(insn->code) == BPF_RET && | |
| 221 (insn->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { | |
| 222 insn->k = sandbox->Trap(ReturnErrno, | |
| 223 reinterpret_cast<void*>(insn->k & SECCOMP_RET_DATA)).err(); | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 // This wraps an existing policy and changes its behavior to match the changes | |
| 228 // made by RedirectToUserspace(). This is part of the framework that allows BPF | |
| 229 // evaluation in userland. | |
| 230 // TODO(markus): document the code inside better. | |
| 231 class RedirectToUserSpacePolicyWrapper : public SandboxBPFPolicy { | |
| 232 public: | |
| 233 explicit RedirectToUserSpacePolicyWrapper( | |
| 234 const SandboxBPFPolicy* wrapped_policy) | |
| 235 : wrapped_policy_(wrapped_policy) { | |
| 236 DCHECK(wrapped_policy_); | |
| 237 } | |
| 238 | |
| 239 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, | |
| 240 int system_call_number) const override { | |
| 241 ErrorCode err = | |
| 242 wrapped_policy_->EvaluateSyscall(sandbox_compiler, system_call_number); | |
| 243 ChangeErrnoToTraps(&err, sandbox_compiler); | |
| 244 return err; | |
| 245 } | |
| 246 | |
| 247 virtual ErrorCode InvalidSyscall( | |
| 248 SandboxBPF* sandbox_compiler) const override { | |
| 249 return ReturnErrnoViaTrap(sandbox_compiler, ENOSYS); | |
| 250 } | |
| 251 | |
| 252 private: | |
| 253 ErrorCode ReturnErrnoViaTrap(SandboxBPF* sandbox_compiler, int err) const { | |
| 254 return sandbox_compiler->Trap(ReturnErrno, reinterpret_cast<void*>(err)); | |
| 255 } | |
| 256 | |
| 257 // ChangeErrnoToTraps recursivly iterates through the ErrorCode | |
| 258 // converting any ERRNO to a userspace trap | |
| 259 void ChangeErrnoToTraps(ErrorCode* err, SandboxBPF* sandbox_compiler) const { | |
| 260 if (err->error_type() == ErrorCode::ET_SIMPLE && | |
| 261 (err->err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { | |
| 262 // Have an errno, need to change this to a trap | |
| 263 *err = | |
| 264 ReturnErrnoViaTrap(sandbox_compiler, err->err() & SECCOMP_RET_DATA); | |
| 265 return; | |
| 266 } else if (err->error_type() == ErrorCode::ET_COND) { | |
| 267 // Need to explore both paths | |
| 268 ChangeErrnoToTraps((ErrorCode*)err->passed(), sandbox_compiler); | |
| 269 ChangeErrnoToTraps((ErrorCode*)err->failed(), sandbox_compiler); | |
| 270 return; | |
| 271 } else if (err->error_type() == ErrorCode::ET_TRAP) { | |
| 272 return; | |
| 273 } else if (err->error_type() == ErrorCode::ET_SIMPLE && | |
| 274 (err->err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ALLOW) { | |
| 275 return; | |
| 276 } | |
| 277 NOTREACHED(); | |
| 278 } | |
| 279 | |
| 280 const SandboxBPFPolicy* wrapped_policy_; | |
| 281 DISALLOW_COPY_AND_ASSIGN(RedirectToUserSpacePolicyWrapper); | |
| 282 }; | |
| 283 | |
| 284 intptr_t BPFFailure(const struct arch_seccomp_data&, void* aux) { | 190 intptr_t BPFFailure(const struct arch_seccomp_data&, void* aux) { |
| 285 SANDBOX_DIE(static_cast<char*>(aux)); | 191 SANDBOX_DIE(static_cast<char*>(aux)); |
| 286 } | 192 } |
| 287 | 193 |
| 288 } // namespace | 194 } // namespace |
| 289 | 195 |
| 290 SandboxBPF::SandboxBPF() | 196 SandboxBPF::SandboxBPF() |
| 291 : quiet_(false), | 197 : quiet_(false), |
| 292 proc_fd_(-1), | 198 proc_fd_(-1), |
| 293 conds_(new Conds), | 199 conds_(new Conds), |
| 294 sandbox_has_started_(false) {} | 200 sandbox_has_started_(false), |
| 201 has_unsafe_traps_(false) { |
| 202 } |
| 295 | 203 |
| 296 SandboxBPF::~SandboxBPF() { | 204 SandboxBPF::~SandboxBPF() { |
| 297 // It is generally unsafe to call any memory allocator operations or to even | 205 // It is generally unsafe to call any memory allocator operations or to even |
| 298 // call arbitrary destructors after having installed a new policy. We just | 206 // call arbitrary destructors after having installed a new policy. We just |
| 299 // have no way to tell whether this policy would allow the system calls that | 207 // have no way to tell whether this policy would allow the system calls that |
| 300 // the constructors can trigger. | 208 // the constructors can trigger. |
| 301 // So, we normally destroy all of our complex state prior to starting the | 209 // So, we normally destroy all of our complex state prior to starting the |
| 302 // sandbox. But this won't happen, if the Sandbox object was created and | 210 // sandbox. But this won't happen, if the Sandbox object was created and |
| 303 // never actually used to set up a sandbox. So, just in case, we are | 211 // never actually used to set up a sandbox. So, just in case, we are |
| 304 // destroying any remaining state. | 212 // destroying any remaining state. |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 } | 557 } |
| 650 | 558 |
| 651 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { | 559 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { |
| 652 #if !defined(NDEBUG) | 560 #if !defined(NDEBUG) |
| 653 force_verification = true; | 561 force_verification = true; |
| 654 #endif | 562 #endif |
| 655 | 563 |
| 656 // Verify that the user pushed a policy. | 564 // Verify that the user pushed a policy. |
| 657 DCHECK(policy_); | 565 DCHECK(policy_); |
| 658 | 566 |
| 567 // If our BPF program has unsafe traps, enable support for them. |
| 568 has_unsafe_traps_ = policy_->HasUnsafeTraps(); |
| 569 if (has_unsafe_traps_) { |
| 570 // As support for unsafe jumps essentially defeats all the security |
| 571 // measures that the sandbox provides, we print a big warning message -- |
| 572 // and of course, we make sure to only ever enable this feature if it |
| 573 // is actually requested by the sandbox policy. |
| 574 if (Syscall::Call(-1) == -1 && errno == ENOSYS) { |
| 575 SANDBOX_DIE( |
| 576 "Support for UnsafeTrap() has not yet been ported to this " |
| 577 "architecture"); |
| 578 } |
| 579 |
| 580 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { |
| 581 if (!policy_->EvaluateSyscall(this, kSyscallsRequiredForUnsafeTraps[i]) |
| 582 .Equals(ErrorCode(ErrorCode::ERR_ALLOWED))) { |
| 583 SANDBOX_DIE( |
| 584 "Policies that use UnsafeTrap() must unconditionally allow all " |
| 585 "required system calls"); |
| 586 } |
| 587 } |
| 588 |
| 589 if (!Trap::EnableUnsafeTrapsInSigSysHandler()) { |
| 590 // We should never be able to get here, as UnsafeTrap() should never |
| 591 // actually return a valid ErrorCode object unless the user set the |
| 592 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore, |
| 593 // "has_unsafe_traps" would always be false. But better double-check |
| 594 // than enabling dangerous code. |
| 595 SANDBOX_DIE("We'd rather die than enable unsafe traps"); |
| 596 } |
| 597 } |
| 598 |
| 659 // Assemble the BPF filter program. | 599 // Assemble the BPF filter program. |
| 660 CodeGen* gen = new CodeGen(); | 600 CodeGen* gen = new CodeGen(); |
| 661 if (!gen) { | 601 if (!gen) { |
| 662 SANDBOX_DIE("Out of memory"); | 602 SANDBOX_DIE("Out of memory"); |
| 663 } | 603 } |
| 664 | 604 Instruction* head = CompilePolicy(gen); |
| 665 bool has_unsafe_traps; | |
| 666 Instruction* head = CompilePolicy(gen, &has_unsafe_traps); | |
| 667 | 605 |
| 668 // Turn the DAG into a vector of instructions. | 606 // Turn the DAG into a vector of instructions. |
| 669 Program* program = new Program(); | 607 Program* program = new Program(); |
| 670 gen->Compile(head, program); | 608 gen->Compile(head, program); |
| 671 delete gen; | 609 delete gen; |
| 672 | 610 |
| 673 // Make sure compilation resulted in BPF program that executes | 611 // Make sure compilation resulted in BPF program that executes |
| 674 // correctly. Otherwise, there is an internal error in our BPF compiler. | 612 // correctly. Otherwise, there is an internal error in our BPF compiler. |
| 675 // There is really nothing the caller can do until the bug is fixed. | 613 // There is really nothing the caller can do until the bug is fixed. |
| 676 if (force_verification) { | 614 if (force_verification) { |
| 677 // Verification is expensive. We only perform this step, if we are | 615 // Verification is expensive. We only perform this step, if we are |
| 678 // compiled in debug mode, or if the caller explicitly requested | 616 // compiled in debug mode, or if the caller explicitly requested |
| 679 // verification. | 617 // verification. |
| 680 VerifyProgram(*program, has_unsafe_traps); | 618 VerifyProgram(*program); |
| 681 } | 619 } |
| 682 | 620 |
| 683 return program; | 621 return program; |
| 684 } | 622 } |
| 685 | 623 |
| 686 Instruction* SandboxBPF::CompilePolicy(CodeGen* gen, bool* has_unsafe_traps) { | 624 Instruction* SandboxBPF::CompilePolicy(CodeGen* gen) { |
| 687 // A compiled policy consists of three logical parts: | 625 // A compiled policy consists of three logical parts: |
| 688 // 1. Check that the "arch" field matches the expected architecture. | 626 // 1. Check that the "arch" field matches the expected architecture. |
| 689 // 2. If the policy involves unsafe traps, check if the syscall was | 627 // 2. If the policy involves unsafe traps, check if the syscall was |
| 690 // invoked by Syscall::Call, and then allow it unconditionally. | 628 // invoked by Syscall::Call, and then allow it unconditionally. |
| 691 // 3. Check the system call number and jump to the appropriate compiled | 629 // 3. Check the system call number and jump to the appropriate compiled |
| 692 // system call policy number. | 630 // system call policy number. |
| 693 return CheckArch( | 631 return CheckArch(gen, MaybeAddEscapeHatch(gen, DispatchSyscall(gen))); |
| 694 gen, MaybeAddEscapeHatch(gen, has_unsafe_traps, DispatchSyscall(gen))); | |
| 695 } | 632 } |
| 696 | 633 |
| 697 Instruction* SandboxBPF::CheckArch(CodeGen* gen, Instruction* passed) { | 634 Instruction* SandboxBPF::CheckArch(CodeGen* gen, Instruction* passed) { |
| 698 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 635 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
| 699 // system call. | 636 // system call. |
| 700 return gen->MakeInstruction( | 637 return gen->MakeInstruction( |
| 701 BPF_LD + BPF_W + BPF_ABS, | 638 BPF_LD + BPF_W + BPF_ABS, |
| 702 SECCOMP_ARCH_IDX, | 639 SECCOMP_ARCH_IDX, |
| 703 gen->MakeInstruction( | 640 gen->MakeInstruction( |
| 704 BPF_JMP + BPF_JEQ + BPF_K, | 641 BPF_JMP + BPF_JEQ + BPF_K, |
| 705 SECCOMP_ARCH, | 642 SECCOMP_ARCH, |
| 706 passed, | 643 passed, |
| 707 RetExpression(gen, | 644 RetExpression(gen, |
| 708 Kill("Invalid audit architecture in BPF filter")))); | 645 Kill("Invalid audit architecture in BPF filter")))); |
| 709 } | 646 } |
| 710 | 647 |
| 711 Instruction* SandboxBPF::MaybeAddEscapeHatch(CodeGen* gen, | 648 Instruction* SandboxBPF::MaybeAddEscapeHatch(CodeGen* gen, |
| 712 bool* has_unsafe_traps, | |
| 713 Instruction* rest) { | 649 Instruction* rest) { |
| 714 // If there is at least one UnsafeTrap() in our program, the entire sandbox | 650 // If no unsafe traps, then simply return |rest|. |
| 715 // is unsafe. We need to modify the program so that all non- | 651 if (!has_unsafe_traps_) { |
| 716 // SECCOMP_RET_ALLOW ErrorCodes are handled in user-space. This will then | |
| 717 // allow us to temporarily disable sandboxing rules inside of callbacks to | |
| 718 // UnsafeTrap(). | |
| 719 *has_unsafe_traps = false; | |
| 720 gen->Traverse(rest, CheckForUnsafeErrorCodes, has_unsafe_traps); | |
| 721 if (!*has_unsafe_traps) { | |
| 722 // If no unsafe traps, then simply return |rest|. | |
| 723 return rest; | 652 return rest; |
| 724 } | 653 } |
| 725 | 654 |
| 726 // If our BPF program has unsafe jumps, enable support for them. This | |
| 727 // test happens very early in the BPF filter program. Even before we | |
| 728 // consider looking at system call numbers. | |
| 729 // As support for unsafe jumps essentially defeats all the security | |
| 730 // measures that the sandbox provides, we print a big warning message -- | |
| 731 // and of course, we make sure to only ever enable this feature if it | |
| 732 // is actually requested by the sandbox policy. | |
| 733 if (Syscall::Call(-1) == -1 && errno == ENOSYS) { | |
| 734 SANDBOX_DIE( | |
| 735 "Support for UnsafeTrap() has not yet been ported to this " | |
| 736 "architecture"); | |
| 737 } | |
| 738 | |
| 739 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { | |
| 740 if (!policy_->EvaluateSyscall(this, kSyscallsRequiredForUnsafeTraps[i]) | |
| 741 .Equals(ErrorCode(ErrorCode::ERR_ALLOWED))) { | |
| 742 SANDBOX_DIE( | |
| 743 "Policies that use UnsafeTrap() must unconditionally allow all " | |
| 744 "required system calls"); | |
| 745 } | |
| 746 } | |
| 747 | |
| 748 if (!Trap::EnableUnsafeTrapsInSigSysHandler()) { | |
| 749 // We should never be able to get here, as UnsafeTrap() should never | |
| 750 // actually return a valid ErrorCode object unless the user set the | |
| 751 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore, | |
| 752 // "has_unsafe_traps" would always be false. But better double-check | |
| 753 // than enabling dangerous code. | |
| 754 SANDBOX_DIE("We'd rather die than enable unsafe traps"); | |
| 755 } | |
| 756 gen->Traverse(rest, RedirectToUserspace, this); | |
| 757 | |
| 758 // Allow system calls, if they originate from our magic return address | 655 // Allow system calls, if they originate from our magic return address |
| 759 // (which we can query by calling Syscall::Call(-1)). | 656 // (which we can query by calling Syscall::Call(-1)). |
| 760 uint64_t syscall_entry_point = | 657 uint64_t syscall_entry_point = |
| 761 static_cast<uint64_t>(static_cast<uintptr_t>(Syscall::Call(-1))); | 658 static_cast<uint64_t>(static_cast<uintptr_t>(Syscall::Call(-1))); |
| 762 uint32_t low = static_cast<uint32_t>(syscall_entry_point); | 659 uint32_t low = static_cast<uint32_t>(syscall_entry_point); |
| 763 uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32); | 660 uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32); |
| 764 | 661 |
| 765 // BPF cannot do native 64-bit comparisons, so we have to compare | 662 // BPF cannot do native 64-bit comparisons, so we have to compare |
| 766 // both 32-bit halves of the instruction pointer. If they match what | 663 // both 32-bit halves of the instruction pointer. If they match what |
| 767 // we expect, we return ERR_ALLOWED. If either or both don't match, | 664 // we expect, we return ERR_ALLOWED. If either or both don't match, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 816 // The older i386 and x86-64 APIs clear bit 30 on all system calls. | 713 // The older i386 and x86-64 APIs clear bit 30 on all system calls. |
| 817 return gen->MakeInstruction( | 714 return gen->MakeInstruction( |
| 818 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed); | 715 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed); |
| 819 } | 716 } |
| 820 } | 717 } |
| 821 | 718 |
| 822 // TODO(mdempsky): Similar validation for other architectures? | 719 // TODO(mdempsky): Similar validation for other architectures? |
| 823 return passed; | 720 return passed; |
| 824 } | 721 } |
| 825 | 722 |
| 826 void SandboxBPF::VerifyProgram(const Program& program, bool has_unsafe_traps) { | 723 void SandboxBPF::VerifyProgram(const Program& program) { |
| 827 // If we previously rewrote the BPF program so that it calls user-space | |
| 828 // whenever we return an "errno" value from the filter, then we have to | |
| 829 // wrap our system call evaluator to perform the same operation. Otherwise, | |
| 830 // the verifier would also report a mismatch in return codes. | |
| 831 scoped_ptr<const RedirectToUserSpacePolicyWrapper> redirected_policy( | |
| 832 new RedirectToUserSpacePolicyWrapper(policy_.get())); | |
| 833 | |
| 834 const char* err = NULL; | 724 const char* err = NULL; |
| 835 if (!Verifier::VerifyBPF(this, | 725 if (!Verifier::VerifyBPF(this, program, *policy_, &err)) { |
| 836 program, | |
| 837 has_unsafe_traps ? *redirected_policy : *policy_, | |
| 838 &err)) { | |
| 839 CodeGen::PrintProgram(program); | 726 CodeGen::PrintProgram(program); |
| 840 SANDBOX_DIE(err); | 727 SANDBOX_DIE(err); |
| 841 } | 728 } |
| 842 } | 729 } |
| 843 | 730 |
| 844 void SandboxBPF::FindRanges(Ranges* ranges) { | 731 void SandboxBPF::FindRanges(Ranges* ranges) { |
| 845 // Please note that "struct seccomp_data" defines system calls as a signed | 732 // Please note that "struct seccomp_data" defines system calls as a signed |
| 846 // int32_t, but BPF instructions always operate on unsigned quantities. We | 733 // int32_t, but BPF instructions always operate on unsigned quantities. We |
| 847 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, | 734 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, |
| 848 // and then verifying that the rest of the number range (both positive and | 735 // and then verifying that the rest of the number range (both positive and |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1054 BPF_ALU + BPF_AND + BPF_K, | 941 BPF_ALU + BPF_AND + BPF_K, |
| 1055 mask, | 942 mask, |
| 1056 gen->MakeInstruction( | 943 gen->MakeInstruction( |
| 1057 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); | 944 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); |
| 1058 } | 945 } |
| 1059 | 946 |
| 1060 ErrorCode SandboxBPF::Unexpected64bitArgument() { | 947 ErrorCode SandboxBPF::Unexpected64bitArgument() { |
| 1061 return Kill("Unexpected 64bit argument detected"); | 948 return Kill("Unexpected 64bit argument detected"); |
| 1062 } | 949 } |
| 1063 | 950 |
| 951 ErrorCode SandboxBPF::Error(int err) { |
| 952 if (has_unsafe_traps_) { |
| 953 // When inside an UnsafeTrap() callback, we want to allow all system calls. |
| 954 // This means, we must conditionally disable the sandbox -- and that's not |
| 955 // something that kernel-side BPF filters can do, as they cannot inspect |
| 956 // any state other than the syscall arguments. |
| 957 // But if we redirect all error handlers to user-space, then we can easily |
| 958 // make this decision. |
| 959 // The performance penalty for this extra round-trip to user-space is not |
| 960 // actually that bad, as we only ever pay it for denied system calls; and a |
| 961 // typical program has very few of these. |
| 962 return Trap(ReturnErrno, reinterpret_cast<void*>(err)); |
| 963 } |
| 964 |
| 965 return ErrorCode(err); |
| 966 } |
| 967 |
| 1064 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { | 968 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { |
| 1065 return ErrorCode(fnc, aux, true /* Safe Trap */); | 969 return ErrorCode(fnc, aux, true /* Safe Trap */); |
| 1066 } | 970 } |
| 1067 | 971 |
| 1068 ErrorCode SandboxBPF::UnsafeTrap(Trap::TrapFnc fnc, const void* aux) { | 972 ErrorCode SandboxBPF::UnsafeTrap(Trap::TrapFnc fnc, const void* aux) { |
| 1069 return ErrorCode(fnc, aux, false /* Unsafe Trap */); | 973 return ErrorCode(fnc, aux, false /* Unsafe Trap */); |
| 1070 } | 974 } |
| 1071 | 975 |
| 1072 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) { | 976 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) { |
| 1073 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { | 977 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1143 } | 1047 } |
| 1144 } | 1048 } |
| 1145 | 1049 |
| 1146 ErrorCode SandboxBPF::Kill(const char* msg) { | 1050 ErrorCode SandboxBPF::Kill(const char* msg) { |
| 1147 return Trap(BPFFailure, const_cast<char*>(msg)); | 1051 return Trap(BPFFailure, const_cast<char*>(msg)); |
| 1148 } | 1052 } |
| 1149 | 1053 |
| 1150 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; | 1054 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; |
| 1151 | 1055 |
| 1152 } // namespace sandbox | 1056 } // namespace sandbox |
| OLD | NEW |