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

Side by Side Diff: sandbox/linux/bpf_dsl/bpf_dsl.h

Issue 670183003: Update from chromium 62675d9fb31fb8cedc40f68e78e8445a74f362e7 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 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
« no previous file with comments | « sandbox/linux/bpf_dsl/DEPS ('k') | sandbox/linux/bpf_dsl/bpf_dsl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 #ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
6 #define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
7
8 #include <stdint.h>
9
10 #include <utility>
11 #include <vector>
12
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "sandbox/linux/bpf_dsl/cons.h"
16 #include "sandbox/linux/bpf_dsl/trap_registry.h"
17 #include "sandbox/sandbox_export.h"
18
19 // The sandbox::bpf_dsl namespace provides a domain-specific language
20 // to make writing BPF policies more expressive. In general, the
21 // object types all have value semantics (i.e., they can be copied
22 // around, returned from or passed to function calls, etc. without any
23 // surprising side effects), though not all support assignment.
24 //
25 // An idiomatic and demonstrative (albeit silly) example of this API
26 // would be:
27 //
28 // #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
29 //
30 // using namespace sandbox::bpf_dsl;
31 //
32 // class SillyPolicy : public SandboxBPFDSLPolicy {
33 // public:
34 // SillyPolicy() {}
35 // virtual ~SillyPolicy() {}
36 // virtual ResultExpr EvaluateSyscall(int sysno) const override {
37 // if (sysno == __NR_fcntl) {
38 // Arg<int> fd(0), cmd(1);
39 // Arg<unsigned long> flags(2);
40 // const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
41 // return If(fd == 0 && cmd == F_SETFL && (flags & ~kGoodFlags) == 0,
42 // Allow())
43 // .ElseIf(cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC,
44 // Error(EMFILE))
45 // .Else(Trap(SetFlagHandler, NULL));
46 // } else {
47 // return Allow();
48 // }
49 // }
50 //
51 // private:
52 // DISALLOW_COPY_AND_ASSIGN(SillyPolicy);
53 // };
54 //
55 // More generally, the DSL currently supports the following grammar:
56 //
57 // result = Allow() | Error(errno) | Kill(msg) | Trace(aux)
58 // | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux)
59 // | If(bool, result)[.ElseIf(bool, result)].Else(result)
60 // | Switch(arg)[.Case(val, result)].Default(result)
61 // bool = BoolConst(boolean) | !bool | bool && bool | bool || bool
62 // | arg == val | arg != val
63 // arg = Arg<T>(num) | arg & mask
64 //
65 // The semantics of each function and operator are intended to be
66 // intuitive, but are described in more detail below.
67 //
68 // (Credit to Sean Parent's "Inheritance is the Base Class of Evil"
69 // talk at Going Native 2013 for promoting value semantics via shared
70 // pointers to immutable state.)
71
72 namespace sandbox {
73 namespace bpf_dsl {
74
75 // Forward declarations of classes; see below for proper documentation.
76 class Elser;
77 template <typename T>
78 class Caser;
79 namespace internal {
80 class ResultExprImpl;
81 class BoolExprImpl;
82 }
83
84 } // namespace bpf_dsl
85 } // namespace sandbox
86
87 extern template class SANDBOX_EXPORT
88 scoped_refptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
89 extern template class SANDBOX_EXPORT
90 scoped_refptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
91
92 namespace sandbox {
93 namespace bpf_dsl {
94
95 // ResultExpr is an opaque reference to an immutable result expression tree.
96 typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr;
97
98 // BoolExpr is an opaque reference to an immutable boolean expression tree.
99 typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr;
100
101 // Interface to implement to define a BPF sandbox policy.
102 // TODO(mdempsky): "sandbox::bpf_dsl::SandboxBPFDSLPolicy" is
103 // tediously repetitive; rename to just "Policy".
104 class SANDBOX_EXPORT SandboxBPFDSLPolicy {
105 public:
106 SandboxBPFDSLPolicy() {}
107 virtual ~SandboxBPFDSLPolicy() {}
108
109 // User extension point for writing custom sandbox policies.
110 // The returned ResultExpr will control how the kernel responds to the
111 // specified system call number.
112 virtual ResultExpr EvaluateSyscall(int sysno) const = 0;
113
114 // Optional overload for specifying alternate behavior for invalid
115 // system calls. The default is to return ENOSYS.
116 virtual ResultExpr InvalidSyscall() const;
117
118 // Helper method so policies can just write Trap(func, aux).
119 static ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux);
120
121 private:
122 DISALLOW_COPY_AND_ASSIGN(SandboxBPFDSLPolicy);
123 };
124
125 // Allow specifies a result that the system call should be allowed to
126 // execute normally.
127 SANDBOX_EXPORT ResultExpr Allow();
128
129 // Error specifies a result that the system call should fail with
130 // error number |err|. As a special case, Error(0) will result in the
131 // system call appearing to have succeeded, but without having any
132 // side effects.
133 SANDBOX_EXPORT ResultExpr Error(int err);
134
135 // Kill specifies a result to kill the program and print an error message.
136 SANDBOX_EXPORT ResultExpr Kill(const char* msg);
137
138 // Trace specifies a result to notify a tracing process via the
139 // PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call.
140 // The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG.
141 SANDBOX_EXPORT ResultExpr Trace(uint16_t aux);
142
143 // Trap specifies a result that the system call should be handled by
144 // trapping back into userspace and invoking |trap_func|, passing
145 // |aux| as the second parameter.
146 SANDBOX_EXPORT ResultExpr
147 Trap(TrapRegistry::TrapFnc trap_func, const void* aux);
148
149 // UnsafeTrap is like Trap, except the policy is marked as "unsafe"
150 // and allowed to use SandboxSyscall to invoke any system call.
151 //
152 // NOTE: This feature, by definition, disables all security features of
153 // the sandbox. It should never be used in production, but it can be
154 // very useful to diagnose code that is incompatible with the sandbox.
155 // If even a single system call returns "UnsafeTrap", the security of
156 // entire sandbox should be considered compromised.
157 SANDBOX_EXPORT ResultExpr
158 UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux);
159
160 // BoolConst converts a bool value into a BoolExpr.
161 SANDBOX_EXPORT BoolExpr BoolConst(bool value);
162
163 // Various ways to combine boolean expressions into more complex expressions.
164 // They follow standard boolean algebra laws.
165 SANDBOX_EXPORT BoolExpr operator!(const BoolExpr& cond);
166 SANDBOX_EXPORT BoolExpr operator&&(const BoolExpr& lhs, const BoolExpr& rhs);
167 SANDBOX_EXPORT BoolExpr operator||(const BoolExpr& lhs, const BoolExpr& rhs);
168
169 template <typename T>
170 class SANDBOX_EXPORT Arg {
171 public:
172 // Initializes the Arg to represent the |num|th system call
173 // argument (indexed from 0), which is of type |T|.
174 explicit Arg(int num);
175
176 Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {}
177
178 // Returns an Arg representing the current argument, but after
179 // bitwise-and'ing it with |rhs|.
180 friend Arg operator&(const Arg& lhs, uint64_t rhs) {
181 return Arg(lhs.num_, lhs.mask_ & rhs);
182 }
183
184 // Returns a boolean expression comparing whether the system call argument
185 // (after applying any bitmasks, if appropriate) equals |rhs|.
186 friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); }
187
188 // Returns a boolean expression comparing whether the system call argument
189 // (after applying any bitmasks, if appropriate) does not equal |rhs|.
190 friend BoolExpr operator!=(const Arg& lhs, T rhs) { return !(lhs == rhs); }
191
192 private:
193 Arg(int num, uint64_t mask) : num_(num), mask_(mask) {}
194
195 BoolExpr EqualTo(T val) const;
196
197 int num_;
198 uint64_t mask_;
199
200 DISALLOW_ASSIGN(Arg);
201 };
202
203 // If begins a conditional result expression predicated on the
204 // specified boolean expression.
205 SANDBOX_EXPORT Elser If(const BoolExpr& cond, const ResultExpr& then_result);
206
207 class SANDBOX_EXPORT Elser {
208 public:
209 Elser(const Elser& elser);
210 ~Elser();
211
212 // ElseIf extends the conditional result expression with another
213 // "if then" clause, predicated on the specified boolean expression.
214 Elser ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const;
215
216 // Else terminates a conditional result expression using |else_result| as
217 // the default fallback result expression.
218 ResultExpr Else(const ResultExpr& else_result) const;
219
220 private:
221 typedef std::pair<BoolExpr, ResultExpr> Clause;
222
223 explicit Elser(cons::List<Clause> clause_list);
224
225 cons::List<Clause> clause_list_;
226
227 friend Elser If(const BoolExpr&, const ResultExpr&);
228 template <typename T>
229 friend Caser<T> Switch(const Arg<T>&);
230 DISALLOW_ASSIGN(Elser);
231 };
232
233 // Switch begins a switch expression dispatched according to the
234 // specified argument value.
235 template <typename T>
236 SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg);
237
238 template <typename T>
239 class SANDBOX_EXPORT Caser {
240 public:
241 Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {}
242 ~Caser() {}
243
244 // Case adds a single-value "case" clause to the switch.
245 Caser<T> Case(T value, ResultExpr result) const;
246
247 // Cases adds a multiple-value "case" clause to the switch.
248 // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way
249 // of using this function.
250 Caser<T> Cases(const std::vector<T>& values, ResultExpr result) const;
251
252 // Terminate the switch with a "default" clause.
253 ResultExpr Default(ResultExpr result) const;
254
255 private:
256 Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {}
257
258 Arg<T> arg_;
259 Elser elser_;
260
261 template <typename U>
262 friend Caser<U> Switch(const Arg<U>&);
263 DISALLOW_ASSIGN(Caser);
264 };
265
266 // Recommended usage is to put
267 // #define CASES SANDBOX_BPF_DSL_CASES
268 // near the top of the .cc file (e.g., nearby any "using" statements), then
269 // use like:
270 // Switch(arg).CASES((3, 5, 7), result)...;
271 #define SANDBOX_BPF_DSL_CASES(values, result) \
272 Cases(SANDBOX_BPF_DSL_CASES_HELPER values, result)
273
274 // Helper macro to construct a std::vector from an initializer list.
275 // TODO(mdempsky): Convert to use C++11 initializer lists instead.
276 #define SANDBOX_BPF_DSL_CASES_HELPER(value, ...) \
277 ({ \
278 const __typeof__(value) bpf_dsl_cases_values[] = {value, __VA_ARGS__}; \
279 std::vector<__typeof__(value)>( \
280 bpf_dsl_cases_values, \
281 bpf_dsl_cases_values + arraysize(bpf_dsl_cases_values)); \
282 })
283
284 // =====================================================================
285 // Official API ends here.
286 // =====================================================================
287
288 namespace internal {
289
290 // Make argument-dependent lookup work. This is necessary because although
291 // BoolExpr is defined in bpf_dsl, since it's merely a typedef for
292 // scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only
293 // searches the "internal" nested namespace.
294 using bpf_dsl::operator!;
295 using bpf_dsl::operator||;
296 using bpf_dsl::operator&&;
297
298 // Returns a boolean expression that represents whether system call
299 // argument |num| of size |size| is equal to |val|, when masked
300 // according to |mask|. Users should use the Arg template class below
301 // instead of using this API directly.
302 SANDBOX_EXPORT BoolExpr
303 ArgEq(int num, size_t size, uint64_t mask, uint64_t val);
304
305 // Returns the default mask for a system call argument of the specified size.
306 SANDBOX_EXPORT uint64_t DefaultMask(size_t size);
307
308 } // namespace internal
309
310 template <typename T>
311 Arg<T>::Arg(int num)
312 : num_(num), mask_(internal::DefaultMask(sizeof(T))) {
313 }
314
315 // Definition requires ArgEq to have been declared. Moved out-of-line
316 // to minimize how much internal clutter users have to ignore while
317 // reading the header documentation.
318 //
319 // Additionally, we use this helper member function to avoid linker errors
320 // caused by defining operator== out-of-line. For a more detailed explanation,
321 // see http://www.parashift.com/c++-faq-lite/template-friends.html.
322 template <typename T>
323 BoolExpr Arg<T>::EqualTo(T val) const {
324 return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
325 }
326
327 template <typename T>
328 SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) {
329 return Caser<T>(arg, Elser(nullptr));
330 }
331
332 template <typename T>
333 Caser<T> Caser<T>::Case(T value, ResultExpr result) const {
334 return SANDBOX_BPF_DSL_CASES((value), result);
335 }
336
337 template <typename T>
338 Caser<T> Caser<T>::Cases(const std::vector<T>& values,
339 ResultExpr result) const {
340 // Theoretically we could evaluate arg_ just once and emit a more efficient
341 // dispatch table, but for now we simply translate into an equivalent
342 // If/ElseIf/Else chain.
343
344 typedef typename std::vector<T>::const_iterator Iter;
345 BoolExpr test = BoolConst(false);
346 for (Iter i = values.begin(), end = values.end(); i != end; ++i) {
347 test = test || (arg_ == *i);
348 }
349 return Caser<T>(arg_, elser_.ElseIf(test, result));
350 }
351
352 template <typename T>
353 ResultExpr Caser<T>::Default(ResultExpr result) const {
354 return elser_.Else(result);
355 }
356
357 } // namespace bpf_dsl
358 } // namespace sandbox
359
360 #endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
OLDNEW
« no previous file with comments | « sandbox/linux/bpf_dsl/DEPS ('k') | sandbox/linux/bpf_dsl/bpf_dsl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698