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 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
855 | 858 |
856 Instruction* SandboxBPF::RetExpression(CodeGen* gen, const ErrorCode& err) { | 859 Instruction* SandboxBPF::RetExpression(CodeGen* gen, const ErrorCode& err) { |
857 if (err.error_type_ == ErrorCode::ET_COND) { | 860 if (err.error_type_ == ErrorCode::ET_COND) { |
858 return CondExpression(gen, err); | 861 return CondExpression(gen, err); |
859 } else { | 862 } else { |
860 return gen->MakeInstruction(BPF_RET + BPF_K, err); | 863 return gen->MakeInstruction(BPF_RET + BPF_K, err); |
861 } | 864 } |
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 // Sanity check that |cond| makes sense. |
866 // CPU registers. | |
867 if (cond.argno_ < 0 || cond.argno_ >= 6) { | 869 if (cond.argno_ < 0 || cond.argno_ >= 6) { |
868 SANDBOX_DIE( | 870 SANDBOX_DIE("sandbox_bpf: invalid argument number"); |
869 "Internal compiler error; invalid argument number " | 871 } |
870 "encountered"); | 872 if (cond.width_ != ErrorCode::TP_32BIT && |
873 cond.width_ != ErrorCode::TP_64BIT) { | |
874 SANDBOX_DIE("sandbox_bpf: invalid argument width"); | |
875 } | |
876 if (cond.mask_ == 0) { | |
877 SANDBOX_DIE("sandbox_bpf: zero mask is invalid"); | |
878 } | |
879 if ((cond.value_ & cond.mask_) != cond.value_) { | |
880 SANDBOX_DIE("sandbox_bpf: value contains masked out bits"); | |
881 } | |
882 if (cond.width_ == ErrorCode::TP_32BIT && | |
883 ((cond.mask_ >> 32) != 0 || (cond.value_ >> 32) != 0)) { | |
884 SANDBOX_DIE("sandbox_bpf: test exceeds argument size"); | |
885 } | |
886 // TODO(mdempsky): Reject TP_64BIT on 32-bit platforms. For now we allow it | |
887 // because some SandboxBPF unit tests exercise it. | |
jln (very slow on Chromium)
2014/09/04 21:45:06
TP_64BIT is actually the right default most of the
| |
888 | |
889 Instruction* passed = RetExpression(gen, *cond.passed_); | |
890 Instruction* failed = RetExpression(gen, *cond.failed_); | |
891 | |
892 // We want to emit code to check "(arg & mask) == value" where arg, mask, and | |
893 // value are 64-bit values, but the BPF machine is only 32-bit. We implement | |
894 // this by independently testing the upper and lower 32-bits and continuing to | |
895 // |passed| if both evaluate true, or to |failed| if either evaluate false. | |
896 return CondExpressionHalf( | |
897 gen, | |
898 cond, | |
899 UpperHalf, | |
900 CondExpressionHalf(gen, cond, LowerHalf, passed, failed), | |
901 failed); | |
902 } | |
903 | |
904 Instruction* SandboxBPF::CondExpressionHalf(CodeGen* gen, | |
905 const ErrorCode& cond, | |
906 ArgHalf half, | |
907 Instruction* passed, | |
908 Instruction* failed) { | |
909 if (cond.width_ == ErrorCode::TP_32BIT && half == UpperHalf) { | |
910 // Special logic for sanity checking the upper 32-bits of 32-bit system | |
911 // call arguments. | |
912 | |
913 // TODO(mdempsky): Compile Unexpected64bitArgument() just per program. | |
914 Instruction* invalid_64bit = RetExpression(gen, Unexpected64bitArgument()); | |
915 | |
916 const uint32_t upper = SECCOMP_ARG_MSB_IDX(cond.argno_); | |
917 const uint32_t lower = SECCOMP_ARG_LSB_IDX(cond.argno_); | |
918 | |
919 if (sizeof(void*) == 4) { | |
920 // On 32-bit platforms, the upper 32-bits should always be 0: | |
921 // LDW [upper] | |
922 // JEQ 0, passed, invalid | |
923 return gen->MakeInstruction( | |
924 BPF_LD + BPF_W + BPF_ABS, | |
925 upper, | |
926 gen->MakeInstruction( | |
927 BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit)); | |
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, | |
943 gen->MakeInstruction( | |
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))); | |
871 } | 958 } |
872 | 959 |
873 // BPF programs operate on 32bit entities. Load both halfs of the 64bit | 960 const uint32_t idx = (half == UpperHalf) ? SECCOMP_ARG_MSB_IDX(cond.argno_) |
874 // system call argument and then generate suitable conditional statements. | 961 : SECCOMP_ARG_LSB_IDX(cond.argno_); |
875 Instruction* msb_head = gen->MakeInstruction( | 962 const uint32_t mask = (half == UpperHalf) ? cond.mask_ >> 32 : cond.mask_; |
876 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARG_MSB_IDX(cond.argno_)); | 963 const uint32_t value = (half == UpperHalf) ? cond.value_ >> 32 : cond.value_; |
877 Instruction* msb_tail = msb_head; | |
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 | 964 |
882 // Emit a suitable comparison statement. | 965 // Emit a suitable instruction sequence for (arg & mask) == value. |
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 | 966 |
892 // If we are looking at a 64bit argument, we need to also compare the | 967 // For (arg & 0) == 0, just return passed. |
893 // most significant bits. | 968 if (mask == 0) { |
894 if (cond.width_ == ErrorCode::TP_64BIT) { | 969 CHECK_EQ(0U, value); |
895 msb_tail = | 970 return passed; |
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 } | 971 } |
1013 | 972 |
1014 // Ensure that we never pass a 64bit value, when we only expect a 32bit | 973 // For (arg & ~0) == value, emit: |
1015 // value. This is somewhat complicated by the fact that on 64bit systems, | 974 // LDW [idx] |
1016 // callers could legitimately pass in a non-zero value in the MSB, iff the | 975 // JEQ value, passed, failed |
1017 // LSB has been sign-extended into the MSB. | 976 if (mask == std::numeric_limits<uint32_t>::max()) { |
1018 if (cond.width_ == ErrorCode::TP_32BIT) { | 977 return gen->MakeInstruction( |
1019 if (cond.value_ >> 32) { | 978 BPF_LD + BPF_W + BPF_ABS, |
1020 SANDBOX_DIE( | 979 idx, |
1021 "Invalid comparison of a 32bit system call argument " | 980 gen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)); |
1022 "against a 64bit constant; this test is always false."); | |
1023 } | |
1024 | |
1025 Instruction* invalid_64bit = RetExpression(gen, Unexpected64bitArgument()); | |
1026 #if __SIZEOF_POINTER__ > 4 | |
1027 invalid_64bit = gen->MakeInstruction( | |
1028 BPF_JMP + BPF_JEQ + BPF_K, | |
1029 0xFFFFFFFF, | |
1030 gen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, | |
1031 SECCOMP_ARG_LSB_IDX(cond.argno_), | |
1032 gen->MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, | |
1033 0x80000000, | |
1034 lsb_head, | |
1035 invalid_64bit)), | |
1036 invalid_64bit); | |
1037 #endif | |
1038 gen->JoinInstructions( | |
1039 msb_tail, | |
1040 gen->MakeInstruction( | |
1041 BPF_JMP + BPF_JEQ + BPF_K, 0, lsb_head, invalid_64bit)); | |
1042 } | 981 } |
1043 | 982 |
1044 return msb_head; | 983 // For (arg & mask) == 0, emit: |
984 // LDW [idx] | |
985 // JSET mask, failed, passed | |
986 // (Note: failed and passed are intentionally swapped.) | |
987 if (value == 0) { | |
988 return gen->MakeInstruction( | |
989 BPF_LD + BPF_W + BPF_ABS, | |
990 idx, | |
991 gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, failed, passed)); | |
992 } | |
993 | |
994 // For (arg & x) == x where x is a single-bit value, emit: | |
995 // LDW [idx] | |
996 // JSET mask, passed, failed | |
997 if (mask == value && HasExactlyOneBit(mask)) { | |
998 return gen->MakeInstruction( | |
999 BPF_LD + BPF_W + BPF_ABS, | |
1000 idx, | |
1001 gen->MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, passed, failed)); | |
1002 } | |
1003 | |
1004 // Generic fallback: | |
1005 // LDW [idx] | |
1006 // AND mask | |
1007 // JEQ value, passed, failed | |
1008 return gen->MakeInstruction( | |
1009 BPF_LD + BPF_W + BPF_ABS, | |
1010 idx, | |
1011 gen->MakeInstruction( | |
1012 BPF_ALU + BPF_AND + BPF_K, | |
1013 mask, | |
1014 gen->MakeInstruction( | |
1015 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); | |
1045 } | 1016 } |
1046 | 1017 |
1047 ErrorCode SandboxBPF::Unexpected64bitArgument() { | 1018 ErrorCode SandboxBPF::Unexpected64bitArgument() { |
1048 return Kill("Unexpected 64bit argument detected"); | 1019 return Kill("Unexpected 64bit argument detected"); |
1049 } | 1020 } |
1050 | 1021 |
1051 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { | 1022 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { |
1052 return Trap::MakeTrap(fnc, aux, true /* Safe Trap */); | 1023 return Trap::MakeTrap(fnc, aux, true /* Safe Trap */); |
1053 } | 1024 } |
1054 | 1025 |
(...skipping 17 matching lines...) Expand all Loading... | |
1072 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) { | 1043 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) { |
1073 return Syscall::Call(args.nr, | 1044 return Syscall::Call(args.nr, |
1074 static_cast<intptr_t>(args.args[0]), | 1045 static_cast<intptr_t>(args.args[0]), |
1075 static_cast<intptr_t>(args.args[1]), | 1046 static_cast<intptr_t>(args.args[1]), |
1076 static_cast<intptr_t>(args.args[2]), | 1047 static_cast<intptr_t>(args.args[2]), |
1077 static_cast<intptr_t>(args.args[3]), | 1048 static_cast<intptr_t>(args.args[3]), |
1078 static_cast<intptr_t>(args.args[4]), | 1049 static_cast<intptr_t>(args.args[4]), |
1079 static_cast<intptr_t>(args.args[5])); | 1050 static_cast<intptr_t>(args.args[5])); |
1080 } | 1051 } |
1081 | 1052 |
1053 ErrorCode SandboxBPF::CondMaskedEqual(int argno, | |
1054 ErrorCode::ArgType width, | |
1055 uint64_t mask, | |
1056 uint64_t value, | |
1057 const ErrorCode& passed, | |
1058 const ErrorCode& failed) { | |
1059 return ErrorCode(argno, | |
1060 width, | |
1061 mask, | |
1062 value, | |
1063 &*conds_->insert(passed).first, | |
1064 &*conds_->insert(failed).first); | |
1065 } | |
1066 | |
1082 ErrorCode SandboxBPF::Cond(int argno, | 1067 ErrorCode SandboxBPF::Cond(int argno, |
1083 ErrorCode::ArgType width, | 1068 ErrorCode::ArgType width, |
1084 ErrorCode::Operation op, | 1069 ErrorCode::Operation op, |
1085 uint64_t value, | 1070 uint64_t value, |
1086 const ErrorCode& passed, | 1071 const ErrorCode& passed, |
1087 const ErrorCode& failed) { | 1072 const ErrorCode& failed) { |
1088 return ErrorCode(argno, | 1073 // CondExpression() currently rejects mask==0 as invalid, but there are |
1089 width, | 1074 // SandboxBPF unit tests that (questionably) expect OP_HAS_{ANY,ALL}_BITS to |
1090 op, | 1075 // work with value==0. To keep those tests working for now, we specially |
1091 value, | 1076 // convert value==0 here. |
1092 &*conds_->insert(passed).first, | 1077 |
1093 &*conds_->insert(failed).first); | 1078 switch (op) { |
1079 case ErrorCode::OP_EQUAL: { | |
1080 // Convert to "(arg & ~0) == value". | |
1081 const uint64_t mask = (width == ErrorCode::TP_64BIT) | |
1082 ? std::numeric_limits<uint64_t>::max() | |
1083 : std::numeric_limits<uint32_t>::max(); | |
1084 return CondMaskedEqual(argno, width, mask, value, passed, failed); | |
1085 } | |
1086 | |
1087 case ErrorCode::OP_HAS_ALL_BITS: | |
1088 if (value == 0) { | |
1089 // Always passes. | |
1090 return passed; | |
1091 } | |
1092 // Convert to "(arg & value) == value". | |
1093 return CondMaskedEqual(argno, width, value, value, passed, failed); | |
1094 | |
1095 case ErrorCode::OP_HAS_ANY_BITS: | |
1096 if (value == 0) { | |
1097 // Always fails. | |
1098 return failed; | |
1099 } | |
1100 // Convert to "(arg & value) == 0", but swap passed and failed. | |
1101 return CondMaskedEqual(argno, width, value, 0, failed, passed); | |
1102 | |
1103 default: | |
1104 SANDBOX_DIE("Not implemented"); | |
1105 } | |
1094 } | 1106 } |
1095 | 1107 |
1096 ErrorCode SandboxBPF::Kill(const char* msg) { | 1108 ErrorCode SandboxBPF::Kill(const char* msg) { |
1097 return Trap(BPFFailure, const_cast<char*>(msg)); | 1109 return Trap(BPFFailure, const_cast<char*>(msg)); |
1098 } | 1110 } |
1099 | 1111 |
1100 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; | 1112 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; |
1101 | 1113 |
1102 } // namespace sandbox | 1114 } // namespace sandbox |
OLD | NEW |