Index: sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h |
diff --git a/sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h b/sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4c2f913c522cc5523f05a21c1206170e9896d51a |
--- /dev/null |
+++ b/sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h |
@@ -0,0 +1,259 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ |
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ |
+ |
+#include <stdint.h> |
+ |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
+#include "sandbox/linux/seccomp-bpf/trap.h" |
+#include "sandbox/sandbox_export.h" |
+ |
+namespace sandbox { |
+class ErrorCode; |
+class SandboxBPF; |
+} |
+ |
+// The sandbox::bpf_dsl namespace provides a domain-specific language |
+// to make writing BPF policies more expressive. In general, the |
+// object types all have value semantics (i.e., they can be copied |
+// around, returned from or passed to function calls, etc. without any |
+// surprising side effects), though not all support assignment. |
+// |
+// An idiomatic and demonstrative (albeit silly) example of this API |
+// would be: |
+// |
+// #include "sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h" |
+// |
+// using namespace sandbox::bpf_dsl; |
+// |
+// class SillyPolicy : public SandboxBPFDSLPolicy { |
+// public: |
+// SillyPolicy() {} |
+// virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
+// if (sysno == __NR_fcntl) { |
+// Arg<int> fd(0), cmd(1); |
+// Arg<unsigned long> flags(2); |
+// const unsigned long kBadFlags = ~(O_ACCMODE|O_NONBLOCK); |
+// return If(fd == 0 && cmd == F_SETFL && |
+// (flags & kBadFlags) == 0).Then( |
+// Allow() |
+// ).ElseIf(cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC).Then( |
+// Error(EMFILE) |
+// ).Else( |
+// Trap(SetFlagHandler, NULL) |
+// ); |
+// } |
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.
|
+// return Allow(); |
+// } |
+// private: |
+// DISALLOW_COPY_AND_ASSIGN(SillyPolicy); |
+// }; |
+// |
+// More generally, the DSL currently supports the following grammar: |
+// |
+// result = Allow() | Error(errno) | Trap(trap_func, arg) |
+// | If(bool).Then(result)[.ElseIf(bool).Then(result)].Else(result) |
+// bool = arg == val | (arg & mask) == mask | (arg & mask) == 0 |
+// | !bool | bool && bool | bool || bool |
+// |
+// The semantics of each function and operator are intended to be |
+// intuitive, but are described in more detail below. |
+// |
+// (Credit to Sean Parent's "Inheritance is the Base Class of Evil" |
+// talk at Going Native 2013 for promoting value semantics via shared |
+// pointers to immutable state.) |
+ |
+namespace sandbox { |
+ |
+namespace bpf_dsl { |
+ |
+// Forward declarations of classes; see below for proper documentation. |
+class Thener; |
+class Elser; |
+namespace internal { |
+class ResultExprImpl; |
+class BoolExprImpl; |
+struct IfThen; |
+typedef scoped_refptr<const IfThen> IfThenList; |
+} |
+ |
+// ResultExpr is an opaque reference to an immutable result expression tree. |
+typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr; |
+ |
+// Allow specifies a result that the system call should be allowed to |
+// execute normally. |
+SANDBOX_EXPORT ResultExpr Allow(); |
+ |
+// Error specifies a result that the system call should fail with |
+// error number |err|. As a special case, Error(0) will result in the |
+// system call appearing to have succeeded, but without having any |
+// side effects. |
+SANDBOX_EXPORT ResultExpr Error(int err); |
+ |
+// Trap specifies a result that the system call should be handled by |
+// trapping back into userspace and invoking |trap_func|, passing |
+// |aux| as the second parameter. |
+SANDBOX_EXPORT ResultExpr Trap(::sandbox::Trap::TrapFnc trap_func, void* aux); |
+ |
+// BoolExpr is an opaque reference to an immutable boolean expression tree. |
+typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr; |
+ |
+template <typename T> |
+class SANDBOX_EXPORT Arg { |
+ public: |
+ // Initializes the Arg to represent the |num|th system call |
+ // argument, which is of type |T|. |
+ explicit Arg(int num) : num_(num), mask_(-1) {} |
+ |
+ Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {} |
+ |
+ // Returns an Arg representing the current argument, but after |
+ // bitwise-and'ing it with |rhs|. |
+ Arg operator&(uint64_t rhs) const { return Arg(num_, mask_ & rhs); } |
+ |
+ // Returns a boolean expression comparing whether the system call |
+ // argument (after applying any bitmasks, if appropriate) equals |rhs|. |
+ BoolExpr operator==(T rhs) const; |
+ |
+ private: |
+ Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} |
+ int num_; |
+ uint64_t mask_; |
+ DISALLOW_ASSIGN(Arg); |
+}; |
+ |
+// Various ways to combine boolean expressions into more complex expressions. |
+// They follow standard boolean algebra laws. |
+SANDBOX_EXPORT BoolExpr operator!(BoolExpr cond); |
+SANDBOX_EXPORT BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs); |
+SANDBOX_EXPORT BoolExpr operator||(BoolExpr lhs, BoolExpr rhs); |
+ |
+// If begins a conditional result expression predicated on the |
+// specified boolean expression. |
+SANDBOX_EXPORT Thener If(BoolExpr cond); |
+ |
+class SANDBOX_EXPORT Thener { |
+ public: |
+ Thener(const Thener& thener); |
+ ~Thener(); |
+ |
+ // Then associates the result expression |then_result| with the most recent |
+ // If or ElseIf clause's boolean expression. |
+ Elser Then(ResultExpr then_result) const; |
+ |
+ private: |
+ Thener(internal::IfThenList if_then_list, BoolExpr cond); |
+ internal::IfThenList if_then_list_; |
+ BoolExpr cond_; |
+ friend Thener If(BoolExpr); |
+ friend class Elser; |
+ DISALLOW_ASSIGN(Thener); |
+}; |
+ |
+class SANDBOX_EXPORT Elser { |
+ public: |
+ Elser(const Elser& elser); |
+ ~Elser(); |
+ |
+ // Else terminates a conditional result expression using |else_result| as |
+ // the default fallback result expression. |
+ ResultExpr Else(ResultExpr else_result) const; |
+ |
+ // ElseIf extends the conditional result expression with another |
+ // clause, predicated on the specified boolean expression. |
+ Thener ElseIf(BoolExpr cond) const; |
+ |
+ private: |
+ Elser(internal::IfThenList if_then_list); |
+ internal::IfThenList if_then_list_; |
+ friend class Thener; |
+ DISALLOW_ASSIGN(Elser); |
+}; |
+ |
+// 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.
|
+class SANDBOX_EXPORT SandboxBPFDSLPolicy : public SandboxBPFPolicy { |
+ public: |
+ SandboxBPFDSLPolicy() : SandboxBPFPolicy() {} |
+ |
+ // User extension point for writing custom sandbox policies. |
+ virtual ResultExpr EvaluateSyscall(int sysno) const = 0; |
+ |
+ // Optional overload for specifying alternate behavior for invalid |
+ // system calls. The default is to return ENOSYS. |
+ virtual ResultExpr InvalidSyscall() const; |
+ |
+ // Override implementations from SandboxBPFPolicy. Marked as FINAL |
+ // to prevent mixups with child classes accidentally overloading |
+ // these instead of the above methods. |
+ virtual ErrorCode EvaluateSyscall(SandboxBPF* sb, |
+ int sysno) const OVERRIDE FINAL; |
+ virtual ErrorCode InvalidSyscall(SandboxBPF* sb) const OVERRIDE FINAL; |
+ |
+ // Helper method so policies can just write Trap(func, aux). |
+ static ResultExpr Trap(::sandbox::Trap::TrapFnc trap_func, void* aux) { |
+ return bpf_dsl::Trap(trap_func, aux); |
+ } |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(SandboxBPFDSLPolicy); |
+}; |
+ |
+namespace internal { |
+ |
+// Returns a boolean expression that represents whether system call |
+// argument |num| of size |size| is equal to |val|, when masked |
+// according to |mask|. Users should use the Arg template class below |
+// instead of using this API directly. |
+SANDBOX_EXPORT BoolExpr |
+ ArgEq(int num, size_t size, uint64_t mask, uint64_t val); |
+ |
+// Internal interface implemented by BoolExpr implementations. |
+class SANDBOX_EXPORT BoolExprImpl : public base::RefCounted<BoolExprImpl> { |
+ public: |
+ BoolExprImpl() {} |
+ virtual ErrorCode Compile(SandboxBPF* sb, |
+ ErrorCode true_ec, |
+ ErrorCode false_ec) const = 0; |
+ |
+ protected: |
+ virtual ~BoolExprImpl() {} |
+ |
+ private: |
+ friend class base::RefCounted<BoolExprImpl>; |
+ DISALLOW_COPY_AND_ASSIGN(BoolExprImpl); |
+}; |
+ |
+// Internal interface implemented by ResultExpr implementations. |
+class SANDBOX_EXPORT ResultExprImpl : public base::RefCounted<ResultExprImpl> { |
+ public: |
+ ResultExprImpl() {} |
+ virtual ErrorCode Compile(SandboxBPF* sb) const = 0; |
+ |
+ protected: |
+ virtual ~ResultExprImpl() {} |
+ |
+ private: |
+ friend class base::RefCounted<ResultExprImpl>; |
+ DISALLOW_COPY_AND_ASSIGN(ResultExprImpl); |
+}; |
+ |
+} // namespace internal |
+ |
+// Definition requires ArgEq to have been declared. Moved out-of-line |
+// to minimize how much internal clutter users have to ignore while |
+// reading the header documentation. |
+template <typename T> |
+BoolExpr Arg<T>::operator==(T rhs) const { |
+ return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(rhs)); |
+} |
+ |
+} // namespace bpf_dsl |
+ |
+} // namespace sandbox |
+ |
+#endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BPF_DSL_H_ |