OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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-helpers/bpf_dsl.h" | |
6 | |
7 #include <errno.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "sandbox/linux/seccomp-bpf/errorcode.h" | |
12 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | |
13 | |
14 using namespace sandbox::bpf_dsl::internal; | |
15 typedef ::sandbox::Trap::TrapFnc TrapFnc; | |
16 | |
17 namespace sandbox { | |
18 | |
19 namespace bpf_dsl { | |
20 | |
21 namespace { | |
22 | |
23 class AllowResultExprImpl : public ResultExprImpl { | |
24 public: | |
25 AllowResultExprImpl() {} | |
26 virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | |
27 return ErrorCode(ErrorCode::ERR_ALLOWED); | |
28 } | |
29 | |
30 private: | |
31 virtual ~AllowResultExprImpl() {} | |
32 DISALLOW_COPY_AND_ASSIGN(AllowResultExprImpl); | |
33 }; | |
34 | |
35 class ErrorResultExprImpl : public ResultExprImpl { | |
36 public: | |
37 explicit ErrorResultExprImpl(int err) : err_(err) { | |
38 CHECK(err_ >= ErrorCode::ERR_MIN_ERRNO && err_ <= ErrorCode::ERR_MAX_ERRNO); | |
39 } | |
40 virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | |
41 return ErrorCode(err_); | |
42 } | |
43 | |
44 private: | |
45 virtual ~ErrorResultExprImpl() {} | |
46 int err_; | |
47 DISALLOW_COPY_AND_ASSIGN(ErrorResultExprImpl); | |
48 }; | |
49 | |
50 class TrapResultExprImpl : public ResultExprImpl { | |
51 public: | |
52 TrapResultExprImpl(TrapFnc func, void* arg) : func_(func), arg_(arg) { | |
53 DCHECK(func_); | |
54 } | |
55 virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | |
56 return sb->Trap(func_, arg_); | |
57 } | |
58 | |
59 private: | |
60 virtual ~TrapResultExprImpl() {} | |
61 TrapFnc func_; | |
62 void* arg_; | |
63 DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl); | |
64 }; | |
65 | |
66 class IfThenResultExprImpl : public ResultExprImpl { | |
67 public: | |
68 IfThenResultExprImpl(BoolExpr cond, | |
69 ResultExpr then_result, | |
70 ResultExpr else_result) | |
71 : cond_(cond), then_result_(then_result), else_result_(else_result) {} | |
72 virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | |
73 return cond_->Compile( | |
74 sb, then_result_->Compile(sb), else_result_->Compile(sb)); | |
75 } | |
76 | |
77 private: | |
78 virtual ~IfThenResultExprImpl() {} | |
79 BoolExpr cond_; | |
80 ResultExpr then_result_; | |
81 ResultExpr else_result_; | |
82 DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl); | |
83 }; | |
84 | |
85 class PrimitiveBoolExprImpl : public BoolExprImpl { | |
86 public: | |
87 PrimitiveBoolExprImpl(int argno, | |
88 ErrorCode::ArgType is_32bit, | |
89 ErrorCode::Operation op, | |
90 uint64_t value) | |
91 : argno_(argno), is_32bit_(is_32bit), op_(op), value_(value) {} | |
92 virtual ErrorCode Compile(SandboxBPF* sb, | |
93 ErrorCode true_ec, | |
94 ErrorCode false_ec) const OVERRIDE { | |
95 return sb->Cond(argno_, is_32bit_, op_, value_, true_ec, false_ec); | |
96 } | |
97 | |
98 private: | |
99 virtual ~PrimitiveBoolExprImpl() {} | |
100 int argno_; | |
101 ErrorCode::ArgType is_32bit_; | |
102 ErrorCode::Operation op_; | |
103 uint64_t value_; | |
104 DISALLOW_COPY_AND_ASSIGN(PrimitiveBoolExprImpl); | |
105 }; | |
106 | |
107 class NegateBoolExprImpl : public BoolExprImpl { | |
108 public: | |
109 explicit NegateBoolExprImpl(BoolExpr cond) : cond_(cond) {} | |
110 virtual ErrorCode Compile(SandboxBPF* sb, | |
111 ErrorCode true_ec, | |
112 ErrorCode false_ec) const OVERRIDE { | |
113 return cond_->Compile(sb, false_ec, true_ec); | |
114 } | |
115 | |
116 private: | |
117 virtual ~NegateBoolExprImpl() {} | |
118 BoolExpr cond_; | |
119 DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl); | |
120 }; | |
121 | |
122 class AndBoolExprImpl : public BoolExprImpl { | |
123 public: | |
124 AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs) : lhs_(lhs), rhs_(rhs) {} | |
125 virtual ErrorCode Compile(SandboxBPF* sb, | |
126 ErrorCode true_ec, | |
127 ErrorCode false_ec) const OVERRIDE { | |
128 return lhs_->Compile(sb, rhs_->Compile(sb, true_ec, false_ec), false_ec); | |
129 } | |
130 | |
131 private: | |
132 virtual ~AndBoolExprImpl() {} | |
133 BoolExpr lhs_, rhs_; | |
134 DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl); | |
135 }; | |
136 | |
137 class OrBoolExprImpl : public BoolExprImpl { | |
138 public: | |
139 OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs) : lhs_(lhs), rhs_(rhs) {} | |
140 virtual ErrorCode Compile(SandboxBPF* sb, | |
141 ErrorCode true_ec, | |
142 ErrorCode false_ec) const OVERRIDE { | |
143 return lhs_->Compile(sb, true_ec, rhs_->Compile(sb, true_ec, false_ec)); | |
144 } | |
145 | |
146 private: | |
147 virtual ~OrBoolExprImpl() {} | |
148 BoolExpr lhs_, rhs_; | |
149 DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl); | |
150 }; | |
151 | |
152 } // namespace | |
153 | |
154 namespace internal { | |
155 | |
156 // Internal helper class. Represents a (BoolExpr, ResultExpr)-pair | |
157 // node in an immutable linked list. | |
158 struct IfThen : public base::RefCounted<IfThen> { | |
jln (very slow on Chromium)
2014/06/24 23:51:31
This should really be a class.
mdempsky
2014/06/25 23:50:21
Done.
| |
159 BoolExpr cond; | |
160 ResultExpr then; | |
161 IfThenList rest; | |
162 | |
163 // Returns a new IfThenList with a node for (cond, then) prepended | |
164 // before rest. | |
165 static IfThenList Cons(BoolExpr cond, ResultExpr then, IfThenList rest) { | |
jln (very slow on Chromium)
2014/06/24 23:51:31
It's a nit, but this confused me for a bit. Is thi
mdempsky
2014/06/25 23:50:21
Done.
| |
166 return IfThenList(new const IfThen(cond, then, rest)); | |
167 } | |
168 | |
169 private: | |
170 IfThen(BoolExpr cond_, ResultExpr then_, IfThenList rest_) | |
jln (very slow on Chromium)
2014/06/24 23:51:31
Constructor arguments should not have a trailing _
mdempsky
2014/06/25 23:50:21
Done.
| |
171 : cond(cond_), then(then_), rest(rest_) {} | |
172 virtual ~IfThen() {} | |
173 friend class base::RefCounted<IfThen>; | |
174 DISALLOW_COPY_AND_ASSIGN(IfThen); | |
175 }; | |
176 | |
177 BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) { | |
178 CHECK(num >= 0 && num < 6); | |
jln (very slow on Chromium)
2014/06/24 23:51:31
We'll need to extend the number of syscalls soon F
mdempsky
2014/06/25 23:50:21
Acknowledged.
| |
179 CHECK(size >= 1 && size <= 8); | |
180 CHECK_NE(0U, mask) << "zero mask doesn't make sense"; | |
181 CHECK_EQ(val, val & mask) << "val contains masked out bits"; | |
182 | |
183 const ErrorCode::ArgType arg_type = | |
184 (size <= 4) ? ErrorCode::TP_32BIT : ErrorCode::TP_64BIT; | |
jln (very slow on Chromium)
2014/06/24 23:51:31
TP_32BIT vs TP_64BIT is one of the most hairy part
mdempsky
2014/06/25 23:50:21
Hm, I'll think about it some more. I've put a TOD
| |
185 if (mask == static_cast<uint64_t>(-1)) { | |
186 // Arg == Val | |
187 return BoolExpr(new const PrimitiveBoolExprImpl( | |
188 num, arg_type, ErrorCode::OP_EQUAL, val)); | |
189 } else if (mask == val) { | |
190 // (Arg & Mask) == Mask | |
191 return BoolExpr(new const PrimitiveBoolExprImpl( | |
192 num, arg_type, ErrorCode::OP_HAS_ALL_BITS, mask)); | |
193 } else if (val == 0) { | |
194 // (Arg & Mask) == 0, which is semantically equivalent to !((arg & mask) != | |
195 // 0). | |
196 return !BoolExpr(new const PrimitiveBoolExprImpl( | |
197 num, arg_type, ErrorCode::OP_HAS_ANY_BITS, mask)); | |
198 } else { | |
199 NOTREACHED() << "Unimplemented ArgEq case"; | |
jln (very slow on Chromium)
2014/06/24 23:51:31
I wonder if we shouldn't CHECK(false) here. This c
mdempsky
2014/06/25 23:50:21
Done, though if we reach here, we'd later null poi
| |
200 return BoolExpr(); | |
201 } | |
202 } | |
203 | |
204 } // namespace internal | |
205 | |
206 ResultExpr Allow() { | |
207 return ResultExpr(new const AllowResultExprImpl()); | |
208 } | |
209 | |
210 ResultExpr Error(int err) { | |
211 return ResultExpr(new const ErrorResultExprImpl(err)); | |
212 } | |
213 | |
214 ResultExpr Trap(TrapFnc trap_func, void* aux) { | |
215 return ResultExpr(new const TrapResultExprImpl(trap_func, aux)); | |
216 } | |
217 | |
218 BoolExpr operator!(BoolExpr cond) { | |
219 return BoolExpr(new const NegateBoolExprImpl(cond)); | |
220 } | |
221 | |
222 BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs) { | |
223 return BoolExpr(new const AndBoolExprImpl(lhs, rhs)); | |
224 } | |
225 | |
226 BoolExpr operator||(BoolExpr lhs, BoolExpr rhs) { | |
227 return BoolExpr(new const OrBoolExprImpl(lhs, rhs)); | |
228 } | |
229 | |
230 Elser If(BoolExpr cond, ResultExpr then_result) { | |
231 return Elser(IfThen::Cons(cond, then_result, IfThenList())); | |
232 } | |
233 | |
234 Elser::Elser(IfThenList if_then_list) : if_then_list_(if_then_list) { | |
235 } | |
236 | |
237 Elser::Elser(const Elser& elser) : if_then_list_(elser.if_then_list_) { | |
238 } | |
239 | |
240 Elser::~Elser() { | |
241 } | |
242 | |
243 Elser Elser::ElseIf(BoolExpr cond, ResultExpr then_result) const { | |
244 return Elser(IfThen::Cons(cond, then_result, if_then_list_)); | |
245 } | |
246 | |
247 ResultExpr Elser::Else(ResultExpr else_result) const { | |
248 // We finally have the default result expression for this | |
249 // if/then/else sequence. Also, we've already accumulated all | |
250 // if/then pairs into a list of reverse order (i.e., lower priority | |
251 // conditions are listed before higher priority ones). E.g., an | |
252 // expression like | |
253 // | |
254 // If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4) | |
255 // | |
256 // will have built up a list like | |
257 // | |
258 // [(b3, e3), (b2, e2), (b1, e1)]. | |
259 // | |
260 // Now that we have e4, we can walk the list and create a ResultExpr | |
261 // tree like: | |
262 // | |
263 // expr = e4 | |
264 // expr = (b3 ? e3 : expr) = (b3 ? e3 : e4) | |
265 // expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4)) | |
266 // expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4))) | |
267 // | |
268 // and end up with an appropriately chained tree. | |
269 | |
270 ResultExpr expr = else_result; | |
271 for (IfThenList it = if_then_list_; it; it = it->rest) { | |
272 expr = ResultExpr(new const IfThenResultExprImpl(it->cond, it->then, expr)); | |
273 } | |
274 return expr; | |
275 } | |
276 | |
277 ResultExpr SandboxBPFDSLPolicy::InvalidSyscall() const { | |
278 return Error(ENOSYS); | |
279 } | |
280 | |
281 ErrorCode SandboxBPFDSLPolicy::EvaluateSyscall(SandboxBPF* sb, | |
282 int sysno) const { | |
283 return EvaluateSyscall(sysno)->Compile(sb); | |
284 } | |
285 | |
286 ErrorCode SandboxBPFDSLPolicy::InvalidSyscall(SandboxBPF* sb) const { | |
287 return InvalidSyscall()->Compile(sb); | |
288 } | |
289 | |
290 ResultExpr SandboxBPFDSLPolicy::Trap(::sandbox::Trap::TrapFnc trap_func, | |
291 void* aux) { | |
292 return bpf_dsl::Trap(trap_func, aux); | |
293 } | |
294 | |
295 } // namespace bpf_dsl | |
296 | |
297 } // namespace sandbox | |
OLD | NEW |