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 void Verifier::verifyBPF(const std::vector<struct sock_filter>& program, | |
| 12 const Sandbox::Evaluators& evaluators) { | |
| 13 // Evaluate the BPF filter program for all possible inputs and | |
|
jln (very slow on Chromium)
2012/06/07 22:55:17
Could you document the API in the interface instea
| |
| 14 // verify that it computes the correct result. | |
|
jln (very slow on Chromium)
2012/06/07 22:55:17
We will probably never iterate over all possible i
| |
| 15 // We do not implement the full BPF syntax, but only the parts that | |
| 16 // can actually be generated by our BPF compiler. If we encounter an | |
| 17 // unsupported instruction, we fail. | |
| 18 // This method is called after compiling the entire BPF filter | |
| 19 // program. It either completes without making any state changes, or | |
| 20 // it terminates the program by calling Sandbox::die(). | |
|
jln (very slow on Chromium)
2012/06/07 22:55:17
See my remark about dying in the interface
| |
| 21 if (evaluators.size() != 1) { | |
| 22 Sandbox::die("Not implemented"); | |
| 23 } | |
| 24 Sandbox::EvaluateSyscall evaluateSyscall = evaluators.begin()->first; | |
| 25 for (int sysnum = MIN_SYSCALL-1; sysnum <= MAX_SYSCALL+1; ++sysnum) { | |
| 26 // Iterate through the entire BPF program until we either return | |
| 27 // or hit an invalid instruction pointer. | |
| 28 for (State state(program, sysnum, evaluateSyscall(sysnum)); | |
| 29 ; | |
|
jln (very slow on Chromium)
2012/06/07 22:55:17
This is roughly an emulator. Can be very useful. D
| |
| 30 ++state.ip) { | |
| 31 if (state.ip >= program.size()) { | |
| 32 Sandbox::die("Invalid instruction pointer in BPF program"); | |
| 33 } | |
| 34 const struct sock_filter& insn = program[state.ip]; | |
| 35 switch (BPF_CLASS(insn.code)) { | |
| 36 case BPF_LD: | |
| 37 ld(&state, insn); | |
| 38 break; | |
| 39 case BPF_JMP: | |
| 40 jmp(&state, insn); | |
| 41 break; | |
| 42 case BPF_RET: | |
| 43 ret(&state, insn); | |
| 44 goto returned; | |
| 45 default: | |
| 46 Sandbox::die("Unexpected instruction in BPF program"); | |
| 47 } | |
| 48 } | |
| 49 returned:; | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 void Verifier::ld(State *state, const struct sock_filter& insn) { | |
| 54 if (BPF_SIZE(insn.code) != BPF_W || | |
| 55 BPF_MODE(insn.code) != BPF_ABS) { | |
| 56 compilation_failure: | |
| 57 Sandbox::die("Invalid BPF_LD instruction"); | |
| 58 } | |
| 59 switch (insn.k) { | |
| 60 case offsetof(struct arch_seccomp_data, arch): | |
| 61 state->accumulator = SECCOMP_ARCH; | |
| 62 break; | |
| 63 case offsetof(struct arch_seccomp_data, nr): | |
| 64 state->accumulator = state->sysnum; | |
| 65 break; | |
| 66 default: | |
| 67 goto compilation_failure; | |
| 68 } | |
| 69 state->accIsValid = true; | |
| 70 } | |
| 71 | |
| 72 void Verifier::jmp(State *state, const struct sock_filter& insn) { | |
| 73 if (BPF_OP(insn.code) == BPF_JA) { | |
| 74 state->ip += insn.k; | |
| 75 } else { | |
| 76 if (BPF_SRC(insn.code) != BPF_K || | |
| 77 !state->accIsValid || | |
| 78 state->ip + insn.jt + 1 >= state->program.size() || | |
| 79 state->ip + insn.jf + 1 >= state->program.size()) { | |
| 80 compilation_failure: | |
| 81 Sandbox::die("Invalid BPF_JMP instruction"); | |
| 82 } | |
| 83 switch (BPF_OP(insn.code)) { | |
| 84 case BPF_JEQ: | |
| 85 if (state->accumulator == insn.k) { | |
| 86 state->ip += insn.jt; | |
| 87 } else { | |
| 88 state->ip += insn.jf; | |
| 89 } | |
| 90 break; | |
| 91 case BPF_JGT: | |
| 92 if (state->accumulator > insn.k) { | |
| 93 state->ip += insn.jt; | |
| 94 } else { | |
| 95 state->ip += insn.jf; | |
| 96 } | |
| 97 break; | |
| 98 case BPF_JGE: | |
| 99 if (state->accumulator >= insn.k) { | |
| 100 state->ip += insn.jt; | |
| 101 } else { | |
| 102 state->ip += insn.jf; | |
| 103 } | |
| 104 break; | |
| 105 case BPF_JSET: | |
| 106 if (state->accumulator & insn.k) { | |
| 107 state->ip += insn.jt; | |
| 108 } else { | |
| 109 state->ip += insn.jf; | |
| 110 } | |
| 111 break; | |
| 112 default: | |
| 113 goto compilation_failure; | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 void Verifier::ret(State *state, const struct sock_filter& insn) { | |
| 119 if (BPF_SRC(insn.code) != BPF_K) { | |
| 120 compilation_failure: | |
| 121 Sandbox::die("Invalid BPF_RET instruction"); | |
| 122 } | |
| 123 switch (state->err) { | |
| 124 case Sandbox::SB_TRAP: | |
| 125 if (insn.k != SECCOMP_RET_TRAP) { | |
| 126 goto compilation_failure; | |
| 127 } | |
| 128 break; | |
| 129 case Sandbox::SB_ALLOWED: | |
| 130 if (insn.k != SECCOMP_RET_ALLOW) { | |
| 131 goto compilation_failure; | |
| 132 } | |
| 133 break; | |
| 134 case Sandbox::SB_INSPECT_ARG_1...Sandbox::SB_INSPECT_ARG_6: | |
| 135 Sandbox::die("Not implemented"); | |
| 136 break; | |
| 137 default: | |
| 138 if (insn.k != SECCOMP_RET_ERRNO + state->err) { | |
| 139 goto compilation_failure; | |
| 140 } | |
| 141 break; | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 } // namespace | |
| OLD | NEW |