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 |