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