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

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

Powered by Google App Engine
This is Rietveld 408576698