Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | |
| 6 #include "sandbox/linux/seccomp-bpf/verifier.h" | |
| 7 | |
| 8 | |
| 9 namespace playground2 { | |
| 10 | |
| 11 bool Verifier::verifyBPF(const std::vector<struct sock_filter>& program, | |
| 12 const Sandbox::Evaluators& evaluators, | |
| 13 const char **err) { | |
| 14 if (evaluators.size() != 1) { | |
|
jln (very slow on Chromium)
2012/06/08 19:28:22
Can you also check for !err ?
Markus (顧孟勤)
2012/06/08 20:04:24
I was originally intending to make error reporting
| |
| 15 *err = "Not implemented"; | |
| 16 return false; | |
| 17 } | |
| 18 Sandbox::EvaluateSyscall evaluateSyscall = evaluators.begin()->first; | |
| 19 for (int nr = MIN_SYSCALL-1; nr <= MAX_SYSCALL+1; ++nr) { | |
| 20 // We ideally want to iterate over the full system call range and values | |
| 21 // just above and just below this range. This gives us the full result set | |
| 22 // of the "evaluators". | |
| 23 // On Intel systems, this can fail in a surprising way, as a cleared bit 30 | |
| 24 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And | |
| 25 // unless we pay attention to setting this bit correctly, an early check in | |
| 26 // our BPF program will make us fail with a misleading error code. | |
| 27 #if defined(__i386__) || defined(__x86_64__) | |
| 28 #if defined(__x86_64__) && defined(__ILP32__) | |
| 29 int sysnum = nr | 0x40000000; | |
| 30 #else | |
| 31 int sysnum = nr & ~0x40000000; | |
| 32 #endif | |
| 33 #else | |
| 34 int sysnum = nr; | |
| 35 #endif | |
| 36 | |
| 37 struct arch_seccomp_data data = { sysnum, SECCOMP_ARCH }; | |
| 38 uint32_t expectedRet; | |
| 39 Sandbox::ErrorCode code = evaluateSyscall(sysnum); | |
| 40 switch (code) { | |
| 41 case Sandbox::SB_TRAP: | |
| 42 expectedRet = SECCOMP_RET_TRAP; | |
| 43 break; | |
| 44 case Sandbox::SB_ALLOWED: | |
| 45 expectedRet = SECCOMP_RET_ALLOW; | |
| 46 break; | |
| 47 case Sandbox::SB_INSPECT_ARG_1...Sandbox::SB_INSPECT_ARG_6: | |
| 48 *err = "Not implemented"; | |
| 49 return false; | |
| 50 default: | |
| 51 if (code >= 1 && code < 4096) { | |
| 52 expectedRet = SECCOMP_RET_ERRNO + static_cast<int>(code); | |
| 53 } else { | |
| 54 *err = "Invalid errno value"; | |
| 55 return false; | |
| 56 } | |
| 57 break; | |
| 58 } | |
| 59 const char *e; | |
| 60 uint32_t computedRet = evaluateBPF(program, data, &e); | |
| 61 if (e) { | |
| 62 *err = e; | |
| 63 return false; | |
| 64 } else if (computedRet != expectedRet) { | |
| 65 *err = "Exit code from BPF program doesn't match"; | |
| 66 return false; | |
| 67 } | |
| 68 } | |
| 69 return true; | |
| 70 } | |
| 71 | |
| 72 uint32_t Verifier::evaluateBPF(const std::vector<struct sock_filter>& program, | |
| 73 const struct arch_seccomp_data& data, | |
| 74 const char **err) { | |
| 75 *err = NULL; | |
|
jln (very slow on Chromium)
2012/06/08 19:28:22
Check !err here too ? (as this is part of the inte
| |
| 76 for (State state(program, data); !*err; ++state.ip) { | |
| 77 if (state.ip >= program.size()) { | |
| 78 *err = "Invalid instruction pointer in BPF program"; | |
| 79 break; | |
| 80 } | |
| 81 const struct sock_filter& insn = program[state.ip]; | |
| 82 switch (BPF_CLASS(insn.code)) { | |
| 83 case BPF_LD: | |
| 84 ld(&state, insn, err); | |
| 85 break; | |
| 86 case BPF_JMP: | |
| 87 jmp(&state, insn, err); | |
| 88 break; | |
| 89 case BPF_RET: | |
| 90 return ret(&state, insn, err); | |
| 91 default: | |
| 92 *err = "Unexpected instruction in BPF program"; | |
| 93 break; | |
| 94 } | |
| 95 } | |
| 96 return 0; | |
| 97 } | |
| 98 | |
| 99 void Verifier::ld(State *state, const struct sock_filter& insn, | |
| 100 const char **err) { | |
| 101 if (BPF_SIZE(insn.code) != BPF_W || | |
| 102 BPF_MODE(insn.code) != BPF_ABS) { | |
| 103 *err = "Invalid BPF_LD instruction"; | |
| 104 return; | |
| 105 } | |
| 106 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { | |
| 107 // We only allow loading of properly aligned 32bit quantities. | |
| 108 memcpy(&state->accumulator, | |
| 109 reinterpret_cast<const char *>(&state->data) + insn.k, | |
| 110 4); | |
| 111 } else { | |
| 112 *err = "Invalid operand in BPF_LD instruction"; | |
| 113 return; | |
| 114 } | |
| 115 state->accIsValid = true; | |
| 116 return; | |
| 117 } | |
| 118 | |
| 119 void Verifier::jmp(State *state, const struct sock_filter& insn, | |
| 120 const char **err) { | |
| 121 if (BPF_OP(insn.code) == BPF_JA) { | |
| 122 state->ip += insn.k; | |
| 123 } else { | |
| 124 if (BPF_SRC(insn.code) != BPF_K || | |
| 125 !state->accIsValid || | |
| 126 state->ip + insn.jt + 1 >= state->program.size() || | |
| 127 state->ip + insn.jf + 1 >= state->program.size()) { | |
| 128 compilation_failure: | |
| 129 *err = "Invalid BPF_JMP instruction"; | |
| 130 return; | |
| 131 } | |
| 132 switch (BPF_OP(insn.code)) { | |
| 133 case BPF_JEQ: | |
| 134 if (state->accumulator == insn.k) { | |
| 135 state->ip += insn.jt; | |
| 136 } else { | |
| 137 state->ip += insn.jf; | |
| 138 } | |
| 139 break; | |
| 140 case BPF_JGT: | |
| 141 if (state->accumulator > insn.k) { | |
| 142 state->ip += insn.jt; | |
| 143 } else { | |
| 144 state->ip += insn.jf; | |
| 145 } | |
| 146 break; | |
| 147 case BPF_JGE: | |
| 148 if (state->accumulator >= insn.k) { | |
| 149 state->ip += insn.jt; | |
| 150 } else { | |
| 151 state->ip += insn.jf; | |
| 152 } | |
| 153 break; | |
| 154 case BPF_JSET: | |
| 155 if (state->accumulator & insn.k) { | |
| 156 state->ip += insn.jt; | |
| 157 } else { | |
| 158 state->ip += insn.jf; | |
| 159 } | |
| 160 break; | |
| 161 default: | |
| 162 goto compilation_failure; | |
| 163 } | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 uint32_t Verifier::ret(State *state, const struct sock_filter& insn, | |
| 168 const char **err) { | |
| 169 if (BPF_SRC(insn.code) != BPF_K) { | |
| 170 *err = "Invalid BPF_RET instruction"; | |
| 171 return 0; | |
| 172 } | |
| 173 return insn.k; | |
| 174 } | |
| 175 | |
| 176 } // namespace | |
| OLD | NEW |