Chromium Code Reviews| 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 |