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