 Chromium Code Reviews
 Chromium Code Reviews Issue 299743002:
  Add domain-specific language for BPF policies  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 299743002:
  Add domain-specific language for BPF policies  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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_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 && | |
| 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 // } | |
| 
jln (very slow on Chromium)
2014/06/24 00:03:52
nit: else {} so that the compiler checks that the
 
mdempsky
2014/06/24 00:55:40
Done.
 | |
| 51 // return Allow(); | |
| 52 // } | |
| 53 // private: | |
| 54 // DISALLOW_COPY_AND_ASSIGN(SillyPolicy); | |
| 55 // }; | |
| 56 // | |
| 57 // More generally, the DSL currently supports the following grammar: | |
| 58 // | |
| 59 // result = Allow() | Error(errno) | Trap(trap_func, arg) | |
| 60 // | If(bool).Then(result)[.ElseIf(bool).Then(result)].Else(result) | |
| 61 // bool = arg == val | (arg & mask) == mask | (arg & mask) == 0 | |
| 62 // | !bool | bool && bool | bool || bool | |
| 63 // | |
| 64 // The semantics of each function and operator are intended to be | |
| 65 // intuitive, but are described in more detail below. | |
| 66 // | |
| 67 // (Credit to Sean Parent's "Inheritance is the Base Class of Evil" | |
| 68 // talk at Going Native 2013 for promoting value semantics via shared | |
| 69 // pointers to immutable state.) | |
| 70 | |
| 71 namespace sandbox { | |
| 72 | |
| 73 namespace bpf_dsl { | |
| 74 | |
| 75 // Forward declarations of classes; see below for proper documentation. | |
| 76 class Thener; | |
| 77 class Elser; | |
| 78 namespace internal { | |
| 79 class ResultExprImpl; | |
| 80 class BoolExprImpl; | |
| 81 struct IfThen; | |
| 82 typedef scoped_refptr<const IfThen> IfThenList; | |
| 83 } | |
| 84 | |
| 85 // ResultExpr is an opaque reference to an immutable result expression tree. | |
| 86 typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr; | |
| 87 | |
| 88 // Allow specifies a result that the system call should be allowed to | |
| 89 // execute normally. | |
| 90 SANDBOX_EXPORT ResultExpr Allow(); | |
| 91 | |
| 92 // Error specifies a result that the system call should fail with | |
| 93 // error number |err|. As a special case, Error(0) will result in the | |
| 94 // system call appearing to have succeeded, but without having any | |
| 95 // side effects. | |
| 96 SANDBOX_EXPORT ResultExpr Error(int err); | |
| 97 | |
| 98 // Trap specifies a result that the system call should be handled by | |
| 99 // trapping back into userspace and invoking |trap_func|, passing | |
| 100 // |aux| as the second parameter. | |
| 101 SANDBOX_EXPORT ResultExpr Trap(::sandbox::Trap::TrapFnc trap_func, void* aux); | |
| 102 | |
| 103 // BoolExpr is an opaque reference to an immutable boolean expression tree. | |
| 104 typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr; | |
| 105 | |
| 106 template <typename T> | |
| 107 class SANDBOX_EXPORT Arg { | |
| 108 public: | |
| 109 // Initializes the Arg to represent the |num|th system call | |
| 110 // argument, which is of type |T|. | |
| 111 explicit Arg(int num) : num_(num), mask_(-1) {} | |
| 112 | |
| 113 Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {} | |
| 114 | |
| 115 // Returns an Arg representing the current argument, but after | |
| 116 // bitwise-and'ing it with |rhs|. | |
| 117 Arg operator&(uint64_t rhs) const { return Arg(num_, mask_ & rhs); } | |
| 118 | |
| 119 // Returns a boolean expression comparing whether the system call | |
| 120 // argument (after applying any bitmasks, if appropriate) equals |rhs|. | |
| 121 BoolExpr operator==(T rhs) const; | |
| 122 | |
| 123 private: | |
| 124 Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} | |
| 125 int num_; | |
| 126 uint64_t mask_; | |
| 127 DISALLOW_ASSIGN(Arg); | |
| 128 }; | |
| 129 | |
| 130 // Various ways to combine boolean expressions into more complex expressions. | |
| 131 // They follow standard boolean algebra laws. | |
| 132 SANDBOX_EXPORT BoolExpr operator!(BoolExpr cond); | |
| 133 SANDBOX_EXPORT BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs); | |
| 134 SANDBOX_EXPORT BoolExpr operator||(BoolExpr lhs, BoolExpr rhs); | |
| 135 | |
| 136 // If begins a conditional result expression predicated on the | |
| 137 // specified boolean expression. | |
| 138 SANDBOX_EXPORT Thener If(BoolExpr cond); | |
| 139 | |
| 140 class SANDBOX_EXPORT Thener { | |
| 141 public: | |
| 142 Thener(const Thener& thener); | |
| 143 ~Thener(); | |
| 144 | |
| 145 // Then associates the result expression |then_result| with the most recent | |
| 146 // If or ElseIf clause's boolean expression. | |
| 147 Elser Then(ResultExpr then_result) const; | |
| 148 | |
| 149 private: | |
| 150 Thener(internal::IfThenList if_then_list, BoolExpr cond); | |
| 151 internal::IfThenList if_then_list_; | |
| 152 BoolExpr cond_; | |
| 153 friend Thener If(BoolExpr); | |
| 154 friend class Elser; | |
| 155 DISALLOW_ASSIGN(Thener); | |
| 156 }; | |
| 157 | |
| 158 class SANDBOX_EXPORT Elser { | |
| 159 public: | |
| 160 Elser(const Elser& elser); | |
| 161 ~Elser(); | |
| 162 | |
| 163 // Else terminates a conditional result expression using |else_result| as | |
| 164 // the default fallback result expression. | |
| 165 ResultExpr Else(ResultExpr else_result) const; | |
| 166 | |
| 167 // ElseIf extends the conditional result expression with another | |
| 168 // clause, predicated on the specified boolean expression. | |
| 169 Thener ElseIf(BoolExpr cond) const; | |
| 170 | |
| 171 private: | |
| 172 Elser(internal::IfThenList if_then_list); | |
| 173 internal::IfThenList if_then_list_; | |
| 174 friend class Thener; | |
| 175 DISALLOW_ASSIGN(Elser); | |
| 176 }; | |
| 177 | |
| 178 // Helper class to make writing policies easier. | |
| 
jln (very slow on Chromium)
2014/06/24 00:03:52
Let's have this earlier in the file as it is one o
 
