| Index: sandbox/linux/bpf_dsl/bpf_dsl.cc | 
| diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.cc b/sandbox/linux/bpf_dsl/bpf_dsl.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..66cd09c22027902a5e7d4ed057a24d0883911365 | 
| --- /dev/null | 
| +++ b/sandbox/linux/bpf_dsl/bpf_dsl.cc | 
| @@ -0,0 +1,278 @@ | 
| +// 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. | 
| + | 
| +#include "sandbox/linux/bpf_dsl/bpf_dsl.h" | 
| + | 
| +#include <errno.h> | 
| + | 
| +#include "base/logging.h" | 
| +#include "base/memory/ref_counted.h" | 
| +#include "sandbox/linux/seccomp-bpf/errorcode.h" | 
| +#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 
| + | 
| +using namespace sandbox::bpf_dsl::internal; | 
| +typedef ::sandbox::Trap::TrapFnc TrapFnc; | 
| + | 
| +namespace sandbox { | 
| +namespace bpf_dsl { | 
| +namespace { | 
| + | 
| +class AllowResultExprImpl : public ResultExprImpl { | 
| + public: | 
| +  AllowResultExprImpl() {} | 
| +  virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | 
| +    return ErrorCode(ErrorCode::ERR_ALLOWED); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~AllowResultExprImpl() {} | 
| +  DISALLOW_COPY_AND_ASSIGN(AllowResultExprImpl); | 
| +}; | 
| + | 
| +class ErrorResultExprImpl : public ResultExprImpl { | 
| + public: | 
| +  explicit ErrorResultExprImpl(int err) : err_(err) { | 
| +    CHECK(err_ >= ErrorCode::ERR_MIN_ERRNO && err_ <= ErrorCode::ERR_MAX_ERRNO); | 
| +  } | 
| +  virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | 
| +    return ErrorCode(err_); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~ErrorResultExprImpl() {} | 
| +  int err_; | 
| +  DISALLOW_COPY_AND_ASSIGN(ErrorResultExprImpl); | 
| +}; | 
| + | 
| +class TrapResultExprImpl : public ResultExprImpl { | 
| + public: | 
| +  TrapResultExprImpl(TrapFnc func, void* arg) : func_(func), arg_(arg) { | 
| +    DCHECK(func_); | 
| +  } | 
| +  virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | 
| +    return sb->Trap(func_, arg_); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~TrapResultExprImpl() {} | 
| +  TrapFnc func_; | 
| +  void* arg_; | 
| +  DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl); | 
| +}; | 
| + | 
| +class IfThenResultExprImpl : public ResultExprImpl { | 
| + public: | 
| +  IfThenResultExprImpl(BoolExpr cond, | 
| +                       ResultExpr then_result, | 
| +                       ResultExpr else_result) | 
| +      : cond_(cond), then_result_(then_result), else_result_(else_result) {} | 
| +  virtual ErrorCode Compile(SandboxBPF* sb) const OVERRIDE { | 
| +    return cond_->Compile( | 
| +        sb, then_result_->Compile(sb), else_result_->Compile(sb)); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~IfThenResultExprImpl() {} | 
| +  BoolExpr cond_; | 
| +  ResultExpr then_result_; | 
| +  ResultExpr else_result_; | 
| +  DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl); | 
| +}; | 
| + | 
| +class PrimitiveBoolExprImpl : public BoolExprImpl { | 
| + public: | 
| +  PrimitiveBoolExprImpl(int argno, | 
| +                        ErrorCode::ArgType is_32bit, | 
| +                        ErrorCode::Operation op, | 
| +                        uint64_t value) | 
| +      : argno_(argno), is_32bit_(is_32bit), op_(op), value_(value) {} | 
| +  virtual ErrorCode Compile(SandboxBPF* sb, | 
| +                            ErrorCode true_ec, | 
| +                            ErrorCode false_ec) const OVERRIDE { | 
| +    return sb->Cond(argno_, is_32bit_, op_, value_, true_ec, false_ec); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~PrimitiveBoolExprImpl() {} | 
| +  int argno_; | 
| +  ErrorCode::ArgType is_32bit_; | 
| +  ErrorCode::Operation op_; | 
| +  uint64_t value_; | 
| +  DISALLOW_COPY_AND_ASSIGN(PrimitiveBoolExprImpl); | 
| +}; | 
| + | 
| +class NegateBoolExprImpl : public BoolExprImpl { | 
| + public: | 
| +  explicit NegateBoolExprImpl(BoolExpr cond) : cond_(cond) {} | 
| +  virtual ErrorCode Compile(SandboxBPF* sb, | 
| +                            ErrorCode true_ec, | 
| +                            ErrorCode false_ec) const OVERRIDE { | 
| +    return cond_->Compile(sb, false_ec, true_ec); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~NegateBoolExprImpl() {} | 
| +  BoolExpr cond_; | 
| +  DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl); | 
| +}; | 
| + | 
| +class AndBoolExprImpl : public BoolExprImpl { | 
| + public: | 
| +  AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs) : lhs_(lhs), rhs_(rhs) {} | 
| +  virtual ErrorCode Compile(SandboxBPF* sb, | 
| +                            ErrorCode true_ec, | 
| +                            ErrorCode false_ec) const OVERRIDE { | 
| +    return lhs_->Compile(sb, rhs_->Compile(sb, true_ec, false_ec), false_ec); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~AndBoolExprImpl() {} | 
| +  BoolExpr lhs_, rhs_; | 
| +  DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl); | 
| +}; | 
| + | 
| +class OrBoolExprImpl : public BoolExprImpl { | 
| + public: | 
| +  OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs) : lhs_(lhs), rhs_(rhs) {} | 
| +  virtual ErrorCode Compile(SandboxBPF* sb, | 
| +                            ErrorCode true_ec, | 
| +                            ErrorCode false_ec) const OVERRIDE { | 
| +    return lhs_->Compile(sb, true_ec, rhs_->Compile(sb, true_ec, false_ec)); | 
| +  } | 
| + | 
| + private: | 
| +  virtual ~OrBoolExprImpl() {} | 
| +  BoolExpr lhs_, rhs_; | 
| +  DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl); | 
| +}; | 
| + | 
| +}  // namespace | 
| + | 
| +namespace internal { | 
| + | 
| +BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) { | 
| +  CHECK(num >= 0 && num < 6); | 
| +  CHECK(size >= 1 && size <= 8); | 
| +  CHECK_NE(0U, mask) << "zero mask doesn't make sense"; | 
| +  CHECK_EQ(val, val & mask) << "val contains masked out bits"; | 
| + | 
| +  // TODO(mdempsky): Should we just always use TP_64BIT? | 
| +  const ErrorCode::ArgType arg_type = | 
| +      (size <= 4) ? ErrorCode::TP_32BIT : ErrorCode::TP_64BIT; | 
| + | 
| +  if (mask == static_cast<uint64_t>(-1)) { | 
| +    // Arg == Val | 
| +    return BoolExpr(new const PrimitiveBoolExprImpl( | 
| +        num, arg_type, ErrorCode::OP_EQUAL, val)); | 
| +  } else if (mask == val) { | 
| +    // (Arg & Mask) == Mask | 
| +    return BoolExpr(new const PrimitiveBoolExprImpl( | 
| +        num, arg_type, ErrorCode::OP_HAS_ALL_BITS, mask)); | 
| +  } else if (val == 0) { | 
| +    // (Arg & Mask) == 0, which is semantically equivalent to !((arg & mask) != | 
| +    // 0). | 
| +    return !BoolExpr(new const PrimitiveBoolExprImpl( | 
| +        num, arg_type, ErrorCode::OP_HAS_ANY_BITS, mask)); | 
| +  } else { | 
| +    CHECK(false) << "Unimplemented ArgEq case"; | 
| +    return BoolExpr(); | 
| +  } | 
| +} | 
| + | 
| +}  // namespace internal | 
| + | 
| +ResultExpr Allow() { | 
| +  return ResultExpr(new const AllowResultExprImpl()); | 
| +} | 
| + | 
| +ResultExpr Error(int err) { | 
| +  return ResultExpr(new const ErrorResultExprImpl(err)); | 
| +} | 
| + | 
| +ResultExpr Trap(TrapFnc trap_func, void* aux) { | 
| +  return ResultExpr(new const TrapResultExprImpl(trap_func, aux)); | 
| +} | 
| + | 
| +BoolExpr operator!(BoolExpr cond) { | 
| +  return BoolExpr(new const NegateBoolExprImpl(cond)); | 
| +} | 
| + | 
| +BoolExpr operator&&(BoolExpr lhs, BoolExpr rhs) { | 
| +  return BoolExpr(new const AndBoolExprImpl(lhs, rhs)); | 
| +} | 
| + | 
| +BoolExpr operator||(BoolExpr lhs, BoolExpr rhs) { | 
| +  return BoolExpr(new const OrBoolExprImpl(lhs, rhs)); | 
| +} | 
| + | 
| +Elser If(BoolExpr cond, ResultExpr then_result) { | 
| +  return Elser(Cons<Elser::Clause>::List()).ElseIf(cond, then_result); | 
| +} | 
| + | 
| +Elser::Elser(Cons<Clause>::List clause_list) : clause_list_(clause_list) { | 
| +} | 
| + | 
| +Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) { | 
| +} | 
| + | 
| +Elser::~Elser() { | 
| +} | 
| + | 
| +Elser Elser::ElseIf(BoolExpr cond, ResultExpr then_result) const { | 
| +  return Elser( | 
| +      Cons<Clause>::Make(std::make_pair(cond, then_result), clause_list_)); | 
| +} | 
| + | 
| +ResultExpr Elser::Else(ResultExpr else_result) const { | 
| +  // We finally have the default result expression for this | 
| +  // if/then/else sequence.  Also, we've already accumulated all | 
| +  // if/then pairs into a list of reverse order (i.e., lower priority | 
| +  // conditions are listed before higher priority ones).  E.g., an | 
| +  // expression like | 
| +  // | 
| +  //    If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4) | 
| +  // | 
| +  // will have built up a list like | 
| +  // | 
| +  //    [(b3, e3), (b2, e2), (b1, e1)]. | 
| +  // | 
| +  // Now that we have e4, we can walk the list and create a ResultExpr | 
| +  // tree like: | 
| +  // | 
| +  //    expr = e4 | 
| +  //    expr = (b3 ? e3 : expr) = (b3 ? e3 : e4) | 
| +  //    expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4)) | 
| +  //    expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4))) | 
| +  // | 
| +  // and end up with an appropriately chained tree. | 
| + | 
| +  ResultExpr expr = else_result; | 
| +  for (Cons<Clause>::List it = clause_list_; it; it = it->tail()) { | 
| +    Clause clause = it->head(); | 
| +    expr = ResultExpr( | 
| +        new const IfThenResultExprImpl(clause.first, clause.second, expr)); | 
| +  } | 
| +  return expr; | 
| +} | 
| + | 
| +ResultExpr SandboxBPFDSLPolicy::InvalidSyscall() const { | 
| +  return Error(ENOSYS); | 
| +} | 
| + | 
| +ErrorCode SandboxBPFDSLPolicy::EvaluateSyscall(SandboxBPF* sb, | 
| +                                               int sysno) const { | 
| +  return EvaluateSyscall(sysno)->Compile(sb); | 
| +} | 
| + | 
| +ErrorCode SandboxBPFDSLPolicy::InvalidSyscall(SandboxBPF* sb) const { | 
| +  return InvalidSyscall()->Compile(sb); | 
| +} | 
| + | 
| +ResultExpr SandboxBPFDSLPolicy::Trap(::sandbox::Trap::TrapFnc trap_func, | 
| +                                     void* aux) { | 
| +  return bpf_dsl::Trap(trap_func, aux); | 
| +} | 
| + | 
| +}  // namespace bpf_dsl | 
| +}  // namespace sandbox | 
|  |