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

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

Issue 10546041: Added a new Verifier class to the BPF compiler. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Refactored error handling and rebased on head of the trunk Created 8 years, 6 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
(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 bool Verifier::verifyBPF(const std::vector<struct sock_filter>& program,
12 const Sandbox::Evaluators& evaluators,
13 const char **err) {
14 if (evaluators.size() != 1) {
jln (very slow on Chromium) 2012/06/08 19:28:22 Can you also check for !err ?
Markus (顧孟勤) 2012/06/08 20:04:24 I was originally intending to make error reporting
15 *err = "Not implemented";
16 return false;
17 }
18 Sandbox::EvaluateSyscall evaluateSyscall = evaluators.begin()->first;
19 for (int nr = MIN_SYSCALL-1; nr <= MAX_SYSCALL+1; ++nr) {
20 // We ideally want to iterate over the full system call range and values
21 // just above and just below this range. This gives us the full result set
22 // of the "evaluators".
23 // On Intel systems, this can fail in a surprising way, as a cleared bit 30
24 // indicates either i386 or x86-64; and a set bit 30 indicates x32. And
25 // unless we pay attention to setting this bit correctly, an early check in
26 // our BPF program will make us fail with a misleading error code.
27 #if defined(__i386__) || defined(__x86_64__)
28 #if defined(__x86_64__) && defined(__ILP32__)
29 int sysnum = nr | 0x40000000;
30 #else
31 int sysnum = nr & ~0x40000000;
32 #endif
33 #else
34 int sysnum = nr;
35 #endif
36
37 struct arch_seccomp_data data = { sysnum, SECCOMP_ARCH };
38 uint32_t expectedRet;
39 Sandbox::ErrorCode code = evaluateSyscall(sysnum);
40 switch (code) {
41 case Sandbox::SB_TRAP:
42 expectedRet = SECCOMP_RET_TRAP;
43 break;
44 case Sandbox::SB_ALLOWED:
45 expectedRet = SECCOMP_RET_ALLOW;
46 break;
47 case Sandbox::SB_INSPECT_ARG_1...Sandbox::SB_INSPECT_ARG_6:
48 *err = "Not implemented";
49 return false;
50 default:
51 if (code >= 1 && code < 4096) {
52 expectedRet = SECCOMP_RET_ERRNO + static_cast<int>(code);
53 } else {
54 *err = "Invalid errno value";
55 return false;
56 }
57 break;
58 }
59 const char *e;
60 uint32_t computedRet = evaluateBPF(program, data, &e);
61 if (e) {
62 *err = e;
63 return false;
64 } else if (computedRet != expectedRet) {
65 *err = "Exit code from BPF program doesn't match";
66 return false;
67 }
68 }
69 return true;
70 }
71
72 uint32_t Verifier::evaluateBPF(const std::vector<struct sock_filter>& program,
73 const struct arch_seccomp_data& data,
74 const char **err) {
75 *err = NULL;
jln (very slow on Chromium) 2012/06/08 19:28:22 Check !err here too ? (as this is part of the inte
76 for (State state(program, data); !*err; ++state.ip) {
77 if (state.ip >= program.size()) {
78 *err = "Invalid instruction pointer in BPF program";
79 break;
80 }
81 const struct sock_filter& insn = program[state.ip];
82 switch (BPF_CLASS(insn.code)) {
83 case BPF_LD:
84 ld(&state, insn, err);
85 break;
86 case BPF_JMP:
87 jmp(&state, insn, err);
88 break;
89 case BPF_RET:
90 return ret(&state, insn, err);
91 default:
92 *err = "Unexpected instruction in BPF program";
93 break;
94 }
95 }
96 return 0;
97 }
98
99 void Verifier::ld(State *state, const struct sock_filter& insn,
100 const char **err) {
101 if (BPF_SIZE(insn.code) != BPF_W ||
102 BPF_MODE(insn.code) != BPF_ABS) {
103 *err = "Invalid BPF_LD instruction";
104 return;
105 }
106 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
107 // We only allow loading of properly aligned 32bit quantities.
108 memcpy(&state->accumulator,
109 reinterpret_cast<const char *>(&state->data) + insn.k,
110 4);
111 } else {
112 *err = "Invalid operand in BPF_LD instruction";
113 return;
114 }
115 state->accIsValid = true;
116 return;
117 }
118
119 void Verifier::jmp(State *state, const struct sock_filter& insn,
120 const char **err) {
121 if (BPF_OP(insn.code) == BPF_JA) {
122 state->ip += insn.k;
123 } else {
124 if (BPF_SRC(insn.code) != BPF_K ||
125 !state->accIsValid ||
126 state->ip + insn.jt + 1 >= state->program.size() ||
127 state->ip + insn.jf + 1 >= state->program.size()) {
128 compilation_failure:
129 *err = "Invalid BPF_JMP instruction";
130 return;
131 }
132 switch (BPF_OP(insn.code)) {
133 case BPF_JEQ:
134 if (state->accumulator == insn.k) {
135 state->ip += insn.jt;
136 } else {
137 state->ip += insn.jf;
138 }
139 break;
140 case BPF_JGT:
141 if (state->accumulator > insn.k) {
142 state->ip += insn.jt;
143 } else {
144 state->ip += insn.jf;
145 }
146 break;
147 case BPF_JGE:
148 if (state->accumulator >= insn.k) {
149 state->ip += insn.jt;
150 } else {
151 state->ip += insn.jf;
152 }
153 break;
154 case BPF_JSET:
155 if (state->accumulator & insn.k) {
156 state->ip += insn.jt;
157 } else {
158 state->ip += insn.jf;
159 }
160 break;
161 default:
162 goto compilation_failure;
163 }
164 }
165 }
166
167 uint32_t Verifier::ret(State *state, const struct sock_filter& insn,
168 const char **err) {
169 if (BPF_SRC(insn.code) != BPF_K) {
170 *err = "Invalid BPF_RET instruction";
171 return 0;
172 }
173 return insn.k;
174 }
175
176 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698