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 |
index 36ec0e11879ce1c6f0645957275aef33cd9f4c9d..37505e333cfcc20f331ffce032fc401cc42fcd15 100644 |
--- a/sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h |
+++ b/sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h |
@@ -5,100 +5,270 @@ |
#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/errorcode.h" |
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
#include "sandbox/sandbox_export.h" |
namespace sandbox { |
+struct arch_seccomp_data; |
+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 SandboxBPFPolicy { |
+// 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) |
+// ); |
+// } |
+// } |
+// 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 bpfdsl { |
+namespace bpf_dsl { |
-class CondImpl : public base::RefCounted<CondImpl> { |
- public: |
- CondImpl() {} |
- virtual ErrorCode Compile(SandboxBPF* sb, |
- ErrorCode true_ec, |
- ErrorCode false_ec) const = 0; |
+// 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; |
+} |
- protected: |
- friend class base::RefCounted<CondImpl>; |
- virtual ~CondImpl() {} |
+// ResultExpr is an opaque reference to an immutable result expression tree. |
+typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr; |
- private: |
- DISALLOW_COPY_AND_ASSIGN(CondImpl); |
-}; |
+// BoolExpr is an opaque reference to an immutable boolean expression tree. |
+typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr; |
-typedef scoped_refptr<const CondImpl> Cond; |
+// Various ways to combine boolean expressions into more complex expressions. |
+// They follow standard boolean algebra laws. |
+SANDBOX_EXPORT BoolExpr operator!(BoolExpr expr); |
+SANDBOX_EXPORT BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs); |
+SANDBOX_EXPORT BoolExpr operator||(BoolExpr lhs, BoolExpr rhs); |
-SANDBOX_EXPORT Cond operator&&(Cond lhs, Cond rhs); |
-SANDBOX_EXPORT Cond operator||(Cond lhs, Cond rhs); |
+// Allow specifies a result that the system call should be allowed to |
+// execute normally. |
+SANDBOX_EXPORT ResultExpr Allow(); |
-class Iffer; |
-class Thener; |
-class Elser; |
+// 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); |
-class SANDBOX_EXPORT Iffer { |
- public: |
- // TODO(mdempsky): Make private? |
- explicit Iffer(SandboxBPF* sb); |
- Iffer(const Iffer& iffer); |
- Thener If(Cond cond) const; |
+// TODO(mdempsky): Move elsewhere. |
+typedef intptr_t (*TrapFunc)(const arch_seccomp_data&, void*); |
- private: |
- SandboxBPF* sb_; |
- DISALLOW_ASSIGN(Iffer); |
-}; |
+// Trap specifies a result that the system call should trap and invoke |
+// the specified callback function. |
+SANDBOX_EXPORT ResultExpr Trap(TrapFunc func, void* arg); |
+ |
+// 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(); |
- Elser Then(ErrorCode ec) const; |
+ |
+ // Then associates the result expression |expr| with the most recent |
+ // If or ElseIf clause's boolean expression. |
+ Elser Then(ResultExpr expr) const; |
private: |
- Thener(SandboxBPF* sb, Cond cond); |
- SandboxBPF* sb_; |
- Cond cond_; |
- friend class Iffer; |
+ Thener(internal::IfThenList if_then_list, BoolExpr cond); |
+ internal::IfThenList if_then_list_; |
+ BoolExpr cond_; |
+ friend Thener If(BoolExpr cond); |
friend class Elser; |
- DISALLOW_COPY_AND_ASSIGN(Thener); |
+ DISALLOW_ASSIGN(Thener); |
}; |
class SANDBOX_EXPORT Elser { |
public: |
+ Elser(const Elser& elser); |
~Elser(); |
- ErrorCode Else(ErrorCode ec) const; |
+ |
+ // Else terminates a conditional result expression using |expr| as |
+ // the default fallback result expression. |
+ ResultExpr Else(ResultExpr expr) const; |
+ |
+ // ElseIf extends the conditional result expression with another |
+ // clause, predicated on the specified boolean expression. |
+ Thener ElseIf(BoolExpr cond) const; |
private: |
- Elser(SandboxBPF* sb, Cond cond, ErrorCode true_ec); |
- SandboxBPF* sb_; |
- Cond cond_; |
- ErrorCode true_ec_; |
- friend class Iffer; |
+ Elser(internal::IfThenList if_then_list); |
+ internal::IfThenList if_then_list_; |
friend class Thener; |
- DISALLOW_COPY_AND_ASSIGN(Elser); |
+ DISALLOW_ASSIGN(Elser); |
}; |
-} // namespace bpfdsl |
- |
-SANDBOX_EXPORT bpfdsl::Iffer DSL(SandboxBPF* sb); |
- |
template <typename T> |
class SANDBOX_EXPORT Arg { |
public: |
- explicit Arg(int num); |
- bpfdsl::Cond operator==(const T& rhs) const; |
+ // Initializes the Arg to represent the |num|th system call |
+ // argument, which is of type |T|. |
+ 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 a bitmask, if appropriate) equals |rhs|. |
+ BoolExpr operator==(T rhs) const; |
private: |
+ Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} |
int num_; |
- DISALLOW_COPY_AND_ASSIGN(Arg); |
+ uint64_t mask_; |
+ DISALLOW_ASSIGN(Arg); |
+}; |
+ |
+// Helper class to make writing policies easier. |
+class SANDBOX_EXPORT SandboxBPFPolicyDSL : public SandboxBPFPolicy { |
+ public: |
+ SandboxBPFPolicyDSL() : 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; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(SandboxBPFPolicyDSL); |
+}; |
+ |
+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 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); |
}; |
-extern template class Arg<int>; |
+// Internal interface implemented by ResultExpr implementations. |
+class 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); |
+}; |
+ |
+// Internal helper class. Represents a (BoolExpr, ResultExpr)-pair |
+// node in a linked list. |
+struct IfThen : public base::RefCounted<IfThen> { |
+ BoolExpr cond; |
+ ResultExpr then; |
+ IfThenList rest; |
+ |
+ // Returns a new IfThenList with a node for (cond, then) prepended |
+ // before rest. |
+ static IfThenList Cons(BoolExpr cond, ResultExpr then, IfThenList rest) { |
+ return IfThenList(new const IfThen(cond, then, rest)); |
+ } |
+ |
+ private: |
+ IfThen(BoolExpr cond, ResultExpr then, IfThenList rest); |
+ virtual ~IfThen(); |
+ friend class base::RefCounted<IfThen>; |
+ DISALLOW_COPY_AND_ASSIGN(IfThen); |
+}; |
+ |
+} // 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_, rhs); |
+} |
+ |
+} // namespace bpf_dsl |
} // namespace sandbox |