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