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.
7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
8 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
9 #include "sandbox/linux/seccomp-bpf/verifier.h"
14 using playground2::ErrorCode;
15 using playground2::Sandbox;
16 using playground2::Verifier;
17 using playground2::arch_seccomp_data;
20 State(const std::vector<struct sock_filter>& p,
21 const struct arch_seccomp_data& d) :
28 const std::vector<struct sock_filter>& program;
29 const struct arch_seccomp_data& data;
35 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
38 uint32_t EvaluateErrorCode(Sandbox *sandbox, const ErrorCode& code,
39 const struct arch_seccomp_data& data) {
40 if (code.error_type() == ErrorCode::ET_SIMPLE ||
41 code.error_type() == ErrorCode::ET_TRAP) {
43 } else if (code.error_type() == ErrorCode::ET_COND) {
44 if (code.width() == ErrorCode::TP_32BIT &&
45 (data.args[code.argno()] >> 32) &&
46 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) !=
47 0xFFFFFFFF80000000ull) {
48 return sandbox->Unexpected64bitArgument().err();
51 case ErrorCode::OP_EQUAL:
52 return EvaluateErrorCode(sandbox,
53 (code.width() == ErrorCode::TP_32BIT
54 ? uint32_t(data.args[code.argno()])
55 : data.args[code.argno()]) == code.value()
59 case ErrorCode::OP_HAS_ALL_BITS:
60 return EvaluateErrorCode(sandbox,
61 ((code.width() == ErrorCode::TP_32BIT
62 ? uint32_t(data.args[code.argno()])
63 : data.args[code.argno()]) & code.value())
68 case ErrorCode::OP_HAS_ANY_BITS:
69 return EvaluateErrorCode(sandbox,
70 (code.width() == ErrorCode::TP_32BIT
71 ? uint32_t(data.args[code.argno()])
72 : data.args[code.argno()]) & code.value()
77 return SECCOMP_RET_INVALID;
80 return SECCOMP_RET_INVALID;
84 bool VerifyErrorCode(Sandbox *sandbox,
85 const std::vector<struct sock_filter>& program,
86 struct arch_seccomp_data *data,
87 const ErrorCode& root_code,
88 const ErrorCode& code,
90 if (code.error_type() == ErrorCode::ET_SIMPLE ||
91 code.error_type() == ErrorCode::ET_TRAP) {
92 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err);
95 } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) {
96 // For efficiency's sake, we'd much rather compare "computed_ret"
97 // against "code.err()". This works most of the time, but it doesn't
98 // always work for nested conditional expressions. The test values
99 // that we generate on the fly to probe expressions can trigger
100 // code flow decisions in multiple nodes of the decision tree, and the
101 // only way to compute the correct error code in that situation is by
102 // calling EvaluateErrorCode().
103 *err = "Exit code from BPF program doesn't match";
106 } else if (code.error_type() == ErrorCode::ET_COND) {
107 if (code.argno() < 0 || code.argno() >= 6) {
108 *err = "Invalid argument number in error code";
112 case ErrorCode::OP_EQUAL:
113 // Verify that we can check a 32bit value (or the LSB of a 64bit value)
115 data->args[code.argno()] = code.value();
116 if (!VerifyErrorCode(sandbox, program, data, root_code,
117 *code.passed(), err)) {
121 // Change the value to no longer match and verify that this is detected
123 data->args[code.argno()] = code.value() ^ 0x55AA55AA;
124 if (!VerifyErrorCode(sandbox, program, data, root_code,
125 *code.failed(), err)) {
129 // BPF programs can only ever operate on 32bit values. So, we have
130 // generated additional BPF instructions that inspect the MSB. Verify
131 // that they behave as intended.
132 if (code.width() == ErrorCode::TP_32BIT) {
133 if (code.value() >> 32) {
134 SANDBOX_DIE("Invalid comparison of a 32bit system call argument "
135 "against a 64bit constant; this test is always false.");
138 // If the system call argument was intended to be a 32bit parameter,
139 // verify that it is a fatal error if a 64bit value is ever passed
141 data->args[code.argno()] = 0x100000000ull;
142 if (!VerifyErrorCode(sandbox, program, data, root_code,
143 sandbox->Unexpected64bitArgument(),
148 // If the system call argument was intended to be a 64bit parameter,
149 // verify that we can handle (in-)equality for the MSB. This is
150 // essentially the same test that we did earlier for the LSB.
151 // We only need to verify the behavior of the inequality test. We
152 // know that the equality test already passed, as unlike the kernel
153 // the Verifier does operate on 64bit quantities.
154 data->args[code.argno()] = code.value() ^ 0x55AA55AA00000000ull;
155 if (!VerifyErrorCode(sandbox, program, data, root_code,
156 *code.failed(), err)) {
161 case ErrorCode::OP_HAS_ALL_BITS:
162 case ErrorCode::OP_HAS_ANY_BITS:
163 // A comprehensive test of bit values is difficult and potentially rather
164 // time-expensive. We avoid doing so at run-time and instead rely on the
165 // unittest for full testing. The test that we have here covers just the
166 // common cases. We test against the bitmask itself, all zeros and all
169 // Testing "any" bits against a zero mask is always false. So, there
170 // are some cases, where we expect tests to take the "failed()" branch
171 // even though this is a test that normally should take "passed()".
172 const ErrorCode& passed =
173 (!code.value() && code.op() == ErrorCode::OP_HAS_ANY_BITS) ||
175 // On a 32bit system, it is impossible to pass a 64bit value as a
176 // system call argument. So, some additional tests always evaluate
178 ((code.value() & ~uint64_t(uintptr_t(-1))) &&
179 code.op() == ErrorCode::OP_HAS_ALL_BITS) ||
180 (code.value() && !(code.value() & uintptr_t(-1)) &&
181 code.op() == ErrorCode::OP_HAS_ANY_BITS)
183 ? *code.failed() : *code.passed();
185 // Similary, testing for "all" bits in a zero mask is always true. So,
186 // some cases pass despite them normally failing.
187 const ErrorCode& failed =
188 !code.value() && code.op() == ErrorCode::OP_HAS_ALL_BITS
189 ? *code.passed() : *code.failed();
191 data->args[code.argno()] = code.value() & uintptr_t(-1);
192 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) {
195 data->args[code.argno()] = uintptr_t(-1);
196 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) {
199 data->args[code.argno()] = 0;
200 if (!VerifyErrorCode(sandbox, program, data, root_code, failed, err)) {
205 default: // TODO(markus): Need to add support for OP_GREATER
206 *err = "Unsupported operation in conditional error code";
210 *err = "Attempting to return invalid error code from BPF program";
216 void Ld(State *state, const struct sock_filter& insn, const char **err) {
217 if (BPF_SIZE(insn.code) != BPF_W ||
218 BPF_MODE(insn.code) != BPF_ABS) {
219 *err = "Invalid BPF_LD instruction";
222 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
223 // We only allow loading of properly aligned 32bit quantities.
224 memcpy(&state->accumulator,
225 reinterpret_cast<const char *>(&state->data) + insn.k,
228 *err = "Invalid operand in BPF_LD instruction";
231 state->acc_is_valid = true;
235 void Jmp(State *state, const struct sock_filter& insn, const char **err) {
236 if (BPF_OP(insn.code) == BPF_JA) {
237 if (state->ip + insn.k + 1 >= state->program.size() ||
238 state->ip + insn.k + 1 <= state->ip) {
240 *err = "Invalid BPF_JMP instruction";
245 if (BPF_SRC(insn.code) != BPF_K ||
246 !state->acc_is_valid ||
247 state->ip + insn.jt + 1 >= state->program.size() ||
248 state->ip + insn.jf + 1 >= state->program.size()) {
249 goto compilation_failure;
251 switch (BPF_OP(insn.code)) {
253 if (state->accumulator == insn.k) {
254 state->ip += insn.jt;
256 state->ip += insn.jf;
260 if (state->accumulator > insn.k) {
261 state->ip += insn.jt;
263 state->ip += insn.jf;
267 if (state->accumulator >= insn.k) {
268 state->ip += insn.jt;
270 state->ip += insn.jf;
274 if (state->accumulator & insn.k) {
275 state->ip += insn.jt;
277 state->ip += insn.jf;
281 goto compilation_failure;
286 uint32_t Ret(State *, const struct sock_filter& insn, const char **err) {
287 if (BPF_SRC(insn.code) != BPF_K) {
288 *err = "Invalid BPF_RET instruction";
294 void Alu(State *state, const struct sock_filter& insn, const char **err) {
295 if (BPF_OP(insn.code) == BPF_NEG) {
296 state->accumulator = -state->accumulator;
299 if (BPF_SRC(insn.code) != BPF_K) {
300 *err = "Unexpected source operand in arithmetic operation";
303 switch (BPF_OP(insn.code)) {
305 state->accumulator += insn.k;
308 state->accumulator -= insn.k;
311 state->accumulator *= insn.k;
315 *err = "Illegal division by zero";
318 state->accumulator /= insn.k;
322 *err = "Illegal division by zero";
325 state->accumulator %= insn.k;
328 state->accumulator |= insn.k;
331 state->accumulator ^= insn.k;
334 state->accumulator &= insn.k;
338 *err = "Illegal shift operation";
341 state->accumulator <<= insn.k;
345 *err = "Illegal shift operation";
348 state->accumulator >>= insn.k;
351 *err = "Invalid operator in arithmetic operation";
359 namespace playground2 {
361 bool Verifier::VerifyBPF(Sandbox *sandbox,
362 const std::vector<struct sock_filter>& program,
363 const Sandbox::Evaluators& evaluators,
366 if (evaluators.size() != 1) {
367 *err = "Not implemented";
370 Sandbox::EvaluateSyscall evaluate_syscall = evaluators.begin()->first;
371 void *aux = evaluators.begin()->second;
372 for (SyscallIterator iter(false); !iter.Done(); ) {
373 uint32_t sysnum = iter.Next();
374 // We ideally want to iterate over the full system call range and values
375 // just above and just below this range. This gives us the full result set
376 // of the "evaluators".
377 // On Intel systems, this can fail in a surprising way, as a cleared bit 30
378 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And
379 // unless we pay attention to setting this bit correctly, an early check in
380 // our BPF program will make us fail with a misleading error code.
381 struct arch_seccomp_data data = { static_cast<int>(sysnum),
382 static_cast<uint32_t>(SECCOMP_ARCH) };
383 #if defined(__i386__) || defined(__x86_64__)
384 #if defined(__x86_64__) && defined(__ILP32__)
385 if (!(sysnum & 0x40000000u)) {
389 if (sysnum & 0x40000000u) {
394 ErrorCode code = evaluate_syscall(sandbox, sysnum, aux);
395 if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) {
402 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
403 const struct arch_seccomp_data& data,
406 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
407 *err = "Invalid program length";
410 for (State state(program, data); !*err; ++state.ip) {
411 if (state.ip >= program.size()) {
412 *err = "Invalid instruction pointer in BPF program";
415 const struct sock_filter& insn = program[state.ip];
416 switch (BPF_CLASS(insn.code)) {
418 Ld(&state, insn, err);
421 Jmp(&state, insn, err);
424 uint32_t r = Ret(&state, insn, err);
425 switch (r & SECCOMP_RET_ACTION) {
426 case SECCOMP_RET_TRAP:
427 case SECCOMP_RET_ERRNO:
428 case SECCOMP_RET_ALLOW:
430 case SECCOMP_RET_KILL: // We don't ever generate this
431 case SECCOMP_RET_TRACE: // We don't ever generate this
432 case SECCOMP_RET_INVALID: // Should never show up in BPF program
434 *err = "Unexpected return code found in BPF program";
439 Alu(&state, insn, err);
442 *err = "Unexpected instruction in BPF program";