| 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
|
|
|
|
|