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> |
11 #endif | 11 #endif |
12 | 12 |
13 #include <errno.h> | 13 #include <errno.h> |
14 #include <fcntl.h> | 14 #include <fcntl.h> |
15 #include <string.h> | 15 #include <string.h> |
16 #include <sys/prctl.h> | 16 #include <sys/prctl.h> |
17 #include <sys/stat.h> | 17 #include <sys/stat.h> |
18 #include <sys/syscall.h> | 18 #include <sys/syscall.h> |
19 #include <sys/types.h> | 19 #include <sys/types.h> |
20 #include <time.h> | 20 #include <time.h> |
21 #include <unistd.h> | 21 #include <unistd.h> |
22 | 22 |
23 #include <limits> | |
24 | |
23 #include "base/compiler_specific.h" | 25 #include "base/compiler_specific.h" |
24 #include "base/logging.h" | 26 #include "base/logging.h" |
25 #include "base/macros.h" | 27 #include "base/macros.h" |
26 #include "base/memory/scoped_ptr.h" | 28 #include "base/memory/scoped_ptr.h" |
27 #include "base/posix/eintr_wrapper.h" | 29 #include "base/posix/eintr_wrapper.h" |
28 #include "sandbox/linux/seccomp-bpf/codegen.h" | 30 #include "sandbox/linux/seccomp-bpf/codegen.h" |
29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | 31 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
30 #include "sandbox/linux/seccomp-bpf/syscall.h" | 32 #include "sandbox/linux/seccomp-bpf/syscall.h" |
31 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" | 33 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" |
32 #include "sandbox/linux/seccomp-bpf/verifier.h" | 34 #include "sandbox/linux/seccomp-bpf/verifier.h" |
33 #include "sandbox/linux/services/linux_syscalls.h" | 35 #include "sandbox/linux/services/linux_syscalls.h" |
34 | 36 |
35 namespace sandbox { | 37 namespace sandbox { |
36 | 38 |
37 namespace { | 39 namespace { |
38 | 40 |
39 const int kExpectedExitCode = 100; | 41 const int kExpectedExitCode = 100; |
40 | 42 |
41 int popcount(uint32_t x) { | 43 bool HasExactlyOneBit(uint64_t x) { |
42 return __builtin_popcount(x); | 44 // Common trick; e.g., see http://stackoverflow.com/a/108329. |
45 return x != 0 && (x & (x - 1)) == 0; | |
43 } | 46 } |
44 | 47 |
45 #if !defined(NDEBUG) | 48 #if !defined(NDEBUG) |
46 void WriteFailedStderrSetupMessage(int out_fd) { | 49 void WriteFailedStderrSetupMessage(int out_fd) { |
47 const char* error_string = strerror(errno); | 50 const char* error_string = strerror(errno); |
48 static const char msg[] = | 51 static const char msg[] = |
49 "You have reproduced a puzzling issue.\n" | 52 "You have reproduced a puzzling issue.\n" |
50 "Please, report to crbug.com/152530!\n" | 53 "Please, report to crbug.com/152530!\n" |
51 "Failed to set up stderr: "; | 54 "Failed to set up stderr: "; |
52 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string && | 55 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string && |
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
862 } | 865 } |
863 | 866 |
864 Instruction* SandboxBPF::CondExpression(CodeGen* gen, const ErrorCode& cond) { | 867 Instruction* SandboxBPF::CondExpression(CodeGen* gen, const ErrorCode& cond) { |
865 // We can only inspect the six system call arguments that are passed in | 868 // We can only inspect the six system call arguments that are passed in |
866 // CPU registers. | 869 // CPU registers. |
867 if (cond.argno_ < 0 || cond.argno_ >= 6) { | 870 if (cond.argno_ < 0 || cond.argno_ >= 6) { |
868 SANDBOX_DIE( | 871 SANDBOX_DIE( |
869 "Internal compiler error; invalid argument number " | 872 "Internal compiler error; invalid argument number " |
870 "encountered"); | 873 "encountered"); |
871 } | 874 } |
872 | 875 if (cond.width_ != ErrorCode::TP_32BIT && |
873 // BPF programs operate on 32bit entities. Load both halfs of the 64bit | 876 cond.width_ != ErrorCode::TP_64BIT) { |
874 // system call argument and then generate suitable conditional statements. | 877 SANDBOX_DIE("Internal compiler error; invalid argument width"); |
875 Instruction* msb_head = gen->MakeInstruction( | 878 } |
876 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARG_MSB_IDX(cond.argno_)); | 879 if ((cond.value_ & cond.mask_) != cond.value_) { |
877 Instruction* msb_tail = msb_head; | 880 SANDBOX_DIE("Internal compiler error; invalid masked value"); |
878 Instruction* lsb_head = gen->MakeInstruction( | |
879 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARG_LSB_IDX(cond.argno_)); | |
880 Instruction* lsb_tail = lsb_head; | |
881 | |
882 // Emit a suitable comparison statement. | |
883 switch (cond.op_) { | |
884 case ErrorCode::OP_EQUAL: | |
885 // Compare the least significant bits for equality | |
886 lsb_tail = gen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, | |
887 static_cast<uint32_t>(cond.value_), | |
888 RetExpression(gen, *cond.passed_), | |
889 RetExpression(gen, *cond.failed_)); | |
890 gen->JoinInstructions(lsb_head, lsb_tail); | |
891 | |
892 // If we are looking at a 64bit argument, we need to also compare the | |
893 // most significant bits. | |
894 if (cond.width_ == ErrorCode::TP_64BIT) { | |
895 msb_tail = | |
896 gen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, | |
897 static_cast<uint32_t>(cond.value_ >> 32), | |
898 lsb_head, | |
899 RetExpression(gen, *cond.failed_)); | |
900 gen->JoinInstructions(msb_head, msb_tail); | |
901 } | |
902 break; | |
903 case ErrorCode::OP_HAS_ALL_BITS: | |
904 // Check the bits in the LSB half of the system call argument. Our | |
905 // OP_HAS_ALL_BITS operator passes, iff all of the bits are set. This is | |
906 // different from the kernel's BPF_JSET operation which passes, if any of | |
907 // the bits are set. | |
908 // Of course, if there is only a single set bit (or none at all), then | |
909 // things get easier. | |
910 { | |
911 uint32_t lsb_bits = static_cast<uint32_t>(cond.value_); | |
912 int lsb_bit_count = popcount(lsb_bits); | |
913 if (lsb_bit_count == 0) { | |
914 // No bits are set in the LSB half. The test will always pass. | |
915 lsb_head = RetExpression(gen, *cond.passed_); | |
916 lsb_tail = NULL; | |
917 } else if (lsb_bit_count == 1) { | |
918 // Exactly one bit is set in the LSB half. We can use the BPF_JSET | |
919 // operator. | |
920 lsb_tail = gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, | |
921 lsb_bits, | |
922 RetExpression(gen, *cond.passed_), | |
923 RetExpression(gen, *cond.failed_)); | |
924 gen->JoinInstructions(lsb_head, lsb_tail); | |
925 } else { | |
926 // More than one bit is set in the LSB half. We need to combine | |
927 // BPF_AND and BPF_JEQ to test whether all of these bits are in fact | |
928 // set in the system call argument. | |
929 gen->JoinInstructions( | |
930 lsb_head, | |
931 gen->MakeInstruction(BPF_ALU + BPF_AND + BPF_K, | |
932 lsb_bits, | |
933 lsb_tail = gen->MakeInstruction( | |
934 BPF_JMP + BPF_JEQ + BPF_K, | |
935 lsb_bits, | |
936 RetExpression(gen, *cond.passed_), | |
937 RetExpression(gen, *cond.failed_)))); | |
938 } | |
939 } | |
940 | |
941 // If we are looking at a 64bit argument, we need to also check the bits | |
942 // in the MSB half of the system call argument. | |
943 if (cond.width_ == ErrorCode::TP_64BIT) { | |
944 uint32_t msb_bits = static_cast<uint32_t>(cond.value_ >> 32); | |
945 int msb_bit_count = popcount(msb_bits); | |
946 if (msb_bit_count == 0) { | |
947 // No bits are set in the MSB half. The test will always pass. | |
948 msb_head = lsb_head; | |
949 } else if (msb_bit_count == 1) { | |
950 // Exactly one bit is set in the MSB half. We can use the BPF_JSET | |
951 // operator. | |
952 msb_tail = gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, | |
953 msb_bits, | |
954 lsb_head, | |
955 RetExpression(gen, *cond.failed_)); | |
956 gen->JoinInstructions(msb_head, msb_tail); | |
957 } else { | |
958 // More than one bit is set in the MSB half. We need to combine | |
959 // BPF_AND and BPF_JEQ to test whether all of these bits are in fact | |
960 // set in the system call argument. | |
961 gen->JoinInstructions( | |
962 msb_head, | |
963 gen->MakeInstruction( | |
964 BPF_ALU + BPF_AND + BPF_K, | |
965 msb_bits, | |
966 gen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, | |
967 msb_bits, | |
968 lsb_head, | |
969 RetExpression(gen, *cond.failed_)))); | |
970 } | |
971 } | |
972 break; | |
973 case ErrorCode::OP_HAS_ANY_BITS: | |
974 // Check the bits in the LSB half of the system call argument. Our | |
975 // OP_HAS_ANY_BITS operator passes, iff any of the bits are set. This maps | |
976 // nicely to the kernel's BPF_JSET operation. | |
977 { | |
978 uint32_t lsb_bits = static_cast<uint32_t>(cond.value_); | |
979 if (!lsb_bits) { | |
980 // No bits are set in the LSB half. The test will always fail. | |
981 lsb_head = RetExpression(gen, *cond.failed_); | |
982 lsb_tail = NULL; | |
983 } else { | |
984 lsb_tail = gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, | |
985 lsb_bits, | |
986 RetExpression(gen, *cond.passed_), | |
987 RetExpression(gen, *cond.failed_)); | |
988 gen->JoinInstructions(lsb_head, lsb_tail); | |
989 } | |
990 } | |
991 | |
992 // If we are looking at a 64bit argument, we need to also check the bits | |
993 // in the MSB half of the system call argument. | |
994 if (cond.width_ == ErrorCode::TP_64BIT) { | |
995 uint32_t msb_bits = static_cast<uint32_t>(cond.value_ >> 32); | |
996 if (!msb_bits) { | |
997 // No bits are set in the MSB half. The test will always fail. | |
998 msb_head = lsb_head; | |
999 } else { | |
1000 msb_tail = gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, | |
1001 msb_bits, | |
1002 RetExpression(gen, *cond.passed_), | |
1003 lsb_head); | |
1004 gen->JoinInstructions(msb_head, msb_tail); | |
1005 } | |
1006 } | |
1007 break; | |
1008 default: | |
1009 // TODO(markus): Need to add support for OP_GREATER | |
1010 SANDBOX_DIE("Not implemented"); | |
1011 break; | |
1012 } | 881 } |
1013 | 882 |
1014 // Ensure that we never pass a 64bit value, when we only expect a 32bit | 883 Instruction* passed = RetExpression(gen, *cond.passed_); |
1015 // value. This is somewhat complicated by the fact that on 64bit systems, | 884 Instruction* failed = RetExpression(gen, *cond.failed_); |
1016 // callers could legitimately pass in a non-zero value in the MSB, iff the | 885 |
1017 // LSB has been sign-extended into the MSB. | 886 // We want to emit code to check "(arg & mask) == value" where arg, mask, and |
1018 if (cond.width_ == ErrorCode::TP_32BIT) { | 887 // value are 64-bit values, but the BPF machine is only 32-bit. We implement |
1019 if (cond.value_ >> 32) { | 888 // this by independently testing the upper and lower 32-bits and continuing to |
889 // "passed" if both evaluate true, or to "failed" if either evaluate false. | |
890 return CondExpressionHalf( | |
891 gen, | |
892 cond, | |
893 UpperHalf, | |
894 CondExpressionHalf(gen, cond, LowerHalf, passed, failed), | |
895 failed); | |
896 } | |
897 | |
898 Instruction* SandboxBPF::CondExpressionHalf(CodeGen* gen, | |
899 const ErrorCode& cond, | |
900 ArgHalf half, | |
901 Instruction* passed, | |
902 Instruction* failed) { | |
903 if (cond.width_ == ErrorCode::TP_32BIT && half == UpperHalf) { | |
904 // Special logic for sanity checking the upper 32-bits of 32-bit system | |
905 // call arguments. | |
906 | |
907 if ((cond.mask_ >> 32) != 0) { | |
1020 SANDBOX_DIE( | 908 SANDBOX_DIE( |
1021 "Invalid comparison of a 32bit system call argument " | 909 "Invalid comparison of a 32bit system call argument " |
1022 "against a 64bit constant; this test is always false."); | 910 "against a 64bit constant; this test is always false."); |
1023 } | 911 } |
1024 | 912 |
913 // TODO(mdempsky): Compile Unexpected64bitArgument() just per program. | |
1025 Instruction* invalid_64bit = RetExpression(gen, Unexpected64bitArgument()); | 914 Instruction* invalid_64bit = RetExpression(gen, Unexpected64bitArgument()); |
1026 #if __SIZEOF_POINTER__ > 4 | 915 |
1027 invalid_64bit = gen->MakeInstruction( | 916 const uint32_t upper = SECCOMP_ARG_MSB_IDX(cond.argno_); |
1028 BPF_JMP + BPF_JEQ + BPF_K, | 917 const uint32_t lower = SECCOMP_ARG_LSB_IDX(cond.argno_); |
1029 0xFFFFFFFF, | 918 |
1030 gen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, | 919 if (sizeof(void*) == 4) { |
1031 SECCOMP_ARG_LSB_IDX(cond.argno_), | 920 // On 32-bit platforms, the upper 32-bits should always be 0: |
jln (very slow on Chromium)
2014/09/04 02:08:36
I think it would be redundant with your previous c
mdempsky
2014/09/04 17:26:48
Yeah, it should be redundant, but I went ahead and
| |
1032 gen->MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, | 921 // LDW [upper] |
1033 0x80000000, | 922 // JEQ 0, passed, invalid |
1034 lsb_head, | 923 return gen->MakeInstruction( |
1035 invalid_64bit)), | 924 BPF_LD + BPF_W + BPF_ABS, |
1036 invalid_64bit); | 925 upper, |
1037 #endif | 926 gen->MakeInstruction( |
1038 gen->JoinInstructions( | 927 BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit)); |
1039 msb_tail, | 928 } |
929 | |
930 // On 64-bit platforms, the upper 32-bits may be 0 or ~0; but we only allow | |
931 // ~0 if the sign bit of the lower 32-bits is set too: | |
932 // LDW [upper] | |
933 // JEQ 0, passed, (next) | |
934 // JEQ ~0, (next), invalid | |
935 // LDW [lower] | |
936 // JSET (1<<31), passed, invalid | |
937 // | |
938 // TODO(mdempsky): The JSET instruction could perhaps jump to passed->next | |
939 // instead, as the first instruction of passed should be "LDW [lower]". | |
940 return gen->MakeInstruction( | |
941 BPF_LD + BPF_W + BPF_ABS, | |
942 upper, | |
1040 gen->MakeInstruction( | 943 gen->MakeInstruction( |
1041 BPF_JMP + BPF_JEQ + BPF_K, 0, lsb_head, invalid_64bit)); | 944 BPF_JMP + BPF_JEQ + BPF_K, |
945 0, | |
946 passed, | |
947 gen->MakeInstruction( | |
948 BPF_JMP + BPF_JEQ + BPF_K, | |
949 std::numeric_limits<uint32_t>::max(), | |
950 gen->MakeInstruction( | |
951 BPF_LD + BPF_W + BPF_ABS, | |
952 lower, | |
953 gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, | |
954 1U << 31, | |
955 passed, | |
956 invalid_64bit)), | |
957 invalid_64bit))); | |
1042 } | 958 } |
1043 | 959 |
1044 return msb_head; | 960 const uint32_t idx = (half == UpperHalf) ? SECCOMP_ARG_MSB_IDX(cond.argno_) |
961 : SECCOMP_ARG_LSB_IDX(cond.argno_); | |
962 const uint32_t mask = (half == UpperHalf) ? cond.mask_ >> 32 : cond.mask_; | |
963 const uint32_t value = (half == UpperHalf) ? cond.value_ >> 32 : cond.value_; | |
964 | |
965 // Emit a suitable instruction sequence for (arg & mask) == value. | |
966 | |
967 // For (arg & 0) == 0, just return passed. | |
968 if (mask == 0) { | |
969 return passed; | |
jln (very slow on Chromium)
2014/09/04 02:08:35
Shouldn't you assert that value == 0 here again? T
mdempsky
2014/09/04 17:26:48
Fair enough, done.
| |
970 } | |
971 | |
972 // For (arg & ~0) == value, emit: | |
973 // LDW [idx] | |
974 // JEQ value, passed, failed | |
975 if (mask == std::numeric_limits<uint32_t>::max()) { | |
976 return gen->MakeInstruction( | |
977 BPF_LD + BPF_W + BPF_ABS, | |
978 idx, | |
979 gen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)); | |
980 } | |
981 | |
982 // For (arg & mask) == 0, emit: | |
983 // LDW [idx] | |
984 // JSET mask, failed, passed | |
985 // (Note: failed and passed are intentionally swapped.) | |
986 if (value == 0) { | |
987 return gen->MakeInstruction( | |
988 BPF_LD + BPF_W + BPF_ABS, | |
989 idx, | |
990 gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, failed, passed)); | |
991 } | |
992 | |
993 // For (arg & x) == x where x is a single-bit value, emit: | |
994 // LDW [idx] | |
995 // JSET mask, passed, failed | |
996 if (mask == value && HasExactlyOneBit(mask)) { | |
997 return gen->MakeInstruction( | |
998 BPF_LD + BPF_W + BPF_ABS, | |
999 idx, | |
1000 gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, passed, failed)); | |
1001 } | |
1002 | |
1003 // Generic fallback: | |
1004 // LDW [idx] | |
1005 // AND mask | |
1006 // JEQ value, passed, failed | |
1007 return gen->MakeInstruction( | |
1008 BPF_LD + BPF_W + BPF_ABS, | |
1009 idx, | |
1010 gen->MakeInstruction( | |
1011 BPF_ALU + BPF_AND + BPF_K, | |
1012 mask, | |
1013 gen->MakeInstruction( | |
1014 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); | |
1045 } | 1015 } |
1046 | 1016 |
1047 ErrorCode SandboxBPF::Unexpected64bitArgument() { | 1017 ErrorCode SandboxBPF::Unexpected64bitArgument() { |
1048 return Kill("Unexpected 64bit argument detected"); | 1018 return Kill("Unexpected 64bit argument detected"); |
1049 } | 1019 } |
1050 | 1020 |
1051 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { | 1021 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { |
1052 return Trap::MakeTrap(fnc, aux, true /* Safe Trap */); | 1022 return Trap::MakeTrap(fnc, aux, true /* Safe Trap */); |
1053 } | 1023 } |
1054 | 1024 |
(...skipping 17 matching lines...) Expand all Loading... | |
1072 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) { | 1042 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) { |
1073 return Syscall::Call(args.nr, | 1043 return Syscall::Call(args.nr, |
1074 static_cast<intptr_t>(args.args[0]), | 1044 static_cast<intptr_t>(args.args[0]), |
1075 static_cast<intptr_t>(args.args[1]), | 1045 static_cast<intptr_t>(args.args[1]), |
1076 static_cast<intptr_t>(args.args[2]), | 1046 static_cast<intptr_t>(args.args[2]), |
1077 static_cast<intptr_t>(args.args[3]), | 1047 static_cast<intptr_t>(args.args[3]), |
1078 static_cast<intptr_t>(args.args[4]), | 1048 static_cast<intptr_t>(args.args[4]), |
1079 static_cast<intptr_t>(args.args[5])); | 1049 static_cast<intptr_t>(args.args[5])); |
1080 } | 1050 } |
1081 | 1051 |
1052 ErrorCode SandboxBPF::CondMaskedEqual(int argno, | |
1053 ErrorCode::ArgType width, | |
1054 uint64_t mask, | |
1055 uint64_t value, | |
1056 const ErrorCode& passed, | |
1057 const ErrorCode& failed) { | |
1058 return ErrorCode(argno, | |
1059 width, | |
1060 mask, | |
1061 value, | |
1062 &*conds_->insert(passed).first, | |
1063 &*conds_->insert(failed).first); | |
1064 } | |
1065 | |
1082 ErrorCode SandboxBPF::Cond(int argno, | 1066 ErrorCode SandboxBPF::Cond(int argno, |
1083 ErrorCode::ArgType width, | 1067 ErrorCode::ArgType width, |
1084 ErrorCode::Operation op, | 1068 ErrorCode::Operation op, |
1085 uint64_t value, | 1069 uint64_t value, |
1086 const ErrorCode& passed, | 1070 const ErrorCode& passed, |
1087 const ErrorCode& failed) { | 1071 const ErrorCode& failed) { |
1088 return ErrorCode(argno, | 1072 switch (op) { |
1089 width, | 1073 case ErrorCode::OP_EQUAL: { |
1090 op, | 1074 // Convert to "(arg & ~0) == value". |
1091 value, | 1075 const uint64_t mask = (width == ErrorCode::TP_64BIT) |
1092 &*conds_->insert(passed).first, | 1076 ? std::numeric_limits<uint64_t>::max() |
1093 &*conds_->insert(failed).first); | 1077 : std::numeric_limits<uint32_t>::max(); |
1078 return CondMaskedEqual(argno, width, mask, value, passed, failed); | |
1079 } | |
1080 case ErrorCode::OP_HAS_ALL_BITS: | |
1081 // Convert to "(arg & value) == value". | |
1082 return CondMaskedEqual(argno, width, value, value, passed, failed); | |
1083 case ErrorCode::OP_HAS_ANY_BITS: | |
1084 // Convert to "(arg & value) == 0", but swap passed and failed. | |
1085 return CondMaskedEqual(argno, width, value, 0, failed, passed); | |
1086 default: | |
1087 SANDBOX_DIE("Not implemented"); | |
1088 } | |
1094 } | 1089 } |
1095 | 1090 |
1096 ErrorCode SandboxBPF::Kill(const char* msg) { | 1091 ErrorCode SandboxBPF::Kill(const char* msg) { |
1097 return Trap(BPFFailure, const_cast<char*>(msg)); | 1092 return Trap(BPFFailure, const_cast<char*>(msg)); |
1098 } | 1093 } |
1099 | 1094 |
1100 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; | 1095 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; |
1101 | 1096 |
1102 } // namespace sandbox | 1097 } // namespace sandbox |
OLD | NEW |