| 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..ffabeac6da5464ce27b8fe2cf117296e7ed73b11
|
| --- /dev/null
|
| +++ b/sandbox/linux/bpf_dsl/bpf_dsl.cc
|
| @@ -0,0 +1,388 @@
|
| +// 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 <limits>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
|
| +#include "sandbox/linux/bpf_dsl/policy_compiler.h"
|
| +#include "sandbox/linux/seccomp-bpf/errorcode.h"
|
| +
|
| +namespace sandbox {
|
| +namespace bpf_dsl {
|
| +namespace {
|
| +
|
| +class AllowResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + AllowResultExprImpl() {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + }
|
| +
|
| + private:
|
| + virtual ~AllowResultExprImpl() {}
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AllowResultExprImpl);
|
| +};
|
| +
|
| +class ErrorResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + explicit ErrorResultExprImpl(int err) : err_(err) {
|
| + CHECK(err_ >= ErrorCode::ERR_MIN_ERRNO && err_ <= ErrorCode::ERR_MAX_ERRNO);
|
| + }
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return pc->Error(err_);
|
| + }
|
| +
|
| + private:
|
| + virtual ~ErrorResultExprImpl() {}
|
| +
|
| + int err_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ErrorResultExprImpl);
|
| +};
|
| +
|
| +class KillResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + explicit KillResultExprImpl(const char* msg) : msg_(msg) { DCHECK(msg_); }
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return pc->Kill(msg_);
|
| + }
|
| +
|
| + private:
|
| + virtual ~KillResultExprImpl() {}
|
| +
|
| + const char* msg_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(KillResultExprImpl);
|
| +};
|
| +
|
| +class TraceResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + TraceResultExprImpl(uint16_t aux) : aux_(aux) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return ErrorCode(ErrorCode::ERR_TRACE + aux_);
|
| + }
|
| +
|
| + private:
|
| + virtual ~TraceResultExprImpl() {}
|
| +
|
| + uint16_t aux_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TraceResultExprImpl);
|
| +};
|
| +
|
| +class TrapResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg)
|
| + : func_(func), arg_(arg) {
|
| + DCHECK(func_);
|
| + }
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return pc->Trap(func_, arg_);
|
| + }
|
| +
|
| + private:
|
| + virtual ~TrapResultExprImpl() {}
|
| +
|
| + TrapRegistry::TrapFnc func_;
|
| + const void* arg_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl);
|
| +};
|
| +
|
| +class UnsafeTrapResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + UnsafeTrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg)
|
| + : func_(func), arg_(arg) {
|
| + DCHECK(func_);
|
| + }
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return pc->UnsafeTrap(func_, arg_);
|
| + }
|
| +
|
| + virtual bool HasUnsafeTraps() const override { return true; }
|
| +
|
| + private:
|
| + virtual ~UnsafeTrapResultExprImpl() {}
|
| +
|
| + TrapRegistry::TrapFnc func_;
|
| + const void* arg_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UnsafeTrapResultExprImpl);
|
| +};
|
| +
|
| +class IfThenResultExprImpl : public internal::ResultExprImpl {
|
| + public:
|
| + IfThenResultExprImpl(const BoolExpr& cond,
|
| + const ResultExpr& then_result,
|
| + const ResultExpr& else_result)
|
| + : cond_(cond), then_result_(then_result), else_result_(else_result) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc) const override {
|
| + return cond_->Compile(
|
| + pc, then_result_->Compile(pc), else_result_->Compile(pc));
|
| + }
|
| +
|
| + virtual bool HasUnsafeTraps() const override {
|
| + return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
|
| + }
|
| +
|
| + private:
|
| + virtual ~IfThenResultExprImpl() {}
|
| +
|
| + BoolExpr cond_;
|
| + ResultExpr then_result_;
|
| + ResultExpr else_result_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl);
|
| +};
|
| +
|
| +class ConstBoolExprImpl : public internal::BoolExprImpl {
|
| + public:
|
| + ConstBoolExprImpl(bool value) : value_(value) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc,
|
| + ErrorCode true_ec,
|
| + ErrorCode false_ec) const override {
|
| + return value_ ? true_ec : false_ec;
|
| + }
|
| +
|
| + private:
|
| + virtual ~ConstBoolExprImpl() {}
|
| +
|
| + bool value_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
|
| +};
|
| +
|
| +class PrimitiveBoolExprImpl : public internal::BoolExprImpl {
|
| + public:
|
| + PrimitiveBoolExprImpl(int argno,
|
| + ErrorCode::ArgType is_32bit,
|
| + uint64_t mask,
|
| + uint64_t value)
|
| + : argno_(argno), is_32bit_(is_32bit), mask_(mask), value_(value) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc,
|
| + ErrorCode true_ec,
|
| + ErrorCode false_ec) const override {
|
| + return pc->CondMaskedEqual(
|
| + argno_, is_32bit_, mask_, value_, true_ec, false_ec);
|
| + }
|
| +
|
| + private:
|
| + virtual ~PrimitiveBoolExprImpl() {}
|
| +
|
| + int argno_;
|
| + ErrorCode::ArgType is_32bit_;
|
| + uint64_t mask_;
|
| + uint64_t value_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PrimitiveBoolExprImpl);
|
| +};
|
| +
|
| +class NegateBoolExprImpl : public internal::BoolExprImpl {
|
| + public:
|
| + explicit NegateBoolExprImpl(const BoolExpr& cond) : cond_(cond) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc,
|
| + ErrorCode true_ec,
|
| + ErrorCode false_ec) const override {
|
| + return cond_->Compile(pc, false_ec, true_ec);
|
| + }
|
| +
|
| + private:
|
| + virtual ~NegateBoolExprImpl() {}
|
| +
|
| + BoolExpr cond_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
|
| +};
|
| +
|
| +class AndBoolExprImpl : public internal::BoolExprImpl {
|
| + public:
|
| + AndBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs)
|
| + : lhs_(lhs), rhs_(rhs) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc,
|
| + ErrorCode true_ec,
|
| + ErrorCode false_ec) const override {
|
| + return lhs_->Compile(pc, rhs_->Compile(pc, true_ec, false_ec), false_ec);
|
| + }
|
| +
|
| + private:
|
| + virtual ~AndBoolExprImpl() {}
|
| +
|
| + BoolExpr lhs_;
|
| + BoolExpr rhs_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl);
|
| +};
|
| +
|
| +class OrBoolExprImpl : public internal::BoolExprImpl {
|
| + public:
|
| + OrBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs)
|
| + : lhs_(lhs), rhs_(rhs) {}
|
| +
|
| + virtual ErrorCode Compile(PolicyCompiler* pc,
|
| + ErrorCode true_ec,
|
| + ErrorCode false_ec) const override {
|
| + return lhs_->Compile(pc, true_ec, rhs_->Compile(pc, true_ec, false_ec));
|
| + }
|
| +
|
| + private:
|
| + virtual ~OrBoolExprImpl() {}
|
| +
|
| + BoolExpr lhs_;
|
| + BoolExpr rhs_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +namespace internal {
|
| +
|
| +bool ResultExprImpl::HasUnsafeTraps() const {
|
| + return false;
|
| +}
|
| +
|
| +uint64_t DefaultMask(size_t size) {
|
| + switch (size) {
|
| + case 4:
|
| + return std::numeric_limits<uint32_t>::max();
|
| + case 8:
|
| + return std::numeric_limits<uint64_t>::max();
|
| + default:
|
| + CHECK(false) << "Unimplemented DefaultMask case";
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) {
|
| + CHECK(size == 4 || size == 8);
|
| +
|
| + // TODO(mdempsky): Should we just always use TP_64BIT?
|
| + const ErrorCode::ArgType arg_type =
|
| + (size == 4) ? ErrorCode::TP_32BIT : ErrorCode::TP_64BIT;
|
| +
|
| + return BoolExpr(new const PrimitiveBoolExprImpl(num, arg_type, mask, val));
|
| +}
|
| +
|
| +} // namespace internal
|
| +
|
| +ResultExpr Allow() {
|
| + return ResultExpr(new const AllowResultExprImpl());
|
| +}
|
| +
|
| +ResultExpr Error(int err) {
|
| + return ResultExpr(new const ErrorResultExprImpl(err));
|
| +}
|
| +
|
| +ResultExpr Kill(const char* msg) {
|
| + return ResultExpr(new const KillResultExprImpl(msg));
|
| +}
|
| +
|
| +ResultExpr Trace(uint16_t aux) {
|
| + return ResultExpr(new const TraceResultExprImpl(aux));
|
| +}
|
| +
|
| +ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
|
| + return ResultExpr(new const TrapResultExprImpl(trap_func, aux));
|
| +}
|
| +
|
| +ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
|
| + return ResultExpr(new const UnsafeTrapResultExprImpl(trap_func, aux));
|
| +}
|
| +
|
| +BoolExpr BoolConst(bool value) {
|
| + return BoolExpr(new const ConstBoolExprImpl(value));
|
| +}
|
| +
|
| +BoolExpr operator!(const BoolExpr& cond) {
|
| + return BoolExpr(new const NegateBoolExprImpl(cond));
|
| +}
|
| +
|
| +BoolExpr operator&&(const BoolExpr& lhs, const BoolExpr& rhs) {
|
| + return BoolExpr(new const AndBoolExprImpl(lhs, rhs));
|
| +}
|
| +
|
| +BoolExpr operator||(const BoolExpr& lhs, const BoolExpr& rhs) {
|
| + return BoolExpr(new const OrBoolExprImpl(lhs, rhs));
|
| +}
|
| +
|
| +Elser If(const BoolExpr& cond, const ResultExpr& then_result) {
|
| + return Elser(nullptr).ElseIf(cond, then_result);
|
| +}
|
| +
|
| +Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
|
| +}
|
| +
|
| +Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
|
| +}
|
| +
|
| +Elser::~Elser() {
|
| +}
|
| +
|
| +Elser Elser::ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const {
|
| + return Elser(Cons(std::make_pair(cond, then_result), clause_list_));
|
| +}
|
| +
|
| +ResultExpr Elser::Else(const 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 (const Clause& clause : clause_list_) {
|
| + expr = ResultExpr(
|
| + new const IfThenResultExprImpl(clause.first, clause.second, expr));
|
| + }
|
| + return expr;
|
| +}
|
| +
|
| +ResultExpr SandboxBPFDSLPolicy::InvalidSyscall() const {
|
| + return Error(ENOSYS);
|
| +}
|
| +
|
| +ResultExpr SandboxBPFDSLPolicy::Trap(TrapRegistry::TrapFnc trap_func,
|
| + const void* aux) {
|
| + return bpf_dsl::Trap(trap_func, aux);
|
| +}
|
| +
|
| +} // namespace bpf_dsl
|
| +} // namespace sandbox
|
| +
|
| +template class scoped_refptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
|
| +template class scoped_refptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
|
|
|