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 <string.h> | |
| 6 | |
| 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 6 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" | 8 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" |
| 7 #include "sandbox/linux/seccomp-bpf/verifier.h" | 9 #include "sandbox/linux/seccomp-bpf/verifier.h" |
| 8 | 10 |
| 9 | 11 |
| 10 namespace playground2 { | 12 namespace playground2 { |
| 11 | 13 |
| 12 bool Verifier::VerifyBPF(const std::vector<struct sock_filter>& program, | 14 namespace { |
|
jln (very slow on Chromium)
2013/02/15 20:58:25
I really would rather not nest the anonymous names
| |
| 13 const Sandbox::Evaluators& evaluators, | 15 |
| 14 const char **err) { | 16 struct State { |
| 15 *err = NULL; | 17 State(const std::vector<struct sock_filter>& p, |
| 16 if (evaluators.size() != 1) { | 18 const struct arch_seccomp_data& d) : |
| 17 *err = "Not implemented"; | 19 program(p), |
| 18 return false; | 20 data(d), |
| 21 ip(0), | |
| 22 accumulator(0), | |
| 23 acc_is_valid(false) { | |
| 19 } | 24 } |
| 20 Sandbox::EvaluateSyscall evaluate_syscall = evaluators.begin()->first; | 25 const std::vector<struct sock_filter>& program; |
| 21 void *aux = evaluators.begin()->second; | 26 const struct arch_seccomp_data& data; |
| 22 for (SyscallIterator iter(false); !iter.Done(); ) { | 27 unsigned int ip; |
| 23 uint32_t sysnum = iter.Next(); | 28 uint32_t accumulator; |
| 24 // We ideally want to iterate over the full system call range and values | 29 bool acc_is_valid; |
| 25 // just above and just below this range. This gives us the full result set | 30 |
| 26 // of the "evaluators". | 31 private: |
| 27 // On Intel systems, this can fail in a surprising way, as a cleared bit 30 | 32 DISALLOW_IMPLICIT_CONSTRUCTORS(State); |
| 28 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And | 33 }; |
| 29 // unless we pay attention to setting this bit correctly, an early check in | 34 |
| 30 // our BPF program will make us fail with a misleading error code. | 35 uint32_t EvaluateErrorCode(Sandbox *sandbox, const ErrorCode& code, |
| 31 struct arch_seccomp_data data = { static_cast<int>(sysnum), | 36 const struct arch_seccomp_data& data) { |
| 32 static_cast<uint32_t>(SECCOMP_ARCH) }; | 37 if (code.error_type() == ErrorCode::ET_SIMPLE || |
| 33 #if defined(__i386__) || defined(__x86_64__) | 38 code.error_type() == ErrorCode::ET_TRAP) { |
| 34 #if defined(__x86_64__) && defined(__ILP32__) | 39 return code.err(); |
| 35 if (!(sysnum & 0x40000000u)) { | 40 } else if (code.error_type() == ErrorCode::ET_COND) { |
| 36 continue; | 41 if (code.width() == ErrorCode::TP_32BIT && |
| 42 (data.args[code.argno()] >> 32) && | |
| 43 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) != | |
| 44 0xFFFFFFFF80000000ull) { | |
| 45 return sandbox->Unexpected64bitArgument().err(); | |
| 37 } | 46 } |
| 38 #else | 47 switch (code.op()) { |
| 39 if (sysnum & 0x40000000u) { | |
| 40 continue; | |
| 41 } | |
| 42 #endif | |
| 43 #endif | |
| 44 ErrorCode code = evaluate_syscall(sysnum, aux); | |
| 45 if (!VerifyErrorCode(program, &data, code, code, err)) { | |
| 46 return false; | |
| 47 } | |
| 48 } | |
| 49 return true; | |
| 50 } | |
| 51 | |
| 52 uint32_t Verifier::EvaluateErrorCode(const ErrorCode& code, | |
| 53 const struct arch_seccomp_data& data) { | |
| 54 if (code.error_type_ == ErrorCode::ET_SIMPLE || | |
| 55 code.error_type_ == ErrorCode::ET_TRAP) { | |
| 56 return code.err_; | |
| 57 } else if (code.error_type_ == ErrorCode::ET_COND) { | |
| 58 if (code.width_ == ErrorCode::TP_32BIT && | |
| 59 (data.args[code.argno_] >> 32) && | |
| 60 (data.args[code.argno_]&0xFFFFFFFF80000000ull)!=0xFFFFFFFF80000000ull){ | |
| 61 return Sandbox::Unexpected64bitArgument().err(); | |
| 62 } | |
| 63 switch (code.op_) { | |
| 64 case ErrorCode::OP_EQUAL: | 48 case ErrorCode::OP_EQUAL: |
| 65 return EvaluateErrorCode((code.width_ == ErrorCode::TP_32BIT | 49 return EvaluateErrorCode(sandbox, |
| 66 ? uint32_t(data.args[code.argno_]) | 50 (code.width() == ErrorCode::TP_32BIT |
| 67 : data.args[code.argno_]) == code.value_ | 51 ? uint32_t(data.args[code.argno()]) |
| 68 ? *code.passed_ | 52 : data.args[code.argno()]) == code.value() |
| 69 : *code.failed_, | 53 ? *code.passed() |
| 54 : *code.failed(), | |
| 70 data); | 55 data); |
| 71 case ErrorCode::OP_HAS_ALL_BITS: | 56 case ErrorCode::OP_HAS_ALL_BITS: |
| 72 return EvaluateErrorCode(((code.width_ == ErrorCode::TP_32BIT | 57 return EvaluateErrorCode(sandbox, |
| 73 ? uint32_t(data.args[code.argno_]) | 58 ((code.width() == ErrorCode::TP_32BIT |
| 74 : data.args[code.argno_]) & code.value_) | 59 ? uint32_t(data.args[code.argno()]) |
| 75 == code.value_ | 60 : data.args[code.argno()]) & code.value()) |
| 76 ? *code.passed_ | 61 == code.value() |
| 77 : *code.failed_, | 62 ? *code.passed() |
| 63 : *code.failed(), | |
| 78 data); | 64 data); |
| 79 case ErrorCode::OP_HAS_ANY_BITS: | 65 case ErrorCode::OP_HAS_ANY_BITS: |
| 80 return EvaluateErrorCode((code.width_ == ErrorCode::TP_32BIT | 66 return EvaluateErrorCode(sandbox, |
| 81 ? uint32_t(data.args[code.argno_]) | 67 (code.width() == ErrorCode::TP_32BIT |
| 82 : data.args[code.argno_]) & code.value_ | 68 ? uint32_t(data.args[code.argno()]) |
| 83 ? *code.passed_ | 69 : data.args[code.argno()]) & code.value() |
| 84 : *code.failed_, | 70 ? *code.passed() |
| 71 : *code.failed(), | |
| 85 data); | 72 data); |
| 86 default: | 73 default: |
| 87 return SECCOMP_RET_INVALID; | 74 return SECCOMP_RET_INVALID; |
| 88 } | 75 } |
| 89 } else { | 76 } else { |
| 90 return SECCOMP_RET_INVALID; | 77 return SECCOMP_RET_INVALID; |
| 91 } | 78 } |
| 92 } | 79 } |
| 93 | 80 |
| 94 bool Verifier::VerifyErrorCode(const std::vector<struct sock_filter>& program, | 81 bool VerifyErrorCode(Sandbox *sandbox, |
| 95 struct arch_seccomp_data *data, | 82 const std::vector<struct sock_filter>& program, |
| 96 const ErrorCode& root_code, | 83 struct arch_seccomp_data *data, |
| 97 const ErrorCode& code, | 84 const ErrorCode& root_code, |
| 98 const char **err) { | 85 const ErrorCode& code, |
| 99 if (code.error_type_ == ErrorCode::ET_SIMPLE || | 86 const char **err) { |
| 100 code.error_type_ == ErrorCode::ET_TRAP) { | 87 if (code.error_type() == ErrorCode::ET_SIMPLE || |
| 101 uint32_t computed_ret = EvaluateBPF(program, *data, err); | 88 code.error_type() == ErrorCode::ET_TRAP) { |
| 89 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err); | |
| 102 if (*err) { | 90 if (*err) { |
| 103 return false; | 91 return false; |
| 104 } else if (computed_ret != EvaluateErrorCode(root_code, *data)) { | 92 } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) { |
| 105 // For efficiency's sake, we'd much rather compare "computed_ret" | 93 // For efficiency's sake, we'd much rather compare "computed_ret" |
| 106 // against "code.err_". This works most of the time, but it doesn't | 94 // against "code.err()". This works most of the time, but it doesn't |
| 107 // always work for nested conditional expressions. The test values | 95 // always work for nested conditional expressions. The test values |
| 108 // that we generate on the fly to probe expressions can trigger | 96 // that we generate on the fly to probe expressions can trigger |
| 109 // code flow decisions in multiple nodes of the decision tree, and the | 97 // code flow decisions in multiple nodes of the decision tree, and the |
| 110 // only way to compute the correct error code in that situation is by | 98 // only way to compute the correct error code in that situation is by |
| 111 // calling EvaluateErrorCode(). | 99 // calling EvaluateErrorCode(). |
| 112 *err = "Exit code from BPF program doesn't match"; | 100 *err = "Exit code from BPF program doesn't match"; |
| 113 return false; | 101 return false; |
| 114 } | 102 } |
| 115 } else if (code.error_type_ == ErrorCode::ET_COND) { | 103 } else if (code.error_type() == ErrorCode::ET_COND) { |
| 116 if (code.argno_ < 0 || code.argno_ >= 6) { | 104 if (code.argno() < 0 || code.argno() >= 6) { |
| 117 *err = "Invalid argument number in error code"; | 105 *err = "Invalid argument number in error code"; |
| 118 return false; | 106 return false; |
| 119 } | 107 } |
| 120 switch (code.op_) { | 108 switch (code.op()) { |
| 121 case ErrorCode::OP_EQUAL: | 109 case ErrorCode::OP_EQUAL: |
| 122 // Verify that we can check a 32bit value (or the LSB of a 64bit value) | 110 // Verify that we can check a 32bit value (or the LSB of a 64bit value) |
| 123 // for equality. | 111 // for equality. |
| 124 data->args[code.argno_] = code.value_; | 112 data->args[code.argno()] = code.value(); |
| 125 if (!VerifyErrorCode(program, data, root_code, *code.passed_, err)) { | 113 if (!VerifyErrorCode(sandbox, program, data, root_code, |
| 114 *code.passed(), err)) { | |
| 126 return false; | 115 return false; |
| 127 } | 116 } |
| 128 | 117 |
| 129 // Change the value to no longer match and verify that this is detected | 118 // Change the value to no longer match and verify that this is detected |
| 130 // as an inequality. | 119 // as an inequality. |
| 131 data->args[code.argno_] = code.value_ ^ 0x55AA55AA; | 120 data->args[code.argno()] = code.value() ^ 0x55AA55AA; |
| 132 if (!VerifyErrorCode(program, data, root_code, *code.failed_, err)) { | 121 if (!VerifyErrorCode(sandbox, program, data, root_code, |
| 122 *code.failed(), err)) { | |
| 133 return false; | 123 return false; |
| 134 } | 124 } |
| 135 | 125 |
| 136 // BPF programs can only ever operate on 32bit values. So, we have | 126 // BPF programs can only ever operate on 32bit values. So, we have |
| 137 // generated additional BPF instructions that inspect the MSB. Verify | 127 // generated additional BPF instructions that inspect the MSB. Verify |
| 138 // that they behave as intended. | 128 // that they behave as intended. |
| 139 if (code.width_ == ErrorCode::TP_32BIT) { | 129 if (code.width() == ErrorCode::TP_32BIT) { |
| 140 if (code.value_ >> 32) { | 130 if (code.value() >> 32) { |
| 141 SANDBOX_DIE("Invalid comparison of a 32bit system call argument " | 131 SANDBOX_DIE("Invalid comparison of a 32bit system call argument " |
| 142 "against a 64bit constant; this test is always false."); | 132 "against a 64bit constant; this test is always false."); |
| 143 } | 133 } |
| 144 | 134 |
| 145 // If the system call argument was intended to be a 32bit parameter, | 135 // If the system call argument was intended to be a 32bit parameter, |
| 146 // verify that it is a fatal error if a 64bit value is ever passed | 136 // verify that it is a fatal error if a 64bit value is ever passed |
| 147 // here. | 137 // here. |
| 148 data->args[code.argno_] = 0x100000000ull; | 138 data->args[code.argno()] = 0x100000000ull; |
| 149 if (!VerifyErrorCode(program, data, root_code, | 139 if (!VerifyErrorCode(sandbox, program, data, root_code, |
| 150 Sandbox::Unexpected64bitArgument(), err)) { | 140 sandbox->Unexpected64bitArgument(), |
| 141 err)) { | |
| 151 return false; | 142 return false; |
| 152 } | 143 } |
| 153 } else { | 144 } else { |
| 154 // If the system call argument was intended to be a 64bit parameter, | 145 // If the system call argument was intended to be a 64bit parameter, |
| 155 // verify that we can handle (in-)equality for the MSB. This is | 146 // verify that we can handle (in-)equality for the MSB. This is |
| 156 // essentially the same test that we did earlier for the LSB. | 147 // essentially the same test that we did earlier for the LSB. |
| 157 // We only need to verify the behavior of the inequality test. We | 148 // We only need to verify the behavior of the inequality test. We |
| 158 // know that the equality test already passed, as unlike the kernel | 149 // know that the equality test already passed, as unlike the kernel |
| 159 // the Verifier does operate on 64bit quantities. | 150 // the Verifier does operate on 64bit quantities. |
| 160 data->args[code.argno_] = code.value_ ^ 0x55AA55AA00000000ull; | 151 data->args[code.argno()] = code.value() ^ 0x55AA55AA00000000ull; |
| 161 if (!VerifyErrorCode(program, data, root_code, *code.failed_, err)) { | 152 if (!VerifyErrorCode(sandbox, program, data, root_code, |
| 153 *code.failed(), err)) { | |
| 162 return false; | 154 return false; |
| 163 } | 155 } |
| 164 } | 156 } |
| 165 break; | 157 break; |
| 166 case ErrorCode::OP_HAS_ALL_BITS: | 158 case ErrorCode::OP_HAS_ALL_BITS: |
| 167 case ErrorCode::OP_HAS_ANY_BITS: | 159 case ErrorCode::OP_HAS_ANY_BITS: |
| 168 // A comprehensive test of bit values is difficult and potentially rather | 160 // A comprehensive test of bit values is difficult and potentially rather |
| 169 // time-expensive. We avoid doing so at run-time and instead rely on the | 161 // time-expensive. We avoid doing so at run-time and instead rely on the |
| 170 // unittest for full testing. The test that we have here covers just the | 162 // unittest for full testing. The test that we have here covers just the |
| 171 // common cases. We test against the bitmask itself, all zeros and all | 163 // common cases. We test against the bitmask itself, all zeros and all |
| 172 // ones. | 164 // ones. |
| 173 { | 165 { |
| 174 // Testing "any" bits against a zero mask is always false. So, there | 166 // Testing "any" bits against a zero mask is always false. So, there |
| 175 // are some cases, where we expect tests to take the "failed_" branch | 167 // are some cases, where we expect tests to take the "failed()" branch |
| 176 // even though this is a test that normally should take "passed_". | 168 // even though this is a test that normally should take "passed()". |
| 177 const ErrorCode& passed = | 169 const ErrorCode& passed = |
| 178 (!code.value_ && code.op_ == ErrorCode::OP_HAS_ANY_BITS) || | 170 (!code.value() && code.op() == ErrorCode::OP_HAS_ANY_BITS) || |
| 179 | 171 |
| 180 // On a 32bit system, it is impossible to pass a 64bit value as a | 172 // On a 32bit system, it is impossible to pass a 64bit value as a |
| 181 // system call argument. So, some additional tests always evaluate | 173 // system call argument. So, some additional tests always evaluate |
| 182 // as false. | 174 // as false. |
| 183 ((code.value_ & ~uint64_t(uintptr_t(-1))) && | 175 ((code.value() & ~uint64_t(uintptr_t(-1))) && |
| 184 code.op_ == ErrorCode::OP_HAS_ALL_BITS) || | 176 code.op() == ErrorCode::OP_HAS_ALL_BITS) || |
| 185 (code.value_ && !(code.value_ & uintptr_t(-1)) && | 177 (code.value() && !(code.value() & uintptr_t(-1)) && |
| 186 code.op_ == ErrorCode::OP_HAS_ANY_BITS) | 178 code.op() == ErrorCode::OP_HAS_ANY_BITS) |
| 187 | 179 |
| 188 ? *code.failed_ : *code.passed_; | 180 ? *code.failed() : *code.passed(); |
| 189 | 181 |
| 190 // Similary, testing for "all" bits in a zero mask is always true. So, | 182 // Similary, testing for "all" bits in a zero mask is always true. So, |
| 191 // some cases pass despite them normally failing. | 183 // some cases pass despite them normally failing. |
| 192 const ErrorCode& failed = | 184 const ErrorCode& failed = |
| 193 !code.value_ && code.op_ == ErrorCode::OP_HAS_ALL_BITS | 185 !code.value() && code.op() == ErrorCode::OP_HAS_ALL_BITS |
| 194 ? *code.passed_ : *code.failed_; | 186 ? *code.passed() : *code.failed(); |
| 195 | 187 |
| 196 data->args[code.argno_] = code.value_ & uintptr_t(-1); | 188 data->args[code.argno()] = code.value() & uintptr_t(-1); |
| 197 if (!VerifyErrorCode(program, data, root_code, passed, err)) { | 189 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) { |
| 198 return false; | 190 return false; |
| 199 } | 191 } |
| 200 data->args[code.argno_] = uintptr_t(-1); | 192 data->args[code.argno()] = uintptr_t(-1); |
| 201 if (!VerifyErrorCode(program, data, root_code, passed, err)) { | 193 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) { |
| 202 return false; | 194 return false; |
| 203 } | 195 } |
| 204 data->args[code.argno_] = 0; | 196 data->args[code.argno()] = 0; |
| 205 if (!VerifyErrorCode(program, data, root_code, failed, err)) { | 197 if (!VerifyErrorCode(sandbox, program, data, root_code, failed, err)) { |
| 206 return false; | 198 return false; |
| 207 } | 199 } |
| 208 } | 200 } |
| 209 break; | 201 break; |
| 210 default: // TODO(markus): Need to add support for OP_GREATER | 202 default: // TODO(markus): Need to add support for OP_GREATER |
| 211 *err = "Unsupported operation in conditional error code"; | 203 *err = "Unsupported operation in conditional error code"; |
| 212 return false; | 204 return false; |
| 213 } | 205 } |
| 214 } else { | 206 } else { |
| 215 *err = "Attempting to return invalid error code from BPF program"; | 207 *err = "Attempting to return invalid error code from BPF program"; |
| 216 return false; | 208 return false; |
| 217 } | 209 } |
| 218 return true; | 210 return true; |
| 219 } | 211 } |
| 220 | 212 |
| 221 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, | 213 void Ld(State *state, const struct sock_filter& insn, const char **err) { |
| 222 const struct arch_seccomp_data& data, | |
| 223 const char **err) { | |
| 224 *err = NULL; | |
| 225 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { | |
| 226 *err = "Invalid program length"; | |
| 227 return 0; | |
| 228 } | |
| 229 for (State state(program, data); !*err; ++state.ip) { | |
| 230 if (state.ip >= program.size()) { | |
| 231 *err = "Invalid instruction pointer in BPF program"; | |
| 232 break; | |
| 233 } | |
| 234 const struct sock_filter& insn = program[state.ip]; | |
| 235 switch (BPF_CLASS(insn.code)) { | |
| 236 case BPF_LD: | |
| 237 Ld(&state, insn, err); | |
| 238 break; | |
| 239 case BPF_JMP: | |
| 240 Jmp(&state, insn, err); | |
| 241 break; | |
| 242 case BPF_RET: { | |
| 243 uint32_t r = Ret(&state, insn, err); | |
| 244 switch (r & SECCOMP_RET_ACTION) { | |
| 245 case SECCOMP_RET_TRAP: | |
| 246 case SECCOMP_RET_ERRNO: | |
| 247 case SECCOMP_RET_ALLOW: | |
| 248 break; | |
| 249 case SECCOMP_RET_KILL: // We don't ever generate this | |
| 250 case SECCOMP_RET_TRACE: // We don't ever generate this | |
| 251 case SECCOMP_RET_INVALID: // Should never show up in BPF program | |
| 252 default: | |
| 253 *err = "Unexpected return code found in BPF program"; | |
| 254 return 0; | |
| 255 } | |
| 256 return r; } | |
| 257 case BPF_ALU: | |
| 258 Alu(&state, insn, err); | |
| 259 break; | |
| 260 default: | |
| 261 *err = "Unexpected instruction in BPF program"; | |
| 262 break; | |
| 263 } | |
| 264 } | |
| 265 return 0; | |
| 266 } | |
| 267 | |
| 268 void Verifier::Ld(State *state, const struct sock_filter& insn, | |
| 269 const char **err) { | |
| 270 if (BPF_SIZE(insn.code) != BPF_W || | 214 if (BPF_SIZE(insn.code) != BPF_W || |
| 271 BPF_MODE(insn.code) != BPF_ABS) { | 215 BPF_MODE(insn.code) != BPF_ABS) { |
| 272 *err = "Invalid BPF_LD instruction"; | 216 *err = "Invalid BPF_LD instruction"; |
| 273 return; | 217 return; |
| 274 } | 218 } |
| 275 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { | 219 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { |
| 276 // We only allow loading of properly aligned 32bit quantities. | 220 // We only allow loading of properly aligned 32bit quantities. |
| 277 memcpy(&state->accumulator, | 221 memcpy(&state->accumulator, |
| 278 reinterpret_cast<const char *>(&state->data) + insn.k, | 222 reinterpret_cast<const char *>(&state->data) + insn.k, |
| 279 4); | 223 4); |
| 280 } else { | 224 } else { |
| 281 *err = "Invalid operand in BPF_LD instruction"; | 225 *err = "Invalid operand in BPF_LD instruction"; |
| 282 return; | 226 return; |
| 283 } | 227 } |
| 284 state->acc_is_valid = true; | 228 state->acc_is_valid = true; |
| 285 return; | 229 return; |
| 286 } | 230 } |
| 287 | 231 |
| 288 void Verifier::Jmp(State *state, const struct sock_filter& insn, | 232 void Jmp(State *state, const struct sock_filter& insn, const char **err) { |
| 289 const char **err) { | |
| 290 if (BPF_OP(insn.code) == BPF_JA) { | 233 if (BPF_OP(insn.code) == BPF_JA) { |
| 291 if (state->ip + insn.k + 1 >= state->program.size() || | 234 if (state->ip + insn.k + 1 >= state->program.size() || |
| 292 state->ip + insn.k + 1 <= state->ip) { | 235 state->ip + insn.k + 1 <= state->ip) { |
| 293 compilation_failure: | 236 compilation_failure: |
| 294 *err = "Invalid BPF_JMP instruction"; | 237 *err = "Invalid BPF_JMP instruction"; |
| 295 return; | 238 return; |
| 296 } | 239 } |
| 297 state->ip += insn.k; | 240 state->ip += insn.k; |
| 298 } else { | 241 } else { |
| 299 if (BPF_SRC(insn.code) != BPF_K || | 242 if (BPF_SRC(insn.code) != BPF_K || |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 330 } else { | 273 } else { |
| 331 state->ip += insn.jf; | 274 state->ip += insn.jf; |
| 332 } | 275 } |
| 333 break; | 276 break; |
| 334 default: | 277 default: |
| 335 goto compilation_failure; | 278 goto compilation_failure; |
| 336 } | 279 } |
| 337 } | 280 } |
| 338 } | 281 } |
| 339 | 282 |
| 340 uint32_t Verifier::Ret(State *, const struct sock_filter& insn, | 283 uint32_t Ret(State *, const struct sock_filter& insn, const char **err) { |
| 341 const char **err) { | |
| 342 if (BPF_SRC(insn.code) != BPF_K) { | 284 if (BPF_SRC(insn.code) != BPF_K) { |
| 343 *err = "Invalid BPF_RET instruction"; | 285 *err = "Invalid BPF_RET instruction"; |
| 344 return 0; | 286 return 0; |
| 345 } | 287 } |
| 346 return insn.k; | 288 return insn.k; |
| 347 } | 289 } |
| 348 | 290 |
| 349 void Verifier::Alu(State *state, const struct sock_filter& insn, | 291 void Alu(State *state, const struct sock_filter& insn, const char **err) { |
| 350 const char **err) { | |
| 351 if (BPF_OP(insn.code) == BPF_NEG) { | 292 if (BPF_OP(insn.code) == BPF_NEG) { |
| 352 state->accumulator = -state->accumulator; | 293 state->accumulator = -state->accumulator; |
| 353 return; | 294 return; |
| 354 } else { | 295 } else { |
| 355 if (BPF_SRC(insn.code) != BPF_K) { | 296 if (BPF_SRC(insn.code) != BPF_K) { |
| 356 *err = "Unexpected source operand in arithmetic operation"; | 297 *err = "Unexpected source operand in arithmetic operation"; |
| 357 return; | 298 return; |
| 358 } | 299 } |
| 359 switch (BPF_OP(insn.code)) { | 300 switch (BPF_OP(insn.code)) { |
| 360 case BPF_ADD: | 301 case BPF_ADD: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 403 } | 344 } |
| 404 state->accumulator >>= insn.k; | 345 state->accumulator >>= insn.k; |
| 405 break; | 346 break; |
| 406 default: | 347 default: |
| 407 *err = "Invalid operator in arithmetic operation"; | 348 *err = "Invalid operator in arithmetic operation"; |
| 408 break; | 349 break; |
| 409 } | 350 } |
| 410 } | 351 } |
| 411 } | 352 } |
| 412 | 353 |
| 354 } // namespace | |
| 355 | |
| 356 bool Verifier::VerifyBPF(Sandbox *sandbox, | |
| 357 const std::vector<struct sock_filter>& program, | |
| 358 const Sandbox::Evaluators& evaluators, | |
| 359 const char **err) { | |
| 360 *err = NULL; | |
| 361 if (evaluators.size() != 1) { | |
| 362 *err = "Not implemented"; | |
| 363 return false; | |
| 364 } | |
| 365 Sandbox::EvaluateSyscall evaluate_syscall = evaluators.begin()->first; | |
| 366 void *aux = evaluators.begin()->second; | |
| 367 for (SyscallIterator iter(false); !iter.Done(); ) { | |
| 368 uint32_t sysnum = iter.Next(); | |
| 369 // We ideally want to iterate over the full system call range and values | |
| 370 // just above and just below this range. This gives us the full result set | |
| 371 // of the "evaluators". | |
| 372 // On Intel systems, this can fail in a surprising way, as a cleared bit 30 | |
| 373 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And | |
| 374 // unless we pay attention to setting this bit correctly, an early check in | |
| 375 // our BPF program will make us fail with a misleading error code. | |
| 376 struct arch_seccomp_data data = { static_cast<int>(sysnum), | |
| 377 static_cast<uint32_t>(SECCOMP_ARCH) }; | |
| 378 #if defined(__i386__) || defined(__x86_64__) | |
| 379 #if defined(__x86_64__) && defined(__ILP32__) | |
| 380 if (!(sysnum & 0x40000000u)) { | |
| 381 continue; | |
| 382 } | |
| 383 #else | |
| 384 if (sysnum & 0x40000000u) { | |
| 385 continue; | |
| 386 } | |
| 387 #endif | |
| 388 #endif | |
| 389 ErrorCode code = evaluate_syscall(sandbox, sysnum, aux); | |
| 390 if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) { | |
| 391 return false; | |
| 392 } | |
| 393 } | |
| 394 return true; | |
| 395 } | |
| 396 | |
| 397 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, | |
| 398 const struct arch_seccomp_data& data, | |
| 399 const char **err) { | |
| 400 *err = NULL; | |
| 401 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { | |
| 402 *err = "Invalid program length"; | |
| 403 return 0; | |
| 404 } | |
| 405 for (State state(program, data); !*err; ++state.ip) { | |
| 406 if (state.ip >= program.size()) { | |
| 407 *err = "Invalid instruction pointer in BPF program"; | |
| 408 break; | |
| 409 } | |
| 410 const struct sock_filter& insn = program[state.ip]; | |
| 411 switch (BPF_CLASS(insn.code)) { | |
| 412 case BPF_LD: | |
| 413 Ld(&state, insn, err); | |
| 414 break; | |
| 415 case BPF_JMP: | |
| 416 Jmp(&state, insn, err); | |
| 417 break; | |
| 418 case BPF_RET: { | |
| 419 uint32_t r = Ret(&state, insn, err); | |
| 420 switch (r & SECCOMP_RET_ACTION) { | |
| 421 case SECCOMP_RET_TRAP: | |
| 422 case SECCOMP_RET_ERRNO: | |
| 423 case SECCOMP_RET_ALLOW: | |
| 424 break; | |
| 425 case SECCOMP_RET_KILL: // We don't ever generate this | |
| 426 case SECCOMP_RET_TRACE: // We don't ever generate this | |
| 427 case SECCOMP_RET_INVALID: // Should never show up in BPF program | |
| 428 default: | |
| 429 *err = "Unexpected return code found in BPF program"; | |
| 430 return 0; | |
| 431 } | |
| 432 return r; } | |
| 433 case BPF_ALU: | |
| 434 Alu(&state, insn, err); | |
| 435 break; | |
| 436 default: | |
| 437 *err = "Unexpected instruction in BPF program"; | |
| 438 break; | |
| 439 } | |
| 440 } | |
| 441 return 0; | |
| 442 } | |
| 413 | 443 |
| 414 } // namespace | 444 } // namespace |
|
jln (very slow on Chromium)
2013/02/15 20:58:25
namespace playground 2
| |
| OLD | NEW |