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

Side by Side Diff: sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h

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

Powered by Google App Engine
This is Rietveld 408576698