summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc')
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc343
1 files changed, 343 insertions, 0 deletions
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
new file mode 100644
index 0000000000..fed6368db6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
@@ -0,0 +1,343 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/errorcode.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+class ReturnResultExprImpl : public internal::ResultExprImpl {
+ public:
+ explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {}
+ ~ReturnResultExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc) const override {
+ return pc->Return(ret_);
+ }
+
+ bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); }
+
+ bool IsDeny() const override {
+ return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL);
+ }
+
+ private:
+ bool IsAction(uint32_t action) const {
+ return (ret_ & SECCOMP_RET_ACTION) == action;
+ }
+
+ uint32_t ret_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReturnResultExprImpl);
+};
+
+class TrapResultExprImpl : public internal::ResultExprImpl {
+ public:
+ TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe)
+ : func_(func), arg_(arg), safe_(safe) {
+ DCHECK(func_);
+ }
+ ~TrapResultExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc) const override {
+ return pc->Trap(func_, arg_, safe_);
+ }
+
+ bool HasUnsafeTraps() const override { return safe_ == false; }
+
+ bool IsDeny() const override { return true; }
+
+ private:
+ TrapRegistry::TrapFnc func_;
+ const void* arg_;
+ bool safe_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl);
+};
+
+class IfThenResultExprImpl : public internal::ResultExprImpl {
+ public:
+ IfThenResultExprImpl(BoolExpr cond,
+ ResultExpr then_result,
+ ResultExpr else_result)
+ : cond_(std::move(cond)),
+ then_result_(std::move(then_result)),
+ else_result_(std::move(else_result)) {}
+ ~IfThenResultExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc) const override {
+ // We compile the "then" and "else" expressions in separate statements so
+ // they have a defined sequencing. See https://crbug.com/529480.
+ CodeGen::Node then_node = then_result_->Compile(pc);
+ CodeGen::Node else_node = else_result_->Compile(pc);
+ return cond_->Compile(pc, then_node, else_node);
+ }
+
+ bool HasUnsafeTraps() const override {
+ return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
+ }
+
+ private:
+ BoolExpr cond_;
+ ResultExpr then_result_;
+ ResultExpr else_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl);
+};
+
+class ConstBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ ConstBoolExprImpl(bool value) : value_(value) {}
+ ~ConstBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return value_ ? then_node : else_node;
+ }
+
+ private:
+ bool value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
+};
+
+class MaskedEqualBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ MaskedEqualBoolExprImpl(int argno,
+ size_t width,
+ uint64_t mask,
+ uint64_t value)
+ : argno_(argno), width_(width), mask_(mask), value_(value) {}
+ ~MaskedEqualBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return pc->MaskedEqual(argno_, width_, mask_, value_, then_node, else_node);
+ }
+
+ private:
+ int argno_;
+ size_t width_;
+ uint64_t mask_;
+ uint64_t value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl);
+};
+
+class NegateBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ explicit NegateBoolExprImpl(BoolExpr cond) : cond_(std::move(cond)) {}
+ ~NegateBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return cond_->Compile(pc, else_node, then_node);
+ }
+
+ private:
+ BoolExpr cond_;
+
+ DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
+};
+
+class AndBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
+ : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+ ~AndBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return lhs_->Compile(pc, rhs_->Compile(pc, then_node, else_node),
+ else_node);
+ }
+
+ private:
+ BoolExpr lhs_;
+ BoolExpr rhs_;
+
+ DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl);
+};
+
+class OrBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
+ : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+ ~OrBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return lhs_->Compile(pc, then_node,
+ rhs_->Compile(pc, then_node, else_node));
+ }
+
+ private:
+ BoolExpr lhs_;
+ BoolExpr rhs_;
+
+ DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl);
+};
+
+} // namespace
+
+namespace internal {
+
+bool ResultExprImpl::HasUnsafeTraps() const {
+ return false;
+}
+
+bool ResultExprImpl::IsAllow() const {
+ return false;
+}
+
+bool ResultExprImpl::IsDeny() 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) {
+ // If this is changed, update Arg<T>::EqualTo's static_cast rules
+ // accordingly.
+ CHECK(size == 4 || size == 8);
+
+ return std::make_shared<MaskedEqualBoolExprImpl>(num, size, mask, val);
+}
+
+} // namespace internal
+
+ResultExpr Allow() {
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ALLOW);
+}
+
+ResultExpr Error(int err) {
+ CHECK(err >= ErrorCode::ERR_MIN_ERRNO && err <= ErrorCode::ERR_MAX_ERRNO);
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ERRNO + err);
+}
+
+ResultExpr Kill() {
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_KILL);
+}
+
+ResultExpr Trace(uint16_t aux) {
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_TRACE + aux);
+}
+
+ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+ return std::make_shared<TrapResultExprImpl>(trap_func, aux, true /* safe */);
+}
+
+ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+ return std::make_shared<TrapResultExprImpl>(trap_func, aux,
+ false /* unsafe */);
+}
+
+BoolExpr BoolConst(bool value) {
+ return std::make_shared<ConstBoolExprImpl>(value);
+}
+
+BoolExpr Not(BoolExpr cond) {
+ return std::make_shared<NegateBoolExprImpl>(std::move(cond));
+}
+
+BoolExpr AllOf() {
+ return BoolConst(true);
+}
+
+BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs) {
+ return std::make_shared<AndBoolExprImpl>(std::move(lhs), std::move(rhs));
+}
+
+BoolExpr AnyOf() {
+ return BoolConst(false);
+}
+
+BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs) {
+ return std::make_shared<OrBoolExprImpl>(std::move(lhs), std::move(rhs));
+}
+
+Elser If(BoolExpr cond, ResultExpr then_result) {
+ return Elser(nullptr).ElseIf(std::move(cond), std::move(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(BoolExpr cond, ResultExpr then_result) const {
+ return Elser(Cons(std::make_pair(std::move(cond), std::move(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 = std::move(else_result);
+ for (const Clause& clause : clause_list_) {
+ expr = std::make_shared<IfThenResultExprImpl>(clause.first, clause.second,
+ std::move(expr));
+ }
+ return expr;
+}
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+namespace std {
+template class shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+template class shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
+} // namespace std