OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ | 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ |
6 #define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ | 6 #define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ |
7 | 7 |
| 8 #include <stdint.h> |
| 9 |
8 #include "base/macros.h" | 10 #include "base/macros.h" |
9 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
10 #include "sandbox/linux/seccomp-bpf/errorcode.h" | 12 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
11 #include "sandbox/sandbox_export.h" | 13 #include "sandbox/sandbox_export.h" |
12 | 14 |
13 namespace sandbox { | 15 namespace sandbox { |
| 16 struct arch_seccomp_data; |
| 17 class ErrorCode; |
14 class SandboxBPF; | 18 class SandboxBPF; |
15 } | 19 } |
16 | 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 SandboxBPFPolicy { |
| 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 && |
| 43 // (flags & kBadFlags) == 0).Then( |
| 44 // Allow() |
| 45 // ).ElseIf(cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC).Then( |
| 46 // Error(EMFILE) |
| 47 // ).Else( |
| 48 // Trap(SetFlagHandler, NULL) |
| 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).Then(result)[.ElseIf(bool).Then(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 |
17 namespace sandbox { | 70 namespace sandbox { |
18 | 71 |
19 namespace bpfdsl { | 72 namespace bpf_dsl { |
20 | 73 |
21 class CondImpl : public base::RefCounted<CondImpl> { | 74 // Forward declarations of classes; see below for proper documentation. |
22 public: | 75 class Thener; |
23 CondImpl() {} | 76 class Elser; |
| 77 namespace internal { |
| 78 class ResultExprImpl; |
| 79 class BoolExprImpl; |
| 80 struct IfThen; |
| 81 typedef scoped_refptr<const IfThen> IfThenList; |
| 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 // Various ways to combine boolean expressions into more complex expressions. |
| 91 // They follow standard boolean algebra laws. |
| 92 SANDBOX_EXPORT BoolExpr operator!(BoolExpr expr); |
| 93 SANDBOX_EXPORT BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs); |
| 94 SANDBOX_EXPORT BoolExpr operator||(BoolExpr lhs, BoolExpr rhs); |
| 95 |
| 96 // Allow specifies a result that the system call should be allowed to |
| 97 // execute normally. |
| 98 SANDBOX_EXPORT ResultExpr Allow(); |
| 99 |
| 100 // Error specifies a result that the system call should fail with |
| 101 // error number |err|. As a special case, Error(0) will result in the |
| 102 // system call appearing to have succeeded, but without having any |
| 103 // side effects. |
| 104 SANDBOX_EXPORT ResultExpr Error(int err); |
| 105 |
| 106 // TODO(mdempsky): Move elsewhere. |
| 107 typedef intptr_t (*TrapFunc)(const arch_seccomp_data&, void*); |
| 108 |
| 109 // Trap specifies a result that the system call should trap and invoke |
| 110 // the specified callback function. |
| 111 SANDBOX_EXPORT ResultExpr Trap(TrapFunc func, void* arg); |
| 112 |
| 113 // If begins a conditional result expression predicated on the |
| 114 // specified boolean expression. |
| 115 SANDBOX_EXPORT Thener If(BoolExpr cond); |
| 116 |
| 117 class SANDBOX_EXPORT Thener { |
| 118 public: |
| 119 Thener(const Thener& thener); |
| 120 ~Thener(); |
| 121 |
| 122 // Then associates the result expression |expr| with the most recent |
| 123 // If or ElseIf clause's boolean expression. |
| 124 Elser Then(ResultExpr expr) const; |
| 125 |
| 126 private: |
| 127 Thener(internal::IfThenList if_then_list, BoolExpr cond); |
| 128 internal::IfThenList if_then_list_; |
| 129 BoolExpr cond_; |
| 130 friend Thener If(BoolExpr cond); |
| 131 friend class Elser; |
| 132 DISALLOW_ASSIGN(Thener); |
| 133 }; |
| 134 |
| 135 class SANDBOX_EXPORT Elser { |
| 136 public: |
| 137 Elser(const Elser& elser); |
| 138 ~Elser(); |
| 139 |
| 140 // Else terminates a conditional result expression using |expr| as |
| 141 // the default fallback result expression. |
| 142 ResultExpr Else(ResultExpr expr) const; |
| 143 |
| 144 // ElseIf extends the conditional result expression with another |
| 145 // clause, predicated on the specified boolean expression. |
| 146 Thener ElseIf(BoolExpr cond) const; |
| 147 |
| 148 private: |
| 149 Elser(internal::IfThenList if_then_list); |
| 150 internal::IfThenList if_then_list_; |
| 151 friend class Thener; |
| 152 DISALLOW_ASSIGN(Elser); |
| 153 }; |
| 154 |
| 155 template <typename T> |
| 156 class SANDBOX_EXPORT Arg { |
| 157 public: |
| 158 // Initializes the Arg to represent the |num|th system call |
| 159 // argument, which is of type |T|. |
| 160 Arg(int num) : num_(num), mask_(-1) {} |
| 161 |
| 162 Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {} |
| 163 |
| 164 // Returns an Arg representing the current argument, but after |
| 165 // bitwise-and'ing it with |rhs|. |
| 166 Arg operator&(uint64_t rhs) const { return Arg(num_, mask_ & rhs); } |
| 167 |
| 168 // Returns a boolean expression comparing whether the system call |
| 169 // argument (after applying a bitmask, if appropriate) equals |rhs|. |
| 170 BoolExpr operator==(T rhs) const; |
| 171 |
| 172 private: |
| 173 Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} |
| 174 int num_; |
| 175 uint64_t mask_; |
| 176 DISALLOW_ASSIGN(Arg); |
| 177 }; |
| 178 |
| 179 // Helper class to make writing policies easier. |
| 180 class SANDBOX_EXPORT SandboxBPFPolicyDSL : public SandboxBPFPolicy { |
| 181 public: |
| 182 SandboxBPFPolicyDSL() : SandboxBPFPolicy() {} |
| 183 |
| 184 // User extension point for writing custom sandbox policies. |
| 185 virtual ResultExpr EvaluateSyscall(int sysno) const = 0; |
| 186 |
| 187 // Optional overload for specifying alternate behavior for invalid |
| 188 // system calls. The default is to return ENOSYS. |
| 189 virtual ResultExpr InvalidSyscall() const; |
| 190 |
| 191 // Override implementations from SandboxBPFPolicy. Marked as FINAL |
| 192 // to prevent mixups with child classes accidentally overloading |
| 193 // these instead of the above methods. |
| 194 virtual ErrorCode EvaluateSyscall(SandboxBPF* sb, |
| 195 int sysno) const OVERRIDE FINAL; |
| 196 virtual ErrorCode InvalidSyscall(SandboxBPF* sb) const OVERRIDE FINAL; |
| 197 |
| 198 private: |
| 199 DISALLOW_COPY_AND_ASSIGN(SandboxBPFPolicyDSL); |
| 200 }; |
| 201 |
| 202 namespace internal { |
| 203 |
| 204 // Returns a boolean expression that represents whether system call |
| 205 // argument |num| of size |size| is equal to |val|, when masked |
| 206 // according to |mask|. Users should use the Arg template class below |
| 207 // instead of using this API directly. |
| 208 SANDBOX_EXPORT BoolExpr |
| 209 ArgEq(int num, size_t size, uint64_t mask, uint64_t val); |
| 210 |
| 211 // Internal interface implemented by BoolExpr implementations. |
| 212 class BoolExprImpl : public base::RefCounted<BoolExprImpl> { |
| 213 public: |
| 214 BoolExprImpl() {} |
24 virtual ErrorCode Compile(SandboxBPF* sb, | 215 virtual ErrorCode Compile(SandboxBPF* sb, |
25 ErrorCode true_ec, | 216 ErrorCode true_ec, |
26 ErrorCode false_ec) const = 0; | 217 ErrorCode false_ec) const = 0; |
27 | 218 |
28 protected: | 219 protected: |
29 friend class base::RefCounted<CondImpl>; | 220 virtual ~BoolExprImpl() {} |
30 virtual ~CondImpl() {} | 221 |
31 | 222 private: |
32 private: | 223 friend class base::RefCounted<BoolExprImpl>; |
33 DISALLOW_COPY_AND_ASSIGN(CondImpl); | 224 DISALLOW_COPY_AND_ASSIGN(BoolExprImpl); |
34 }; | 225 }; |
35 | 226 |
36 typedef scoped_refptr<const CondImpl> Cond; | 227 // Internal interface implemented by ResultExpr implementations. |
37 | 228 class ResultExprImpl : public base::RefCounted<ResultExprImpl> { |
38 SANDBOX_EXPORT Cond operator&&(Cond lhs, Cond rhs); | 229 public: |
39 SANDBOX_EXPORT Cond operator||(Cond lhs, Cond rhs); | 230 ResultExprImpl() {} |
40 | 231 virtual ErrorCode Compile(SandboxBPF* sb) const = 0; |
41 class Iffer; | 232 |
42 class Thener; | 233 protected: |
43 class Elser; | 234 virtual ~ResultExprImpl() {} |
44 | 235 |
45 class SANDBOX_EXPORT Iffer { | 236 private: |
46 public: | 237 friend class base::RefCounted<ResultExprImpl>; |
47 // TODO(mdempsky): Make private? | 238 DISALLOW_COPY_AND_ASSIGN(ResultExprImpl); |
48 explicit Iffer(SandboxBPF* sb); | 239 }; |
49 Iffer(const Iffer& iffer); | 240 |
50 Thener If(Cond cond) const; | 241 // Internal helper class. Represents a (BoolExpr, ResultExpr)-pair |
51 | 242 // node in a linked list. |
52 private: | 243 struct IfThen : public base::RefCounted<IfThen> { |
53 SandboxBPF* sb_; | 244 BoolExpr cond; |
54 DISALLOW_ASSIGN(Iffer); | 245 ResultExpr then; |
55 }; | 246 IfThenList rest; |
56 | 247 |
57 class SANDBOX_EXPORT Thener { | 248 // Returns a new IfThenList with a node for (cond, then) prepended |
58 public: | 249 // before rest. |
59 ~Thener(); | 250 static IfThenList Cons(BoolExpr cond, ResultExpr then, IfThenList rest) { |
60 Elser Then(ErrorCode ec) const; | 251 return IfThenList(new const IfThen(cond, then, rest)); |
61 | 252 } |
62 private: | 253 |
63 Thener(SandboxBPF* sb, Cond cond); | 254 private: |
64 SandboxBPF* sb_; | 255 IfThen(BoolExpr cond, ResultExpr then, IfThenList rest); |
65 Cond cond_; | 256 virtual ~IfThen(); |
66 friend class Iffer; | 257 friend class base::RefCounted<IfThen>; |
67 friend class Elser; | 258 DISALLOW_COPY_AND_ASSIGN(IfThen); |
68 DISALLOW_COPY_AND_ASSIGN(Thener); | 259 }; |
69 }; | 260 |
70 | 261 } // namespace internal |
71 class SANDBOX_EXPORT Elser { | 262 |
72 public: | 263 // Definition requires ArgEq to have been declared. Moved out-of-line |
73 ~Elser(); | 264 // to minimize how much internal clutter users have to ignore while |
74 ErrorCode Else(ErrorCode ec) const; | 265 // reading the header documentation. |
75 | |
76 private: | |
77 Elser(SandboxBPF* sb, Cond cond, ErrorCode true_ec); | |
78 SandboxBPF* sb_; | |
79 Cond cond_; | |
80 ErrorCode true_ec_; | |
81 friend class Iffer; | |
82 friend class Thener; | |
83 DISALLOW_COPY_AND_ASSIGN(Elser); | |
84 }; | |
85 | |
86 } // namespace bpfdsl | |
87 | |
88 SANDBOX_EXPORT bpfdsl::Iffer DSL(SandboxBPF* sb); | |
89 | |
90 template <typename T> | 266 template <typename T> |
91 class SANDBOX_EXPORT Arg { | 267 BoolExpr Arg<T>::operator==(T rhs) const { |
92 public: | 268 return internal::ArgEq(num_, sizeof(T), mask_, rhs); |
93 explicit Arg(int num); | 269 } |
94 bpfdsl::Cond operator==(const T& rhs) const; | 270 |
95 | 271 } // namespace bpf_dsl |
96 private: | |
97 int num_; | |
98 DISALLOW_COPY_AND_ASSIGN(Arg); | |
99 }; | |
100 | |
101 extern template class Arg<int>; | |
102 | 272 |
103 } // namespace sandbox | 273 } // namespace sandbox |
104 | 274 |
105 #endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ | 275 #endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ |
OLD | NEW |