Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(821)

Side by Side Diff: sandbox/linux/seccomp-bpf/verifier.cc

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

Powered by Google App Engine
This is Rietveld 408576698