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