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

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

Issue 66723007: Make sandbox/linux/seccomp-bpf/ follow the style guide. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: (empty) rebase Created 7 years, 1 month 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
« no previous file with comments | « sandbox/linux/seccomp-bpf/verifier.h ('k') | sandbox/linux/tests/main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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> 5 #include <string.h>
6 6
7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
8 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 8 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
9 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 9 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
10 #include "sandbox/linux/seccomp-bpf/verifier.h" 10 #include "sandbox/linux/seccomp-bpf/verifier.h"
11 11
12
13 namespace { 12 namespace {
14 13
15 using playground2::ErrorCode; 14 using playground2::ErrorCode;
16 using playground2::Sandbox; 15 using playground2::Sandbox;
17 using playground2::Verifier; 16 using playground2::Verifier;
18 using playground2::arch_seccomp_data; 17 using playground2::arch_seccomp_data;
19 18
20 struct State { 19 struct State {
21 State(const std::vector<struct sock_filter>& p, 20 State(const std::vector<struct sock_filter>& p,
22 const struct arch_seccomp_data& d) : 21 const struct arch_seccomp_data& d)
23 program(p), 22 : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {}
24 data(d),
25 ip(0),
26 accumulator(0),
27 acc_is_valid(false) {
28 }
29 const std::vector<struct sock_filter>& program; 23 const std::vector<struct sock_filter>& program;
30 const struct arch_seccomp_data& data; 24 const struct arch_seccomp_data& data;
31 unsigned int ip; 25 unsigned int ip;
32 uint32_t accumulator; 26 uint32_t accumulator;
33 bool acc_is_valid; 27 bool acc_is_valid;
34 28
35 private: 29 private:
36 DISALLOW_IMPLICIT_CONSTRUCTORS(State); 30 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
37 }; 31 };
38 32
39 uint32_t EvaluateErrorCode(Sandbox *sandbox, const ErrorCode& code, 33 uint32_t EvaluateErrorCode(Sandbox* sandbox,
34 const ErrorCode& code,
40 const struct arch_seccomp_data& data) { 35 const struct arch_seccomp_data& data) {
41 if (code.error_type() == ErrorCode::ET_SIMPLE || 36 if (code.error_type() == ErrorCode::ET_SIMPLE ||
42 code.error_type() == ErrorCode::ET_TRAP) { 37 code.error_type() == ErrorCode::ET_TRAP) {
43 return code.err(); 38 return code.err();
44 } else if (code.error_type() == ErrorCode::ET_COND) { 39 } else if (code.error_type() == ErrorCode::ET_COND) {
45 if (code.width() == ErrorCode::TP_32BIT && 40 if (code.width() == ErrorCode::TP_32BIT &&
46 (data.args[code.argno()] >> 32) && 41 (data.args[code.argno()] >> 32) &&
47 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) != 42 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) !=
48 0xFFFFFFFF80000000ull) { 43 0xFFFFFFFF80000000ull) {
49 return sandbox->Unexpected64bitArgument().err(); 44 return sandbox->Unexpected64bitArgument().err();
50 } 45 }
51 switch (code.op()) { 46 switch (code.op()) {
52 case ErrorCode::OP_EQUAL: 47 case ErrorCode::OP_EQUAL:
53 return EvaluateErrorCode(sandbox, 48 return EvaluateErrorCode(sandbox,
54 (code.width() == ErrorCode::TP_32BIT 49 (code.width() == ErrorCode::TP_32BIT
55 ? uint32_t(data.args[code.argno()]) 50 ? uint32_t(data.args[code.argno()])
56 : data.args[code.argno()]) == code.value() 51 : data.args[code.argno()]) == code.value()
57 ? *code.passed() 52 ? *code.passed()
58 : *code.failed(), 53 : *code.failed(),
59 data); 54 data);
60 case ErrorCode::OP_HAS_ALL_BITS: 55 case ErrorCode::OP_HAS_ALL_BITS:
61 return EvaluateErrorCode(sandbox, 56 return EvaluateErrorCode(sandbox,
62 ((code.width() == ErrorCode::TP_32BIT 57 ((code.width() == ErrorCode::TP_32BIT
63 ? uint32_t(data.args[code.argno()]) 58 ? uint32_t(data.args[code.argno()])
64 : data.args[code.argno()]) & code.value()) 59 : data.args[code.argno()]) &
65 == code.value() 60 code.value()) == code.value()
66 ? *code.passed() 61 ? *code.passed()
67 : *code.failed(), 62 : *code.failed(),
68 data); 63 data);
69 case ErrorCode::OP_HAS_ANY_BITS: 64 case ErrorCode::OP_HAS_ANY_BITS:
70 return EvaluateErrorCode(sandbox, 65 return EvaluateErrorCode(sandbox,
71 (code.width() == ErrorCode::TP_32BIT 66 (code.width() == ErrorCode::TP_32BIT
72 ? uint32_t(data.args[code.argno()]) 67 ? uint32_t(data.args[code.argno()])
73 : data.args[code.argno()]) & code.value() 68 : data.args[code.argno()]) &
74 ? *code.passed() 69 code.value()
75 : *code.failed(), 70 ? *code.passed()
76 data); 71 : *code.failed(),
77 default: 72 data);
78 return SECCOMP_RET_INVALID; 73 default:
74 return SECCOMP_RET_INVALID;
79 } 75 }
80 } else { 76 } else {
81 return SECCOMP_RET_INVALID; 77 return SECCOMP_RET_INVALID;
82 } 78 }
83 } 79 }
84 80
85 bool VerifyErrorCode(Sandbox *sandbox, 81 bool VerifyErrorCode(Sandbox* sandbox,
86 const std::vector<struct sock_filter>& program, 82 const std::vector<struct sock_filter>& program,
87 struct arch_seccomp_data *data, 83 struct arch_seccomp_data* data,
88 const ErrorCode& root_code, 84 const ErrorCode& root_code,
89 const ErrorCode& code, 85 const ErrorCode& code,
90 const char **err) { 86 const char** err) {
91 if (code.error_type() == ErrorCode::ET_SIMPLE || 87 if (code.error_type() == ErrorCode::ET_SIMPLE ||
92 code.error_type() == ErrorCode::ET_TRAP) { 88 code.error_type() == ErrorCode::ET_TRAP) {
93 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err); 89 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err);
94 if (*err) { 90 if (*err) {
95 return false; 91 return false;
96 } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) { 92 } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) {
97 // For efficiency's sake, we'd much rather compare "computed_ret" 93 // For efficiency's sake, we'd much rather compare "computed_ret"
98 // against "code.err()". This works most of the time, but it doesn't 94 // against "code.err()". This works most of the time, but it doesn't
99 // always work for nested conditional expressions. The test values 95 // always work for nested conditional expressions. The test values
100 // that we generate on the fly to probe expressions can trigger 96 // that we generate on the fly to probe expressions can trigger
101 // code flow decisions in multiple nodes of the decision tree, and the 97 // code flow decisions in multiple nodes of the decision tree, and the
102 // only way to compute the correct error code in that situation is by 98 // only way to compute the correct error code in that situation is by
103 // calling EvaluateErrorCode(). 99 // calling EvaluateErrorCode().
104 *err = "Exit code from BPF program doesn't match"; 100 *err = "Exit code from BPF program doesn't match";
105 return false; 101 return false;
106 } 102 }
107 } else if (code.error_type() == ErrorCode::ET_COND) { 103 } else if (code.error_type() == ErrorCode::ET_COND) {
108 if (code.argno() < 0 || code.argno() >= 6) { 104 if (code.argno() < 0 || code.argno() >= 6) {
109 *err = "Invalid argument number in error code"; 105 *err = "Invalid argument number in error code";
110 return false; 106 return false;
111 } 107 }
112 switch (code.op()) { 108 switch (code.op()) {
113 case ErrorCode::OP_EQUAL: 109 case ErrorCode::OP_EQUAL:
114 // Verify that we can check a 32bit value (or the LSB of a 64bit value) 110 // Verify that we can check a 32bit value (or the LSB of a 64bit value)
115 // for equality. 111 // for equality.
116 data->args[code.argno()] = code.value(); 112 data->args[code.argno()] = code.value();
117 if (!VerifyErrorCode(sandbox, program, data, root_code, 113 if (!VerifyErrorCode(
118 *code.passed(), err)) { 114 sandbox, program, data, root_code, *code.passed(), err)) {
119 return false; 115 return false;
120 }
121
122 // Change the value to no longer match and verify that this is detected
123 // as an inequality.
124 data->args[code.argno()] = code.value() ^ 0x55AA55AA;
125 if (!VerifyErrorCode(sandbox, program, data, root_code,
126 *code.failed(), err)) {
127 return false;
128 }
129
130 // BPF programs can only ever operate on 32bit values. So, we have
131 // generated additional BPF instructions that inspect the MSB. Verify
132 // that they behave as intended.
133 if (code.width() == ErrorCode::TP_32BIT) {
134 if (code.value() >> 32) {
135 SANDBOX_DIE("Invalid comparison of a 32bit system call argument "
136 "against a 64bit constant; this test is always false.");
137 } 116 }
138 117
139 // If the system call argument was intended to be a 32bit parameter, 118 // Change the value to no longer match and verify that this is detected
140 // verify that it is a fatal error if a 64bit value is ever passed 119 // as an inequality.
141 // here. 120 data->args[code.argno()] = code.value() ^ 0x55AA55AA;
142 data->args[code.argno()] = 0x100000000ull; 121 if (!VerifyErrorCode(
143 if (!VerifyErrorCode(sandbox, program, data, root_code, 122 sandbox, program, data, root_code, *code.failed(), err)) {
144 sandbox->Unexpected64bitArgument(),
145 err)) {
146 return false; 123 return false;
147 } 124 }
148 } else { 125
149 // If the system call argument was intended to be a 64bit parameter, 126 // BPF programs can only ever operate on 32bit values. So, we have
150 // verify that we can handle (in-)equality for the MSB. This is 127 // generated additional BPF instructions that inspect the MSB. Verify
151 // essentially the same test that we did earlier for the LSB. 128 // that they behave as intended.
152 // We only need to verify the behavior of the inequality test. We 129 if (code.width() == ErrorCode::TP_32BIT) {
153 // know that the equality test already passed, as unlike the kernel 130 if (code.value() >> 32) {
154 // the Verifier does operate on 64bit quantities. 131 SANDBOX_DIE(
155 data->args[code.argno()] = code.value() ^ 0x55AA55AA00000000ull; 132 "Invalid comparison of a 32bit system call argument "
156 if (!VerifyErrorCode(sandbox, program, data, root_code, 133 "against a 64bit constant; this test is always false.");
157 *code.failed(), err)) { 134 }
158 return false; 135
136 // If the system call argument was intended to be a 32bit parameter,
137 // verify that it is a fatal error if a 64bit value is ever passed
138 // here.
139 data->args[code.argno()] = 0x100000000ull;
140 if (!VerifyErrorCode(sandbox,
141 program,
142 data,
143 root_code,
144 sandbox->Unexpected64bitArgument(),
145 err)) {
146 return false;
147 }
148 } else {
149 // If the system call argument was intended to be a 64bit parameter,
150 // verify that we can handle (in-)equality for the MSB. This is
151 // essentially the same test that we did earlier for the LSB.
152 // We only need to verify the behavior of the inequality test. We
153 // know that the equality test already passed, as unlike the kernel
154 // the Verifier does operate on 64bit quantities.
155 data->args[code.argno()] = code.value() ^ 0x55AA55AA00000000ull;
156 if (!VerifyErrorCode(
157 sandbox, program, data, root_code, *code.failed(), err)) {
158 return false;
159 }
159 } 160 }
160 } 161 break;
161 break; 162 case ErrorCode::OP_HAS_ALL_BITS:
162 case ErrorCode::OP_HAS_ALL_BITS: 163 case ErrorCode::OP_HAS_ANY_BITS:
163 case ErrorCode::OP_HAS_ANY_BITS: 164 // A comprehensive test of bit values is difficult and potentially
164 // A comprehensive test of bit values is difficult and potentially rather 165 // rather
165 // time-expensive. We avoid doing so at run-time and instead rely on the 166 // time-expensive. We avoid doing so at run-time and instead rely on the
166 // unittest for full testing. The test that we have here covers just the 167 // unittest for full testing. The test that we have here covers just the
167 // common cases. We test against the bitmask itself, all zeros and all 168 // common cases. We test against the bitmask itself, all zeros and all
168 // ones. 169 // ones.
169 { 170 {
170 // Testing "any" bits against a zero mask is always false. So, there 171 // Testing "any" bits against a zero mask is always false. So, there
171 // are some cases, where we expect tests to take the "failed()" branch 172 // are some cases, where we expect tests to take the "failed()" branch
172 // even though this is a test that normally should take "passed()". 173 // even though this is a test that normally should take "passed()".
173 const ErrorCode& passed = 174 const ErrorCode& passed =
174 (!code.value() && code.op() == ErrorCode::OP_HAS_ANY_BITS) || 175 (!code.value() && code.op() == ErrorCode::OP_HAS_ANY_BITS) ||
175 176
176 // On a 32bit system, it is impossible to pass a 64bit value as a 177 // On a 32bit system, it is impossible to pass a 64bit
177 // system call argument. So, some additional tests always evaluate 178 // value as a
178 // as false. 179 // system call argument. So, some additional tests always
179 ((code.value() & ~uint64_t(uintptr_t(-1))) && 180 // evaluate
180 code.op() == ErrorCode::OP_HAS_ALL_BITS) || 181 // as false.
181 (code.value() && !(code.value() & uintptr_t(-1)) && 182 ((code.value() & ~uint64_t(uintptr_t(-1))) &&
182 code.op() == ErrorCode::OP_HAS_ANY_BITS) 183 code.op() == ErrorCode::OP_HAS_ALL_BITS) ||
184 (code.value() && !(code.value() & uintptr_t(-1)) &&
185 code.op() == ErrorCode::OP_HAS_ANY_BITS)
186 ? *code.failed()
187 : *code.passed();
183 188
184 ? *code.failed() : *code.passed(); 189 // Similary, testing for "all" bits in a zero mask is always true. So,
190 // some cases pass despite them normally failing.
191 const ErrorCode& failed =
192 !code.value() && code.op() == ErrorCode::OP_HAS_ALL_BITS
193 ? *code.passed()
194 : *code.failed();
185 195
186 // Similary, testing for "all" bits in a zero mask is always true. So, 196 data->args[code.argno()] = code.value() & uintptr_t(-1);
187 // some cases pass despite them normally failing. 197 if (!VerifyErrorCode(
188 const ErrorCode& failed = 198 sandbox, program, data, root_code, passed, err)) {
189 !code.value() && code.op() == ErrorCode::OP_HAS_ALL_BITS 199 return false;
190 ? *code.passed() : *code.failed(); 200 }
191 201 data->args[code.argno()] = uintptr_t(-1);
192 data->args[code.argno()] = code.value() & uintptr_t(-1); 202 if (!VerifyErrorCode(
193 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) { 203 sandbox, program, data, root_code, passed, err)) {
194 return false; 204 return false;
205 }
206 data->args[code.argno()] = 0;
207 if (!VerifyErrorCode(
208 sandbox, program, data, root_code, failed, err)) {
209 return false;
210 }
195 } 211 }
196 data->args[code.argno()] = uintptr_t(-1); 212 break;
197 if (!VerifyErrorCode(sandbox, program, data, root_code, passed, err)) { 213 default: // TODO(markus): Need to add support for OP_GREATER
198 return false; 214 *err = "Unsupported operation in conditional error code";
199 } 215 return false;
200 data->args[code.argno()] = 0;
201 if (!VerifyErrorCode(sandbox, program, data, root_code, failed, err)) {
202 return false;
203 }
204 }
205 break;
206 default: // TODO(markus): Need to add support for OP_GREATER
207 *err = "Unsupported operation in conditional error code";
208 return false;
209 } 216 }
210 } else { 217 } else {
211 *err = "Attempting to return invalid error code from BPF program"; 218 *err = "Attempting to return invalid error code from BPF program";
212 return false; 219 return false;
213 } 220 }
214 return true; 221 return true;
215 } 222 }
216 223
217 void Ld(State *state, const struct sock_filter& insn, const char **err) { 224 void Ld(State* state, const struct sock_filter& insn, const char** err) {
218 if (BPF_SIZE(insn.code) != BPF_W || 225 if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS) {
219 BPF_MODE(insn.code) != BPF_ABS) {
220 *err = "Invalid BPF_LD instruction"; 226 *err = "Invalid BPF_LD instruction";
221 return; 227 return;
222 } 228 }
223 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { 229 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
224 // We only allow loading of properly aligned 32bit quantities. 230 // We only allow loading of properly aligned 32bit quantities.
225 memcpy(&state->accumulator, 231 memcpy(&state->accumulator,
226 reinterpret_cast<const char *>(&state->data) + insn.k, 232 reinterpret_cast<const char*>(&state->data) + insn.k,
227 4); 233 4);
228 } else { 234 } else {
229 *err = "Invalid operand in BPF_LD instruction"; 235 *err = "Invalid operand in BPF_LD instruction";
230 return; 236 return;
231 } 237 }
232 state->acc_is_valid = true; 238 state->acc_is_valid = true;
233 return; 239 return;
234 } 240 }
235 241
236 void Jmp(State *state, const struct sock_filter& insn, const char **err) { 242 void Jmp(State* state, const struct sock_filter& insn, const char** err) {
237 if (BPF_OP(insn.code) == BPF_JA) { 243 if (BPF_OP(insn.code) == BPF_JA) {
238 if (state->ip + insn.k + 1 >= state->program.size() || 244 if (state->ip + insn.k + 1 >= state->program.size() ||
239 state->ip + insn.k + 1 <= state->ip) { 245 state->ip + insn.k + 1 <= state->ip) {
240 compilation_failure: 246 compilation_failure:
241 *err = "Invalid BPF_JMP instruction"; 247 *err = "Invalid BPF_JMP instruction";
242 return; 248 return;
243 } 249 }
244 state->ip += insn.k; 250 state->ip += insn.k;
245 } else { 251 } else {
246 if (BPF_SRC(insn.code) != BPF_K || 252 if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid ||
247 !state->acc_is_valid ||
248 state->ip + insn.jt + 1 >= state->program.size() || 253 state->ip + insn.jt + 1 >= state->program.size() ||
249 state->ip + insn.jf + 1 >= state->program.size()) { 254 state->ip + insn.jf + 1 >= state->program.size()) {
250 goto compilation_failure; 255 goto compilation_failure;
251 } 256 }
252 switch (BPF_OP(insn.code)) { 257 switch (BPF_OP(insn.code)) {
253 case BPF_JEQ: 258 case BPF_JEQ:
254 if (state->accumulator == insn.k) { 259 if (state->accumulator == insn.k) {
255 state->ip += insn.jt; 260 state->ip += insn.jt;
256 } else { 261 } else {
257 state->ip += insn.jf; 262 state->ip += insn.jf;
258 } 263 }
259 break; 264 break;
260 case BPF_JGT: 265 case BPF_JGT:
261 if (state->accumulator > insn.k) { 266 if (state->accumulator > insn.k) {
262 state->ip += insn.jt; 267 state->ip += insn.jt;
263 } else { 268 } else {
264 state->ip += insn.jf; 269 state->ip += insn.jf;
265 } 270 }
266 break; 271 break;
267 case BPF_JGE: 272 case BPF_JGE:
268 if (state->accumulator >= insn.k) { 273 if (state->accumulator >= insn.k) {
269 state->ip += insn.jt; 274 state->ip += insn.jt;
270 } else { 275 } else {
271 state->ip += insn.jf; 276 state->ip += insn.jf;
272 } 277 }
273 break; 278 break;
274 case BPF_JSET: 279 case BPF_JSET:
275 if (state->accumulator & insn.k) { 280 if (state->accumulator & insn.k) {
276 state->ip += insn.jt; 281 state->ip += insn.jt;
277 } else { 282 } else {
278 state->ip += insn.jf; 283 state->ip += insn.jf;
279 } 284 }
280 break; 285 break;
281 default: 286 default:
282 goto compilation_failure; 287 goto compilation_failure;
283 } 288 }
284 } 289 }
285 } 290 }
286 291
287 uint32_t Ret(State *, const struct sock_filter& insn, const char **err) { 292 uint32_t Ret(State*, const struct sock_filter& insn, const char** err) {
288 if (BPF_SRC(insn.code) != BPF_K) { 293 if (BPF_SRC(insn.code) != BPF_K) {
289 *err = "Invalid BPF_RET instruction"; 294 *err = "Invalid BPF_RET instruction";
290 return 0; 295 return 0;
291 } 296 }
292 return insn.k; 297 return insn.k;
293 } 298 }
294 299
295 void Alu(State *state, const struct sock_filter& insn, const char **err) { 300 void Alu(State* state, const struct sock_filter& insn, const char** err) {
296 if (BPF_OP(insn.code) == BPF_NEG) { 301 if (BPF_OP(insn.code) == BPF_NEG) {
297 state->accumulator = -state->accumulator; 302 state->accumulator = -state->accumulator;
298 return; 303 return;
299 } else { 304 } else {
300 if (BPF_SRC(insn.code) != BPF_K) { 305 if (BPF_SRC(insn.code) != BPF_K) {
301 *err = "Unexpected source operand in arithmetic operation"; 306 *err = "Unexpected source operand in arithmetic operation";
302 return; 307 return;
303 } 308 }
304 switch (BPF_OP(insn.code)) { 309 switch (BPF_OP(insn.code)) {
305 case BPF_ADD: 310 case BPF_ADD:
306 state->accumulator += insn.k; 311 state->accumulator += insn.k;
307 break;
308 case BPF_SUB:
309 state->accumulator -= insn.k;
310 break;
311 case BPF_MUL:
312 state->accumulator *= insn.k;
313 break;
314 case BPF_DIV:
315 if (!insn.k) {
316 *err = "Illegal division by zero";
317 break; 312 break;
318 } 313 case BPF_SUB:
319 state->accumulator /= insn.k; 314 state->accumulator -= insn.k;
320 break;
321 case BPF_MOD:
322 if (!insn.k) {
323 *err = "Illegal division by zero";
324 break; 315 break;
325 } 316 case BPF_MUL:
326 state->accumulator %= insn.k; 317 state->accumulator *= insn.k;
327 break;
328 case BPF_OR:
329 state->accumulator |= insn.k;
330 break;
331 case BPF_XOR:
332 state->accumulator ^= insn.k;
333 break;
334 case BPF_AND:
335 state->accumulator &= insn.k;
336 break;
337 case BPF_LSH:
338 if (insn.k > 32) {
339 *err = "Illegal shift operation";
340 break; 318 break;
341 } 319 case BPF_DIV:
342 state->accumulator <<= insn.k; 320 if (!insn.k) {
343 break; 321 *err = "Illegal division by zero";
344 case BPF_RSH: 322 break;
345 if (insn.k > 32) { 323 }
346 *err = "Illegal shift operation"; 324 state->accumulator /= insn.k;
347 break; 325 break;
348 } 326 case BPF_MOD:
349 state->accumulator >>= insn.k; 327 if (!insn.k) {
350 break; 328 *err = "Illegal division by zero";
351 default: 329 break;
352 *err = "Invalid operator in arithmetic operation"; 330 }
353 break; 331 state->accumulator %= insn.k;
332 break;
333 case BPF_OR:
334 state->accumulator |= insn.k;
335 break;
336 case BPF_XOR:
337 state->accumulator ^= insn.k;
338 break;
339 case BPF_AND:
340 state->accumulator &= insn.k;
341 break;
342 case BPF_LSH:
343 if (insn.k > 32) {
344 *err = "Illegal shift operation";
345 break;
346 }
347 state->accumulator <<= insn.k;
348 break;
349 case BPF_RSH:
350 if (insn.k > 32) {
351 *err = "Illegal shift operation";
352 break;
353 }
354 state->accumulator >>= insn.k;
355 break;
356 default:
357 *err = "Invalid operator in arithmetic operation";
358 break;
354 } 359 }
355 } 360 }
356 } 361 }
357 362
358 } // namespace 363 } // namespace
359 364
360 namespace playground2 { 365 namespace playground2 {
361 366
362 bool Verifier::VerifyBPF(Sandbox *sandbox, 367 bool Verifier::VerifyBPF(Sandbox* sandbox,
363 const std::vector<struct sock_filter>& program, 368 const std::vector<struct sock_filter>& program,
364 const SandboxBpfPolicy& policy, 369 const SandboxBpfPolicy& policy,
365 const char **err) { 370 const char** err) {
366 *err = NULL; 371 *err = NULL;
367 for (SyscallIterator iter(false); !iter.Done(); ) { 372 for (SyscallIterator iter(false); !iter.Done();) {
368 uint32_t sysnum = iter.Next(); 373 uint32_t sysnum = iter.Next();
369 // We ideally want to iterate over the full system call range and values 374 // We ideally want to iterate over the full system call range and values
370 // just above and just below this range. This gives us the full result set 375 // just above and just below this range. This gives us the full result set
371 // of the "evaluators". 376 // of the "evaluators".
372 // On Intel systems, this can fail in a surprising way, as a cleared bit 30 377 // On Intel systems, this can fail in a surprising way, as a cleared bit 30
373 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And 378 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And
374 // unless we pay attention to setting this bit correctly, an early check in 379 // unless we pay attention to setting this bit correctly, an early check in
375 // our BPF program will make us fail with a misleading error code. 380 // our BPF program will make us fail with a misleading error code.
376 struct arch_seccomp_data data = { static_cast<int>(sysnum), 381 struct arch_seccomp_data data = {static_cast<int>(sysnum),
377 static_cast<uint32_t>(SECCOMP_ARCH) }; 382 static_cast<uint32_t>(SECCOMP_ARCH)};
378 #if defined(__i386__) || defined(__x86_64__) 383 #if defined(__i386__) || defined(__x86_64__)
379 #if defined(__x86_64__) && defined(__ILP32__) 384 #if defined(__x86_64__) && defined(__ILP32__)
380 if (!(sysnum & 0x40000000u)) { 385 if (!(sysnum & 0x40000000u)) {
381 continue; 386 continue;
382 } 387 }
383 #else 388 #else
384 if (sysnum & 0x40000000u) { 389 if (sysnum & 0x40000000u) {
385 continue; 390 continue;
386 } 391 }
387 #endif 392 #endif
388 #endif 393 #endif
389 ErrorCode code = policy.EvaluateSyscall(sandbox, sysnum); 394 ErrorCode code = policy.EvaluateSyscall(sandbox, sysnum);
390 if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) { 395 if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) {
391 return false; 396 return false;
392 } 397 }
393 } 398 }
394 return true; 399 return true;
395 } 400 }
396 401
397 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, 402 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
398 const struct arch_seccomp_data& data, 403 const struct arch_seccomp_data& data,
399 const char **err) { 404 const char** err) {
400 *err = NULL; 405 *err = NULL;
401 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { 406 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
402 *err = "Invalid program length"; 407 *err = "Invalid program length";
403 return 0; 408 return 0;
404 } 409 }
405 for (State state(program, data); !*err; ++state.ip) { 410 for (State state(program, data); !*err; ++state.ip) {
406 if (state.ip >= program.size()) { 411 if (state.ip >= program.size()) {
407 *err = "Invalid instruction pointer in BPF program"; 412 *err = "Invalid instruction pointer in BPF program";
408 break; 413 break;
409 } 414 }
410 const struct sock_filter& insn = program[state.ip]; 415 const struct sock_filter& insn = program[state.ip];
411 switch (BPF_CLASS(insn.code)) { 416 switch (BPF_CLASS(insn.code)) {
412 case BPF_LD: 417 case BPF_LD:
413 Ld(&state, insn, err); 418 Ld(&state, insn, err);
414 break;
415 case BPF_JMP:
416 Jmp(&state, insn, err);
417 break;
418 case BPF_RET: {
419 uint32_t r = Ret(&state, insn, err);
420 switch (r & SECCOMP_RET_ACTION) {
421 case SECCOMP_RET_TRAP:
422 case SECCOMP_RET_ERRNO:
423 case SECCOMP_RET_ALLOW:
424 break; 419 break;
425 case SECCOMP_RET_KILL: // We don't ever generate this 420 case BPF_JMP:
426 case SECCOMP_RET_TRACE: // We don't ever generate this 421 Jmp(&state, insn, err);
427 case SECCOMP_RET_INVALID: // Should never show up in BPF program 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 }
439 case BPF_ALU:
440 Alu(&state, insn, err);
441 break;
428 default: 442 default:
429 *err = "Unexpected return code found in BPF program"; 443 *err = "Unexpected instruction in BPF program";
430 return 0; 444 break;
431 }
432 return r; }
433 case BPF_ALU:
434 Alu(&state, insn, err);
435 break;
436 default:
437 *err = "Unexpected instruction in BPF program";
438 break;
439 } 445 }
440 } 446 }
441 return 0; 447 return 0;
442 } 448 }
443 449
444 } // namespace 450 } // namespace
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/verifier.h ('k') | sandbox/linux/tests/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698