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 |