mdempsky
2014/06/24 00:55:40
Done.
 | |
| 179 class SANDBOX_EXPORT SandboxBPFDSLPolicy : public SandboxBPFPolicy { | |
| 180 public: | |
| 181 SandboxBPFDSLPolicy() : SandboxBPFPolicy() {} | |
| 182 | |
| 183 // User extension point for writing custom sandbox policies. | |
| 184 virtual ResultExpr EvaluateSyscall(int sysno) const = 0; | |
| 185 | |
| 186 // Optional overload for specifying alternate behavior for invalid | |
| 187 // system calls. The default is to return ENOSYS. | |
| 188 virtual ResultExpr InvalidSyscall() const; | |
| 189 | |
| 190 // Override implementations from SandboxBPFPolicy. Marked as FINAL | |
| 191 // to prevent mixups with child classes accidentally overloading | |
| 192 // these instead of the above methods. | |
| 193 virtual ErrorCode EvaluateSyscall(SandboxBPF* sb, | |
| 194 int sysno) const OVERRIDE FINAL; | |
| 195 virtual ErrorCode InvalidSyscall(SandboxBPF* sb) const OVERRIDE FINAL; | |
| 196 | |
| 197 // Helper method so policies can just write Trap(func, aux). | |
| 198 static ResultExpr Trap(::sandbox::Trap::TrapFnc trap_func, void* aux) { | |
| 199 return bpf_dsl::Trap(trap_func, aux); | |
| 200 } | |
| 201 | |
| 202 private: | |
| 203 DISALLOW_COPY_AND_ASSIGN(SandboxBPFDSLPolicy); | |
| 204 }; | |
| 205 | |
| 206 namespace internal { | |
| 207 | |
| 208 // Returns a boolean expression that represents whether system call | |
| 209 // argument |num| of size |size| is equal to |val|, when masked | |
| 210 // according to |mask|. Users should use the Arg template class below | |
| 211 // instead of using this API directly. | |
| 212 SANDBOX_EXPORT BoolExpr | |
| 213 ArgEq(int num, size_t size, uint64_t mask, uint64_t val); | |
| 214 | |
| 215 // Internal interface implemented by BoolExpr implementations. | |
| 216 class SANDBOX_EXPORT BoolExprImpl : public base::RefCounted<BoolExprImpl> { | |
| 217 public: | |
| 218 BoolExprImpl() {} | |
| 219 virtual ErrorCode Compile(SandboxBPF* sb, | |
| 220 ErrorCode true_ec, | |
| 221 ErrorCode false_ec) const = 0; | |
| 222 | |
| 223 protected: | |
| 224 virtual ~BoolExprImpl() {} | |
| 225 | |
| 226 private: | |
| 227 friend class base::RefCounted<BoolExprImpl>; | |
| 228 DISALLOW_COPY_AND_ASSIGN(BoolExprImpl); | |
| 229 }; | |
| 230 | |
| 231 // Internal interface implemented by ResultExpr implementations. | |
| 232 class SANDBOX_EXPORT ResultExprImpl : public base::RefCounted<ResultExprImpl> { | |
| 233 public: | |
| 234 ResultExprImpl() {} | |
| 235 virtual ErrorCode Compile(SandboxBPF* sb) const = 0; | |
| 236 | |
| 237 protected: | |
| 238 virtual ~ResultExprImpl() {} | |
| 239 | |
| 240 private: | |
| 241 friend class base::RefCounted<ResultExprImpl>; | |
| 242 DISALLOW_COPY_AND_ASSIGN(ResultExprImpl); | |
| 243 }; | |
| 244 | |
| 245 } // namespace internal | |
| 246 | |
| 247 // Definition requires ArgEq to have been declared. Moved out-of-line | |
| 248 // to minimize how much internal clutter users have to ignore while | |
| 249 // reading the header documentation. | |
| 250 template <typename T> | |
| 251 BoolExpr Arg<T>::operator==(T rhs) const { | |
| 252 return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(rhs)); | |
| 253 } | |
| 254 | |
| 255 } // namespace bpf_dsl | |
| 256 | |
| 257 } // namespace sandbox | |
| 258 | |
| 259 #endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ | |
| OLD | NEW |