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 #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 | |
12 #include "base/macros.h" | |
13 #include "base/memory/ref_counted.h" | |
14 #include "sandbox/linux/bpf_dsl/cons.h" | |
15 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | |
16 #include "sandbox/linux/seccomp-bpf/trap.h" | |
17 #include "sandbox/sandbox_export.h" | |
18 | |
19 namespace sandbox { | |
20 class ErrorCode; | |
21 class SandboxBPF; | |
22 } | |
23 | |
24 // The sandbox::bpf_dsl namespace provides a domain-specific language | |
25 // to make writing BPF policies more expressive. In general, the | |
26 // object types all have value semantics (i.e., they can be copied | |
27 // around, returned from or passed to function calls, etc. without any | |
28 // surprising side effects), though not all support assignment. | |
29 // | |
30 // An idiomatic and demonstrative (albeit silly) example of this API | |
31 // would be: | |
32 // | |
33 // #include "sandbox/linux/bpf_dsl/bpf_dsl.h" | |
34 // | |
35 // using namespace sandbox::bpf_dsl; | |
36 // | |
37 // class SillyPolicy : public SandboxBPFDSLPolicy { | |
38 // public: | |
39 // SillyPolicy() {} | |
40 // virtual ~SillyPolicy() {} | |
41 // virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
42 // if (sysno == __NR_fcntl) { | |
43 // Arg<int> fd(0), cmd(1); | |
44 // Arg<unsigned long> flags(2); | |
45 // const unsigned long kBadFlags = ~(O_ACCMODE | O_NONBLOCK); | |
46 // return If(fd == 0 && cmd == F_SETFL && (flags & kBadFlags) == 0, | |
47 // Allow()) | |
48 // .ElseIf(cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC, | |
49 // Error(EMFILE)) | |
50 // .Else(Trap(SetFlagHandler, NULL)); | |
51 // } else { | |
52 // return Allow(); | |
53 // } | |
54 // } | |
55 // | |
56 // private: | |
57 // DISALLOW_COPY_AND_ASSIGN(SillyPolicy); | |
58 // }; | |
59 // | |
60 // More generally, the DSL currently supports the following grammar: | |
61 // | |
62 // result = Allow() | Error(errno) | Trap(trap_func, arg) | |
63 // | If(bool, result)[.ElseIf(bool, result)].Else(result) | |
64 // bool = arg == val | (arg & mask) == mask | (arg & mask) == 0 | |
65 // | !bool | bool && bool | bool || bool | |
66 // | |
67 // The semantics of each function and operator are intended to be | |
68 // intuitive, but are described in more detail below. | |
69 // | |
70 // (Credit to Sean Parent's "Inheritance is the Base Class of Evil" | |
71 // talk at Going Native 2013 for promoting value semantics via shared | |
72 // pointers to immutable state.) | |
73 | |
74 namespace sandbox { | |
75 namespace bpf_dsl { | |
76 | |
77 // Forward declarations of classes; see below for proper documentation. | |
78 class Elser; | |
79 namespace internal { | |
80 class ResultExprImpl; | |
81 class BoolExprImpl; | |
82 } | |
83 | |
84 // ResultExpr is an opaque reference to an immutable result expression tree. | |
85 typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr; | |
86 | |
87 // BoolExpr is an opaque reference to an immutable boolean expression tree. | |
88 typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr; | |
89 | |
90 // Helper class to make writing policies easier. | |
91 class SANDBOX_EXPORT SandboxBPFDSLPolicy : public SandboxBPFPolicy { | |
92 public: | |
93 SandboxBPFDSLPolicy() : SandboxBPFPolicy() {} | |
94 virtual ~SandboxBPFDSLPolicy() {} | |
95 | |
96 // User extension point for writing custom sandbox policies. | |
97 virtual ResultExpr EvaluateSyscall(int sysno) const = 0; | |
98 | |
99 // Optional overload for specifying alternate behavior for invalid | |
100 // system calls. The default is to return ENOSYS. | |
101 virtual ResultExpr InvalidSyscall() const; | |
102 | |
103 // Override implementations from SandboxBPFPolicy. Marked as FINAL | |
104 // to prevent mixups with child classes accidentally overloading | |
105 // these instead of the above methods. | |
106 virtual ErrorCode EvaluateSyscall(SandboxBPF* sb, | |
107 int sysno) const OVERRIDE FINAL; | |
108 virtual ErrorCode InvalidSyscall(SandboxBPF* sb) const OVERRIDE FINAL; | |
109 | |
110 // Helper method so policies can just write Trap(func, aux). | |
111 static ResultExpr Trap(::sandbox::Trap::TrapFnc trap_func, void* aux); | |
112 | |
113 private: | |
114 DISALLOW_COPY_AND_ASSIGN(SandboxBPFDSLPolicy); | |
115 }; | |
116 | |
117 // Allow specifies a result that the system call should be allowed to | |
118 // execute normally. | |
119 SANDBOX_EXPORT ResultExpr Allow(); | |
120 | |
121 // Error specifies a result that the system call should fail with | |
122 // error number |err|. As a special case, Error(0) will result in the | |
123 // system call appearing to have succeeded, but without having any | |
124 // side effects. | |
125 SANDBOX_EXPORT ResultExpr Error(int err); | |
126 | |
127 // Trap specifies a result that the system call should be handled by | |
128 // trapping back into userspace and invoking |trap_func|, passing | |
129 // |aux| as the second parameter. | |
130 SANDBOX_EXPORT ResultExpr Trap(::sandbox::Trap::TrapFnc trap_func, void* aux); | |
131 | |
132 template <typename T> | |
133 class SANDBOX_EXPORT Arg { | |
134 public: | |
135 // Initializes the Arg to represent the |num|th system call | |
136 // argument (indexed from 0), which is of type |T|. | |
137 explicit Arg(int num) : num_(num), mask_(-1) {} | |
138 | |
139 Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {} | |
140 | |
141 // Returns an Arg representing the current argument, but after | |
142 // bitwise-and'ing it with |rhs|. | |
143 Arg operator&(uint64_t rhs) const { return Arg(num_, mask_ & rhs); } | |
144 | |
145 // Returns a boolean expression comparing whether the system call | |
146 // argument (after applying any bitmasks, if appropriate) equals |rhs|. | |
147 BoolExpr operator==(T rhs) const; | |
148 | |
149 private: | |
150 Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} | |
151 int num_; | |
152 uint64_t mask_; | |
153 DISALLOW_ASSIGN(Arg); | |
154 }; | |
155 | |
156 // Various ways to combine boolean expressions into more complex expressions. | |
157 // They follow standard boolean algebra laws. | |
158 SANDBOX_EXPORT BoolExpr operator!(BoolExpr cond); | |
159 SANDBOX_EXPORT BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs); | |
160 SANDBOX_EXPORT BoolExpr operator||(BoolExpr lhs, BoolExpr rhs); | |
161 | |
162 // If begins a conditional result expression predicated on the | |
163 // specified boolean expression. | |
164 SANDBOX_EXPORT Elser If(BoolExpr cond, ResultExpr then_result); | |
165 | |
166 class SANDBOX_EXPORT Elser { | |
167 public: | |
168 Elser(const Elser& elser); | |
169 ~Elser(); | |
170 | |
171 // ElseIf extends the conditional result expression with another | |
172 // "if then" clause, predicated on the specified boolean expression. | |
173 Elser ElseIf(BoolExpr cond, ResultExpr then_result) const; | |
174 | |
175 // Else terminates a conditional result expression using |else_result| as | |
176 // the default fallback result expression. | |
177 ResultExpr Else(ResultExpr else_result) const; | |
178 | |
179 private: | |
180 typedef std::pair<BoolExpr, ResultExpr> Clause; | |
181 explicit Elser(Cons<Clause>::List clause_list); | |
182 Cons<Clause>::List clause_list_; | |
183 friend Elser If(BoolExpr, ResultExpr); | |
184 DISALLOW_ASSIGN(Elser); | |
185 }; | |
186 | |
187 // ===================================================================== | |
188 // Official API ends here. | |
189 // ===================================================================== | |
190 | |
191 // Definitions below are necessary here only for C++03 compatibility. | |
192 // Once C++11 is available, they should be moved into bpf_dsl.cc via extern | |
193 // templates. | |
194 namespace internal { | |
195 | |
196 // Returns a boolean expression that represents whether system call | |
197 // argument |num| of size |size| is equal to |val|, when masked | |
198 // according to |mask|. Users should use the Arg template class below | |
199 // instead of using this API directly. | |
200 SANDBOX_EXPORT BoolExpr | |
201 ArgEq(int num, size_t size, uint64_t mask, uint64_t val); | |
202 | |
203 // Internal interface implemented by BoolExpr implementations. | |
204 class SANDBOX_EXPORT BoolExprImpl : public base::RefCounted<BoolExprImpl> { | |
205 public: | |
206 BoolExprImpl() {} | |
207 virtual ErrorCode Compile(SandboxBPF* sb, | |
208 ErrorCode true_ec, | |
209 ErrorCode false_ec) const = 0; | |
210 | |
211 protected: | |
212 virtual ~BoolExprImpl() {} | |
213 | |
214 private: | |
215 friend class base::RefCounted<BoolExprImpl>; | |
216 DISALLOW_COPY_AND_ASSIGN(BoolExprImpl); | |
217 }; | |
218 | |
219 // Internal interface implemented by ResultExpr implementations. | |
220 class SANDBOX_EXPORT ResultExprImpl : public base::RefCounted<ResultExprImpl> { | |
221 public: | |
222 ResultExprImpl() {} | |
223 virtual ErrorCode Compile(SandboxBPF* sb) const = 0; | |
224 | |
225 protected: | |
226 virtual ~ResultExprImpl() {} | |
227 | |
228 private: | |
229 friend class base::RefCounted<ResultExprImpl>; | |
230 DISALLOW_COPY_AND_ASSIGN(ResultExprImpl); | |
231 }; | |
232 | |
233 } // namespace internal | |
234 | |
235 // Definition requires ArgEq to have been declared. Moved out-of-line | |
236 // to minimize how much internal clutter users have to ignore while | |
237 // reading the header documentation. | |
238 template <typename T> | |
239 BoolExpr Arg<T>::operator==(T rhs) const { | |
240 return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(rhs)); | |
241 } | |
242 | |
243 } // namespace bpf_dsl | |
244 } // namespace sandbox | |
245 | |
246 #endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_ | |
OLD | NEW |