summaryrefslogtreecommitdiff
path: root/sandbox/linux/bpf_dsl
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/linux/bpf_dsl')
-rw-r--r--sandbox/linux/bpf_dsl/DEPS3
-rw-r--r--sandbox/linux/bpf_dsl/bpf_dsl.cc343
-rw-r--r--sandbox/linux/bpf_dsl/bpf_dsl.h340
-rw-r--r--sandbox/linux/bpf_dsl/bpf_dsl_forward.h37
-rw-r--r--sandbox/linux/bpf_dsl/bpf_dsl_impl.h67
-rw-r--r--sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc478
-rw-r--r--sandbox/linux/bpf_dsl/codegen.cc147
-rw-r--r--sandbox/linux/bpf_dsl/codegen.h119
-rw-r--r--sandbox/linux/bpf_dsl/codegen_unittest.cc404
-rw-r--r--sandbox/linux/bpf_dsl/cons.h137
-rw-r--r--sandbox/linux/bpf_dsl/dump_bpf.cc159
-rw-r--r--sandbox/linux/bpf_dsl/dump_bpf.h24
-rw-r--r--sandbox/linux/bpf_dsl/errorcode.h37
-rw-r--r--sandbox/linux/bpf_dsl/linux_syscall_ranges.h57
-rw-r--r--sandbox/linux/bpf_dsl/policy.cc19
-rw-r--r--sandbox/linux/bpf_dsl/policy.h37
-rw-r--r--sandbox/linux/bpf_dsl/policy_compiler.cc466
-rw-r--r--sandbox/linux/bpf_dsl/policy_compiler.h153
-rw-r--r--sandbox/linux/bpf_dsl/seccomp_macros.h294
-rw-r--r--sandbox/linux/bpf_dsl/syscall_set.cc146
-rw-r--r--sandbox/linux/bpf_dsl/syscall_set.h103
-rw-r--r--sandbox/linux/bpf_dsl/syscall_set_unittest.cc126
-rw-r--r--sandbox/linux/bpf_dsl/trap_registry.h73
-rw-r--r--sandbox/linux/bpf_dsl/verifier.cc225
-rw-r--r--sandbox/linux/bpf_dsl/verifier.h45
25 files changed, 0 insertions, 4039 deletions
diff --git a/sandbox/linux/bpf_dsl/DEPS b/sandbox/linux/bpf_dsl/DEPS
deleted file mode 100644
index 70d9b18aa1..0000000000
--- a/sandbox/linux/bpf_dsl/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+sandbox/linux/system_headers",
-]
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.cc b/sandbox/linux/bpf_dsl/bpf_dsl.cc
deleted file mode 100644
index fed6368db6..0000000000
--- a/sandbox/linux/bpf_dsl/bpf_dsl.cc
+++ /dev/null
@@ -1,343 +0,0 @@
-// 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
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.h b/sandbox/linux/bpf_dsl/bpf_dsl.h
deleted file mode 100644
index 6f0dd4eb39..0000000000
--- a/sandbox/linux/bpf_dsl/bpf_dsl.h
+++ /dev/null
@@ -1,340 +0,0 @@
-// 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
-#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
-#include "sandbox/linux/bpf_dsl/cons.h"
-#include "sandbox/linux/bpf_dsl/trap_registry.h"
-#include "sandbox/sandbox_export.h"
-
-// 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/bpf_dsl/bpf_dsl.h"
-//
-// using namespace sandbox::bpf_dsl;
-//
-// class SillyPolicy : public Policy {
-// public:
-// SillyPolicy() {}
-// ~SillyPolicy() override {}
-// ResultExpr EvaluateSyscall(int sysno) const override {
-// if (sysno == __NR_fcntl) {
-// Arg<int> fd(0), cmd(1);
-// Arg<unsigned long> flags(2);
-// const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
-// return If(AllOf(fd == 0,
-// cmd == F_SETFL,
-// (flags & ~kGoodFlags) == 0),
-// Allow())
-// .ElseIf(AnyOf(cmd == F_DUPFD, cmd == F_DUPFD_CLOEXEC),
-// Error(EMFILE))
-// .Else(Trap(SetFlagHandler, NULL));
-// } else {
-// return Allow();
-// }
-// }
-//
-// private:
-// DISALLOW_COPY_AND_ASSIGN(SillyPolicy);
-// };
-//
-// More generally, the DSL currently supports the following grammar:
-//
-// result = Allow() | Error(errno) | Kill() | Trace(aux)
-// | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux)
-// | If(bool, result)[.ElseIf(bool, result)].Else(result)
-// | Switch(arg)[.Case(val, result)].Default(result)
-// bool = BoolConst(boolean) | Not(bool) | AllOf(bool...) | AnyOf(bool...)
-// | arg == val | arg != val
-// arg = Arg<T>(num) | arg & mask
-//
-// 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 bpf_dsl {
-
-template <typename T>
-class Caser;
-
-class Elser;
-
-// ResultExpr is an opaque reference to an immutable result expression tree.
-using ResultExpr = std::shared_ptr<const internal::ResultExprImpl>;
-
-// BoolExpr is an opaque reference to an immutable boolean expression tree.
-using BoolExpr = std::shared_ptr<const internal::BoolExprImpl>;
-
-// Allow specifies a result that the system call should be allowed to
-// execute normally.
-SANDBOX_EXPORT ResultExpr Allow();
-
-// 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);
-
-// Kill specifies a result to kill the process (task) immediately.
-SANDBOX_EXPORT ResultExpr Kill();
-
-// Trace specifies a result to notify a tracing process via the
-// PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call.
-// The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG.
-SANDBOX_EXPORT ResultExpr Trace(uint16_t aux);
-
-// Trap specifies a result that the system call should be handled by
-// trapping back into userspace and invoking |trap_func|, passing
-// |aux| as the second parameter.
-SANDBOX_EXPORT ResultExpr
- Trap(TrapRegistry::TrapFnc trap_func, const void* aux);
-
-// UnsafeTrap is like Trap, except the policy is marked as "unsafe"
-// and allowed to use SandboxSyscall to invoke any system call.
-//
-// NOTE: This feature, by definition, disables all security features of
-// the sandbox. It should never be used in production, but it can be
-// very useful to diagnose code that is incompatible with the sandbox.
-// If even a single system call returns "UnsafeTrap", the security of
-// entire sandbox should be considered compromised.
-SANDBOX_EXPORT ResultExpr
- UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux);
-
-// BoolConst converts a bool value into a BoolExpr.
-SANDBOX_EXPORT BoolExpr BoolConst(bool value);
-
-// Not returns a BoolExpr representing the logical negation of |cond|.
-SANDBOX_EXPORT BoolExpr Not(BoolExpr cond);
-
-// AllOf returns a BoolExpr representing the logical conjunction ("and")
-// of zero or more BoolExprs.
-SANDBOX_EXPORT BoolExpr AllOf();
-SANDBOX_EXPORT BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs);
-template <typename... Rest>
-SANDBOX_EXPORT BoolExpr AllOf(BoolExpr first, Rest&&... rest);
-
-// AnyOf returns a BoolExpr representing the logical disjunction ("or")
-// of zero or more BoolExprs.
-SANDBOX_EXPORT BoolExpr AnyOf();
-SANDBOX_EXPORT BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs);
-template <typename... Rest>
-SANDBOX_EXPORT BoolExpr AnyOf(BoolExpr first, Rest&&... rest);
-
-template <typename T>
-class SANDBOX_EXPORT Arg {
- public:
- // Initializes the Arg to represent the |num|th system call
- // argument (indexed from 0), which is of type |T|.
- explicit Arg(int num);
-
- 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|.
- friend Arg operator&(const Arg& lhs, uint64_t rhs) {
- return Arg(lhs.num_, lhs.mask_ & rhs);
- }
-
- // Returns a boolean expression comparing whether the system call argument
- // (after applying any bitmasks, if appropriate) equals |rhs|.
- friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); }
-
- // Returns a boolean expression comparing whether the system call argument
- // (after applying any bitmasks, if appropriate) does not equal |rhs|.
- friend BoolExpr operator!=(const Arg& lhs, T rhs) { return Not(lhs == rhs); }
-
- private:
- Arg(int num, uint64_t mask) : num_(num), mask_(mask) {}
-
- BoolExpr EqualTo(T val) const;
-
- int num_;
- uint64_t mask_;
-
- DISALLOW_ASSIGN(Arg);
-};
-
-// If begins a conditional result expression predicated on the
-// specified boolean expression.
-SANDBOX_EXPORT Elser If(BoolExpr cond, ResultExpr then_result);
-
-class SANDBOX_EXPORT Elser {
- public:
- Elser(const Elser& elser);
- ~Elser();
-
- // ElseIf extends the conditional result expression with another
- // "if then" clause, predicated on the specified boolean expression.
- Elser ElseIf(BoolExpr cond, ResultExpr then_result) const;
-
- // Else terminates a conditional result expression using |else_result| as
- // the default fallback result expression.
- ResultExpr Else(ResultExpr else_result) const;
-
- private:
- using Clause = std::pair<BoolExpr, ResultExpr>;
-
- explicit Elser(cons::List<Clause> clause_list);
-
- cons::List<Clause> clause_list_;
-
- friend Elser If(BoolExpr, ResultExpr);
- template <typename T>
- friend Caser<T> Switch(const Arg<T>&);
- DISALLOW_ASSIGN(Elser);
-};
-
-// Switch begins a switch expression dispatched according to the
-// specified argument value.
-template <typename T>
-SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg);
-
-template <typename T>
-class SANDBOX_EXPORT Caser {
- public:
- Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {}
- ~Caser() {}
-
- // Case adds a single-value "case" clause to the switch.
- Caser<T> Case(T value, ResultExpr result) const;
-
- // Cases adds a multiple-value "case" clause to the switch.
- // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way
- // of using this function.
- template <typename... Values>
- Caser<T> CasesImpl(ResultExpr result, const Values&... values) const;
-
- // Terminate the switch with a "default" clause.
- ResultExpr Default(ResultExpr result) const;
-
- private:
- Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {}
-
- Arg<T> arg_;
- Elser elser_;
-
- template <typename U>
- friend Caser<U> Switch(const Arg<U>&);
- DISALLOW_ASSIGN(Caser);
-};
-
-// Recommended usage is to put
-// #define CASES SANDBOX_BPF_DSL_CASES
-// near the top of the .cc file (e.g., nearby any "using" statements), then
-// use like:
-// Switch(arg).CASES((3, 5, 7), result)...;
-#define SANDBOX_BPF_DSL_CASES(values, result) \
- CasesImpl(result, SANDBOX_BPF_DSL_CASES_HELPER values)
-
-// Helper macro to strip parentheses.
-#define SANDBOX_BPF_DSL_CASES_HELPER(...) __VA_ARGS__
-
-// =====================================================================
-// Official API ends here.
-// =====================================================================
-
-namespace internal {
-
-// Make argument-dependent lookup work. This is necessary because although
-// BoolExpr is defined in bpf_dsl, since it's merely a typedef for
-// scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only
-// searches the "internal" nested namespace.
-using bpf_dsl::Not;
-using bpf_dsl::AllOf;
-using bpf_dsl::AnyOf;
-
-// 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);
-
-// Returns the default mask for a system call argument of the specified size.
-SANDBOX_EXPORT uint64_t DefaultMask(size_t size);
-
-} // namespace internal
-
-template <typename T>
-Arg<T>::Arg(int num)
- : num_(num), mask_(internal::DefaultMask(sizeof(T))) {
-}
-
-// 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.
-//
-// Additionally, we use this helper member function to avoid linker errors
-// caused by defining operator== out-of-line. For a more detailed explanation,
-// see http://www.parashift.com/c++-faq-lite/template-friends.html.
-template <typename T>
-BoolExpr Arg<T>::EqualTo(T val) const {
- if (sizeof(T) == 4) {
- // Prevent sign-extension of negative int32_t values.
- return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint32_t>(val));
- }
- return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
-}
-
-template <typename T>
-SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) {
- return Caser<T>(arg, Elser(nullptr));
-}
-
-template <typename T>
-Caser<T> Caser<T>::Case(T value, ResultExpr result) const {
- return SANDBOX_BPF_DSL_CASES((value), std::move(result));
-}
-
-template <typename T>
-template <typename... Values>
-Caser<T> Caser<T>::CasesImpl(ResultExpr result, const Values&... values) const {
- // Theoretically we could evaluate arg_ just once and emit a more efficient
- // dispatch table, but for now we simply translate into an equivalent
- // If/ElseIf/Else chain.
-
- return Caser<T>(arg_,
- elser_.ElseIf(AnyOf((arg_ == values)...), std::move(result)));
-}
-
-template <typename T>
-ResultExpr Caser<T>::Default(ResultExpr result) const {
- return elser_.Else(std::move(result));
-}
-
-template <typename... Rest>
-BoolExpr AllOf(BoolExpr first, Rest&&... rest) {
- return AllOf(std::move(first), AllOf(std::forward<Rest>(rest)...));
-}
-
-template <typename... Rest>
-BoolExpr AnyOf(BoolExpr first, Rest&&... rest) {
- return AnyOf(std::move(first), AnyOf(std::forward<Rest>(rest)...));
-}
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_forward.h b/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
deleted file mode 100644
index af1b48b407..0000000000
--- a/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
-#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
-
-#include <memory>
-
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-// The bpf_dsl_forward.h header provides forward declarations for the
-// types defined in bpf_dsl.h. It's intended for use in user headers
-// that need to reference bpf_dsl types, but don't require definitions.
-
-namespace internal {
-class ResultExprImpl;
-class BoolExprImpl;
-}
-
-using ResultExpr = std::shared_ptr<const internal::ResultExprImpl>;
-using BoolExpr = std::shared_ptr<const internal::BoolExprImpl>;
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-namespace std {
-extern template class SANDBOX_EXPORT
- shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
-extern template class SANDBOX_EXPORT
- shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
-} // namespace std
-
-#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
deleted file mode 100644
index f397321edd..0000000000
--- a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
-#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-class PolicyCompiler;
-
-namespace internal {
-
-// Internal interface implemented by BoolExpr implementations.
-class BoolExprImpl {
- public:
- // Compile uses |pc| to emit a CodeGen::Node that conditionally continues
- // to either |then_node| or |false_node|, depending on whether the represented
- // boolean expression is true or false.
- virtual CodeGen::Node Compile(PolicyCompiler* pc,
- CodeGen::Node then_node,
- CodeGen::Node else_node) const = 0;
-
- protected:
- BoolExprImpl() {}
- virtual ~BoolExprImpl() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BoolExprImpl);
-};
-
-// Internal interface implemented by ResultExpr implementations.
-class ResultExprImpl {
- public:
- // Compile uses |pc| to emit a CodeGen::Node that executes the
- // represented result expression.
- virtual CodeGen::Node Compile(PolicyCompiler* pc) const = 0;
-
- // HasUnsafeTraps returns whether the result expression is or recursively
- // contains an unsafe trap expression.
- virtual bool HasUnsafeTraps() const;
-
- // IsAllow returns whether the result expression is an "allow" result.
- virtual bool IsAllow() const;
-
- // IsAllow returns whether the result expression is a "deny" result.
- virtual bool IsDeny() const;
-
- protected:
- ResultExprImpl() {}
- virtual ~ResultExprImpl() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ResultExprImpl);
-};
-
-} // namespace internal
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
deleted file mode 100644
index 801deee3e7..0000000000
--- a/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
+++ /dev/null
@@ -1,478 +0,0 @@
-// 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 <fcntl.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/utsname.h>
-#include <unistd.h>
-
-#include <map>
-#include <utility>
-
-#include "base/files/scoped_file.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/linux/bpf_dsl/dump_bpf.h"
-#include "sandbox/linux/bpf_dsl/golden/golden_files.h"
-#include "sandbox/linux/bpf_dsl/policy.h"
-#include "sandbox/linux/bpf_dsl/policy_compiler.h"
-#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-#include "sandbox/linux/bpf_dsl/test_trap_registry.h"
-#include "sandbox/linux/bpf_dsl/verifier.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#define CASES SANDBOX_BPF_DSL_CASES
-
-namespace sandbox {
-namespace bpf_dsl {
-namespace {
-
-// Helper function to construct fake arch_seccomp_data objects.
-struct arch_seccomp_data FakeSyscall(int nr,
- uintptr_t p0 = 0,
- uintptr_t p1 = 0,
- uintptr_t p2 = 0,
- uintptr_t p3 = 0,
- uintptr_t p4 = 0,
- uintptr_t p5 = 0) {
- // Made up program counter for syscall address.
- const uint64_t kFakePC = 0x543210;
-
- struct arch_seccomp_data data = {
- nr,
- SECCOMP_ARCH,
- kFakePC,
- {
- p0, p1, p2, p3, p4, p5,
- },
- };
-
- return data;
-}
-
-class PolicyEmulator {
- public:
- PolicyEmulator(const golden::Golden& golden, const Policy& policy)
- : program_() {
- TestTrapRegistry traps;
- program_ = PolicyCompiler(&policy, &traps).Compile();
-
- // TODO(mdempsky): Generalize to more arches.
- const char* expected = nullptr;
-#if defined(ARCH_CPU_X86)
- expected = golden.i386_dump;
-#elif defined(ARCH_CPU_X86_64)
- expected = golden.x86_64_dump;
-#endif
-
- if (expected != nullptr) {
- const std::string actual = DumpBPF::StringPrintProgram(program_);
- EXPECT_EQ(expected, actual);
- } else {
- LOG(WARNING) << "Missing golden file data entry";
- }
- }
-
- ~PolicyEmulator() {}
-
- void ExpectAllow(const struct arch_seccomp_data& data) const {
- EXPECT_EQ(SECCOMP_RET_ALLOW, Emulate(data));
- }
-
- void ExpectErrno(uint16_t err, const struct arch_seccomp_data& data) const {
- EXPECT_EQ(SECCOMP_RET_ERRNO | err, Emulate(data));
- }
-
- void ExpectKill(const struct arch_seccomp_data& data) const {
- EXPECT_EQ(SECCOMP_RET_KILL, Emulate(data));
- }
-
- private:
- uint32_t Emulate(const struct arch_seccomp_data& data) const {
- const char* err = nullptr;
- uint32_t res = Verifier::EvaluateBPF(program_, data, &err);
- if (err) {
- ADD_FAILURE() << err;
- return 0;
- }
- return res;
- }
-
- CodeGen::Program program_;
-
- DISALLOW_COPY_AND_ASSIGN(PolicyEmulator);
-};
-
-class BasicPolicy : public Policy {
- public:
- BasicPolicy() {}
- ~BasicPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_getpgid) {
- const Arg<pid_t> pid(0);
- return If(pid == 0, Error(EPERM)).Else(Error(EINVAL));
- }
- if (sysno == __NR_setuid) {
- const Arg<uid_t> uid(0);
- return If(uid != 42, Kill()).Else(Allow());
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BasicPolicy);
-};
-
-TEST(BPFDSL, Basic) {
- PolicyEmulator emulator(golden::kBasicPolicy, BasicPolicy());
-
- emulator.ExpectErrno(EPERM, FakeSyscall(__NR_getpgid, 0));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_getpgid, 1));
-
- emulator.ExpectAllow(FakeSyscall(__NR_setuid, 42));
- emulator.ExpectKill(FakeSyscall(__NR_setuid, 43));
-}
-
-/* On IA-32, socketpair() is implemented via socketcall(). :-( */
-#if !defined(ARCH_CPU_X86)
-class BooleanLogicPolicy : public Policy {
- public:
- BooleanLogicPolicy() {}
- ~BooleanLogicPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_socketpair) {
- const Arg<int> domain(0), type(1), protocol(2);
- return If(AllOf(domain == AF_UNIX,
- AnyOf(type == SOCK_STREAM, type == SOCK_DGRAM),
- protocol == 0),
- Error(EPERM))
- .Else(Error(EINVAL));
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy);
-};
-
-TEST(BPFDSL, BooleanLogic) {
- PolicyEmulator emulator(golden::kBooleanLogicPolicy, BooleanLogicPolicy());
-
- const intptr_t kFakeSV = 0x12345;
-
- // Acceptable combinations that should return EPERM.
- emulator.ExpectErrno(
- EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_STREAM, 0, kFakeSV));
- emulator.ExpectErrno(
- EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_DGRAM, 0, kFakeSV));
-
- // Combinations that are invalid for only one reason; should return EINVAL.
- emulator.ExpectErrno(
- EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_STREAM, 0, kFakeSV));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX,
- SOCK_SEQPACKET, 0, kFakeSV));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX,
- SOCK_STREAM, IPPROTO_TCP, kFakeSV));
-
- // Completely unacceptable combination; should also return EINVAL.
- emulator.ExpectErrno(
- EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_SEQPACKET, IPPROTO_UDP,
- kFakeSV));
-}
-#endif // !ARCH_CPU_X86
-
-class MoreBooleanLogicPolicy : public Policy {
- public:
- MoreBooleanLogicPolicy() {}
- ~MoreBooleanLogicPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_setresuid) {
- const Arg<uid_t> ruid(0), euid(1), suid(2);
- return If(AnyOf(ruid == 0, euid == 0, suid == 0), Error(EPERM))
- .ElseIf(AllOf(ruid == 1, euid == 1, suid == 1), Error(EAGAIN))
- .Else(Error(EINVAL));
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MoreBooleanLogicPolicy);
-};
-
-TEST(BPFDSL, MoreBooleanLogic) {
- PolicyEmulator emulator(golden::kMoreBooleanLogicPolicy,
- MoreBooleanLogicPolicy());
-
- // Expect EPERM if any set to 0.
- emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 0, 5, 5));
- emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 0, 5));
- emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 5, 0));
-
- // Expect EAGAIN if all set to 1.
- emulator.ExpectErrno(EAGAIN, FakeSyscall(__NR_setresuid, 1, 1, 1));
-
- // Expect EINVAL for anything else.
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 5, 1, 1));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 5, 1));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 1, 5));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 3, 4, 5));
-}
-
-static const uintptr_t kDeadBeefAddr =
- static_cast<uintptr_t>(0xdeadbeefdeadbeefULL);
-
-class ArgSizePolicy : public Policy {
- public:
- ArgSizePolicy() {}
- ~ArgSizePolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_uname) {
- const Arg<uintptr_t> addr(0);
- return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow());
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy);
-};
-
-TEST(BPFDSL, ArgSizeTest) {
- PolicyEmulator emulator(golden::kArgSizePolicy, ArgSizePolicy());
-
- emulator.ExpectAllow(FakeSyscall(__NR_uname, 0));
- emulator.ExpectErrno(EPERM, FakeSyscall(__NR_uname, kDeadBeefAddr));
-}
-
-class NegativeConstantsPolicy : public Policy {
- public:
- NegativeConstantsPolicy() {}
- ~NegativeConstantsPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_fcntl) {
- const Arg<int> fd(0);
- return If(fd == -314, Error(EPERM)).Else(Allow());
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NegativeConstantsPolicy);
-};
-
-TEST(BPFDSL, NegativeConstantsTest) {
- PolicyEmulator emulator(golden::kNegativeConstantsPolicy,
- NegativeConstantsPolicy());
-
- emulator.ExpectAllow(FakeSyscall(__NR_fcntl, -5, F_DUPFD));
- emulator.ExpectAllow(FakeSyscall(__NR_fcntl, 20, F_DUPFD));
- emulator.ExpectErrno(EPERM, FakeSyscall(__NR_fcntl, -314, F_DUPFD));
-}
-
-#if 0
-// TODO(mdempsky): This is really an integration test.
-
-class TrappingPolicy : public Policy {
- public:
- TrappingPolicy() {}
- ~TrappingPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_uname) {
- return Trap(UnameTrap, &count_);
- }
- return Allow();
- }
-
- private:
- static intptr_t count_;
-
- static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) {
- BPF_ASSERT_EQ(&count_, aux);
- return ++count_;
- }
-
- DISALLOW_COPY_AND_ASSIGN(TrappingPolicy);
-};
-
-intptr_t TrappingPolicy::count_;
-
-BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) {
- ASSERT_SYSCALL_RESULT(1, uname, NULL);
- ASSERT_SYSCALL_RESULT(2, uname, NULL);
- ASSERT_SYSCALL_RESULT(3, uname, NULL);
-}
-#endif
-
-class MaskingPolicy : public Policy {
- public:
- MaskingPolicy() {}
- ~MaskingPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_setuid) {
- const Arg<uid_t> uid(0);
- return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES));
- }
- if (sysno == __NR_setgid) {
- const Arg<gid_t> gid(0);
- return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES));
- }
- if (sysno == __NR_setpgid) {
- const Arg<pid_t> pid(0);
- return If((pid & 0xa5) == 0xa0, Error(EINVAL)).Else(Error(EACCES));
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MaskingPolicy);
-};
-
-TEST(BPFDSL, MaskTest) {
- PolicyEmulator emulator(golden::kMaskingPolicy, MaskingPolicy());
-
- for (uid_t uid = 0; uid < 0x100; ++uid) {
- const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES;
- emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setuid, uid));
- }
-
- for (gid_t gid = 0; gid < 0x100; ++gid) {
- const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES;
- emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setgid, gid));
- }
-
- for (pid_t pid = 0; pid < 0x100; ++pid) {
- const int expect_errno = (pid & 0xa5) == 0xa0 ? EINVAL : EACCES;
- emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setpgid, pid, 0));
- }
-}
-
-class ElseIfPolicy : public Policy {
- public:
- ElseIfPolicy() {}
- ~ElseIfPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_setuid) {
- const Arg<uid_t> uid(0);
- return If((uid & 0xfff) == 0, Error(0))
- .ElseIf((uid & 0xff0) == 0, Error(EINVAL))
- .ElseIf((uid & 0xf00) == 0, Error(EEXIST))
- .Else(Error(EACCES));
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy);
-};
-
-TEST(BPFDSL, ElseIfTest) {
- PolicyEmulator emulator(golden::kElseIfPolicy, ElseIfPolicy());
-
- emulator.ExpectErrno(0, FakeSyscall(__NR_setuid, 0));
-
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0001));
- emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0002));
-
- emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0011));
- emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0022));
-
- emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0111));
- emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0222));
-}
-
-class SwitchPolicy : public Policy {
- public:
- SwitchPolicy() {}
- ~SwitchPolicy() override {}
- ResultExpr EvaluateSyscall(int sysno) const override {
- if (sysno == __NR_fcntl) {
- const Arg<int> cmd(1);
- const Arg<unsigned long> long_arg(2);
- return Switch(cmd)
- .CASES((F_GETFL, F_GETFD), Error(ENOENT))
- .Case(F_SETFD, If(long_arg == O_CLOEXEC, Allow()).Else(Error(EINVAL)))
- .Case(F_SETFL, Error(EPERM))
- .Default(Error(EACCES));
- }
- return Allow();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SwitchPolicy);
-};
-
-TEST(BPFDSL, SwitchTest) {
- PolicyEmulator emulator(golden::kSwitchPolicy, SwitchPolicy());
-
- const int kFakeSockFD = 42;
-
- emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFD));
- emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFL));
-
- emulator.ExpectAllow(
- FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, O_CLOEXEC));
- emulator.ExpectErrno(EINVAL,
- FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, 0));
-
- emulator.ExpectErrno(EPERM,
- FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFL, O_RDONLY));
-
- emulator.ExpectErrno(EACCES,
- FakeSyscall(__NR_fcntl, kFakeSockFD, F_DUPFD, 0));
-}
-
-static intptr_t DummyTrap(const struct arch_seccomp_data& data, void* aux) {
- return 0;
-}
-
-TEST(BPFDSL, IsAllowDeny) {
- ResultExpr allow = Allow();
- EXPECT_TRUE(allow->IsAllow());
- EXPECT_FALSE(allow->IsDeny());
-
- ResultExpr error = Error(ENOENT);
- EXPECT_FALSE(error->IsAllow());
- EXPECT_TRUE(error->IsDeny());
-
- ResultExpr trace = Trace(42);
- EXPECT_FALSE(trace->IsAllow());
- EXPECT_FALSE(trace->IsDeny());
-
- ResultExpr trap = Trap(DummyTrap, nullptr);
- EXPECT_FALSE(trap->IsAllow());
- EXPECT_TRUE(trap->IsDeny());
-
- const Arg<int> arg(0);
- ResultExpr maybe = If(arg == 0, Allow()).Else(Error(EPERM));
- EXPECT_FALSE(maybe->IsAllow());
- EXPECT_FALSE(maybe->IsDeny());
-}
-
-TEST(BPFDSL, HasUnsafeTraps) {
- ResultExpr allow = Allow();
- EXPECT_FALSE(allow->HasUnsafeTraps());
-
- ResultExpr safe = Trap(DummyTrap, nullptr);
- EXPECT_FALSE(safe->HasUnsafeTraps());
-
- ResultExpr unsafe = UnsafeTrap(DummyTrap, nullptr);
- EXPECT_TRUE(unsafe->HasUnsafeTraps());
-
- const Arg<int> arg(0);
- ResultExpr maybe = If(arg == 0, allow).Else(unsafe);
- EXPECT_TRUE(maybe->HasUnsafeTraps());
-}
-
-} // namespace
-} // namespace bpf_dsl
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/codegen.cc b/sandbox/linux/bpf_dsl/codegen.cc
deleted file mode 100644
index d88bd531a2..0000000000
--- a/sandbox/linux/bpf_dsl/codegen.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2012 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/codegen.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-#include <utility>
-
-#include "base/logging.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-
-// This CodeGen implementation strives for simplicity while still
-// generating acceptable BPF programs under typical usage patterns
-// (e.g., by PolicyCompiler).
-//
-// The key to its simplicity is that BPF programs only support forward
-// jumps/branches, which allows constraining the DAG construction API
-// to make instruction nodes immutable. Immutable nodes admits a
-// simple greedy approach of emitting new instructions as needed and
-// then reusing existing ones that have already been emitted. This
-// cleanly avoids any need to compute basic blocks or apply
-// topological sorting because the API effectively sorts instructions
-// for us (e.g., before MakeInstruction() can be called to emit a
-// branch instruction, it must have already been called for each
-// branch path).
-//
-// This greedy algorithm is not without (theoretical) weakness though:
-//
-// 1. In the general case, we don't eliminate dead code. If needed,
-// we could trace back through the program in Compile() and elide
-// any unneeded instructions, but in practice we only emit live
-// instructions anyway.
-//
-// 2. By not dividing instructions into basic blocks and sorting, we
-// lose an opportunity to move non-branch/non-return instructions
-// adjacent to their successor instructions, which means we might
-// need to emit additional jumps. But in practice, they'll
-// already be nearby as long as callers don't go out of their way
-// to interleave MakeInstruction() calls for unrelated code
-// sequences.
-
-namespace sandbox {
-
-// kBranchRange is the maximum value that can be stored in
-// sock_filter's 8-bit jt and jf fields.
-const size_t kBranchRange = std::numeric_limits<uint8_t>::max();
-
-const CodeGen::Node CodeGen::kNullNode;
-
-CodeGen::CodeGen() : program_(), equivalent_(), memos_() {
-}
-
-CodeGen::~CodeGen() {
-}
-
-CodeGen::Program CodeGen::Compile(CodeGen::Node head) {
- return Program(program_.rbegin() + Offset(head), program_.rend());
-}
-
-CodeGen::Node CodeGen::MakeInstruction(uint16_t code,
- uint32_t k,
- Node jt,
- Node jf) {
- // To avoid generating redundant code sequences, we memoize the
- // results from AppendInstruction().
- auto res = memos_.insert(std::make_pair(MemoKey(code, k, jt, jf), kNullNode));
- CodeGen::Node* node = &res.first->second;
- if (res.second) { // Newly inserted memo entry.
- *node = AppendInstruction(code, k, jt, jf);
- }
- return *node;
-}
-
-CodeGen::Node CodeGen::AppendInstruction(uint16_t code,
- uint32_t k,
- Node jt,
- Node jf) {
- if (BPF_CLASS(code) == BPF_JMP) {
- CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed";
-
- // Optimally adding jumps is rather tricky, so we use a quick
- // approximation: by artificially reducing |jt|'s range, |jt| will
- // stay within its true range even if we add a jump for |jf|.
- jt = WithinRange(jt, kBranchRange - 1);
- jf = WithinRange(jf, kBranchRange);
- return Append(code, k, Offset(jt), Offset(jf));
- }
-
- CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf";
- if (BPF_CLASS(code) == BPF_RET) {
- CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt";
- } else {
- // For non-branch/non-return instructions, execution always
- // proceeds to the next instruction; so we need to arrange for
- // that to be |jt|.
- jt = WithinRange(jt, 0);
- CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction";
- }
- return Append(code, k, 0, 0);
-}
-
-CodeGen::Node CodeGen::WithinRange(Node target, size_t range) {
- // Just use |target| if it's already within range.
- if (Offset(target) <= range) {
- return target;
- }
-
- // Alternatively, look for an equivalent instruction within range.
- if (Offset(equivalent_.at(target)) <= range) {
- return equivalent_.at(target);
- }
-
- // Otherwise, fall back to emitting a jump instruction.
- Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0);
- equivalent_.at(target) = jump;
- return jump;
-}
-
-CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) {
- if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) {
- CHECK_LE(jt, kBranchRange);
- CHECK_LE(jf, kBranchRange);
- } else {
- CHECK_EQ(0U, jt);
- CHECK_EQ(0U, jf);
- }
-
- CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS));
- CHECK_EQ(program_.size(), equivalent_.size());
-
- Node res = program_.size();
- program_.push_back(sock_filter{
- code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k});
- equivalent_.push_back(res);
- return res;
-}
-
-size_t CodeGen::Offset(Node target) const {
- CHECK_LT(target, program_.size()) << "Bogus offset target node";
- return (program_.size() - 1) - target;
-}
-
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/codegen.h b/sandbox/linux/bpf_dsl/codegen.h
deleted file mode 100644
index 3fc3f35a0d..0000000000
--- a/sandbox/linux/bpf_dsl/codegen.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
-#define SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <tuple>
-#include <vector>
-
-#include "base/macros.h"
-#include "sandbox/sandbox_export.h"
-
-struct sock_filter;
-
-namespace sandbox {
-
-// The code generator implements a basic assembler that can convert a
-// graph of BPF instructions into a well-formed array of BPF
-// instructions. Most notably, it ensures that jumps are always
-// forward and don't exceed the limit of 255 instructions imposed by
-// the instruction set.
-//
-// Callers would typically create a new CodeGen object and then use it
-// to build a DAG of instruction nodes. They'll eventually call
-// Compile() to convert this DAG to a Program.
-//
-// CodeGen gen;
-// CodeGen::Node allow, branch, dag;
-//
-// allow =
-// gen.MakeInstruction(BPF_RET+BPF_K,
-// ErrorCode(ErrorCode::ERR_ALLOWED).err()));
-// branch =
-// gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid,
-// Trap(GetPidHandler, NULL), allow);
-// dag =
-// gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
-// offsetof(struct arch_seccomp_data, nr), branch);
-//
-// // Simplified code follows; in practice, it is important to avoid calling
-// // any C++ destructors after starting the sandbox.
-// CodeGen::Program program = gen.Compile(dag);
-// const struct sock_fprog prog = {
-// static_cast<unsigned short>(program.size()), &program[0] };
-// prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
-//
-class SANDBOX_EXPORT CodeGen {
- public:
- // A vector of BPF instructions that need to be installed as a filter
- // program in the kernel.
- typedef std::vector<struct sock_filter> Program;
-
- // Node represents a node within the instruction DAG being compiled.
- using Node = Program::size_type;
-
- // kNullNode represents the "null" node; i.e., the reserved node
- // value guaranteed to not equal any actual nodes.
- static const Node kNullNode = -1;
-
- CodeGen();
- ~CodeGen();
-
- // MakeInstruction creates a node representing the specified
- // instruction, or returns and existing equivalent node if one
- // exists. For details on the possible parameters refer to
- // https://www.kernel.org/doc/Documentation/networking/filter.txt.
- // TODO(mdempsky): Reconsider using default arguments here.
- Node MakeInstruction(uint16_t code,
- uint32_t k,
- Node jt = kNullNode,
- Node jf = kNullNode);
-
- // Compile linearizes the instruction DAG rooted at |head| into a
- // program that can be executed by a BPF virtual machine.
- Program Compile(Node head);
-
- private:
- using MemoKey = std::tuple<uint16_t, uint32_t, Node, Node>;
-
- // AppendInstruction adds a new instruction, ensuring that |jt| and
- // |jf| are within range as necessary for |code|.
- Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf);
-
- // WithinRange returns a node equivalent to |next| that is at most
- // |range| instructions away from the (logical) beginning of the
- // program.
- Node WithinRange(Node next, size_t range);
-
- // Append appends a new instruction to the physical end (i.e.,
- // logical beginning) of |program_|.
- Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf);
-
- // Offset returns how many instructions exist in |program_| after |target|.
- size_t Offset(Node target) const;
-
- // NOTE: program_ is the compiled program in *reverse*, so that
- // indices remain stable as we add instructions.
- Program program_;
-
- // equivalent_ stores the most recent semantically-equivalent node for each
- // instruction in program_. A node is defined as semantically-equivalent to N
- // if it has the same instruction code and constant as N and its successor
- // nodes (if any) are semantically-equivalent to N's successor nodes, or
- // if it's an unconditional jump to a node semantically-equivalent to N.
- std::vector<Node> equivalent_;
-
- std::map<MemoKey, Node> memos_;
-
- DISALLOW_COPY_AND_ASSIGN(CodeGen);
-};
-
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
diff --git a/sandbox/linux/bpf_dsl/codegen_unittest.cc b/sandbox/linux/bpf_dsl/codegen_unittest.cc
deleted file mode 100644
index 56a0dd27e1..0000000000
--- a/sandbox/linux/bpf_dsl/codegen_unittest.cc
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright (c) 2012 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/codegen.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/md5.h"
-#include "base/strings/string_piece.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace sandbox {
-namespace {
-
-// Hash provides an abstraction for building "hash trees" from BPF
-// control flow graphs, and efficiently identifying equivalent graphs.
-//
-// For simplicity, we use MD5, because base happens to provide a
-// convenient API for its use. However, any collision-resistant hash
-// should suffice.
-class Hash {
- public:
- static const Hash kZero;
-
- Hash() : digest_() {}
-
- Hash(uint16_t code,
- uint32_t k,
- const Hash& jt = kZero,
- const Hash& jf = kZero)
- : digest_() {
- base::MD5Context ctx;
- base::MD5Init(&ctx);
- HashValue(&ctx, code);
- HashValue(&ctx, k);
- HashValue(&ctx, jt);
- HashValue(&ctx, jf);
- base::MD5Final(&digest_, &ctx);
- }
-
- Hash(const Hash& hash) = default;
- Hash& operator=(const Hash& rhs) = default;
-
- friend bool operator==(const Hash& lhs, const Hash& rhs) {
- return lhs.Base16() == rhs.Base16();
- }
- friend bool operator!=(const Hash& lhs, const Hash& rhs) {
- return !(lhs == rhs);
- }
-
- private:
- template <typename T>
- void HashValue(base::MD5Context* ctx, const T& value) {
- base::MD5Update(ctx,
- base::StringPiece(reinterpret_cast<const char*>(&value),
- sizeof(value)));
- }
-
- std::string Base16() const {
- return base::MD5DigestToBase16(digest_);
- }
-
- base::MD5Digest digest_;
-};
-
-const Hash Hash::kZero;
-
-// Sanity check that equality and inequality work on Hash as required.
-TEST(CodeGen, HashSanity) {
- std::vector<Hash> hashes;
-
- // Push a bunch of logically distinct hashes.
- hashes.push_back(Hash::kZero);
- for (int i = 0; i < 4; ++i) {
- hashes.push_back(Hash(i & 1, i & 2));
- }
- for (int i = 0; i < 16; ++i) {
- hashes.push_back(Hash(i & 1, i & 2, Hash(i & 4, i & 8)));
- }
- for (int i = 0; i < 64; ++i) {
- hashes.push_back(
- Hash(i & 1, i & 2, Hash(i & 4, i & 8), Hash(i & 16, i & 32)));
- }
-
- for (const Hash& a : hashes) {
- for (const Hash& b : hashes) {
- // Hashes should equal themselves, but not equal all others.
- if (&a == &b) {
- EXPECT_EQ(a, b);
- } else {
- EXPECT_NE(a, b);
- }
- }
- }
-}
-
-// ProgramTest provides a fixture for writing compiling sample
-// programs with CodeGen and verifying the linearized output matches
-// the input DAG.
-class ProgramTest : public ::testing::Test {
- protected:
- ProgramTest() : gen_(), node_hashes_() {}
-
- // MakeInstruction calls CodeGen::MakeInstruction() and associated
- // the returned address with a hash of the instruction.
- CodeGen::Node MakeInstruction(uint16_t code,
- uint32_t k,
- CodeGen::Node jt = CodeGen::kNullNode,
- CodeGen::Node jf = CodeGen::kNullNode) {
- CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf);
- EXPECT_NE(CodeGen::kNullNode, res);
-
- Hash digest(code, k, Lookup(jt), Lookup(jf));
- auto it = node_hashes_.insert(std::make_pair(res, digest));
- EXPECT_EQ(digest, it.first->second);
-
- return res;
- }
-
- // RunTest compiles the program and verifies that the output matches
- // what is expected. It should be called at the end of each program
- // test case.
- void RunTest(CodeGen::Node head) {
- // Compile the program
- CodeGen::Program program = gen_.Compile(head);
-
- // Walk the program backwards, and compute the hash for each instruction.
- std::vector<Hash> prog_hashes(program.size());
- for (size_t i = program.size(); i > 0; --i) {
- const sock_filter& insn = program.at(i - 1);
- Hash& hash = prog_hashes.at(i - 1);
-
- if (BPF_CLASS(insn.code) == BPF_JMP) {
- if (BPF_OP(insn.code) == BPF_JA) {
- // The compiler adds JA instructions as needed, so skip them.
- hash = prog_hashes.at(i + insn.k);
- } else {
- hash = Hash(insn.code, insn.k, prog_hashes.at(i + insn.jt),
- prog_hashes.at(i + insn.jf));
- }
- } else if (BPF_CLASS(insn.code) == BPF_RET) {
- hash = Hash(insn.code, insn.k);
- } else {
- hash = Hash(insn.code, insn.k, prog_hashes.at(i));
- }
- }
-
- EXPECT_EQ(Lookup(head), prog_hashes.at(0));
- }
-
- private:
- const Hash& Lookup(CodeGen::Node next) const {
- if (next == CodeGen::kNullNode) {
- return Hash::kZero;
- }
- auto it = node_hashes_.find(next);
- if (it == node_hashes_.end()) {
- ADD_FAILURE() << "No hash found for node " << next;
- return Hash::kZero;
- }
- return it->second;
- }
-
- CodeGen gen_;
- std::map<CodeGen::Node, Hash> node_hashes_;
-
- DISALLOW_COPY_AND_ASSIGN(ProgramTest);
-};
-
-TEST_F(ProgramTest, OneInstruction) {
- // Create the most basic valid BPF program:
- // RET 0
- CodeGen::Node head = MakeInstruction(BPF_RET + BPF_K, 0);
- RunTest(head);
-}
-
-TEST_F(ProgramTest, SimpleBranch) {
- // Create a program with a single branch:
- // JUMP if eq 42 then $0 else $1
- // 0: RET 1
- // 1: RET 0
- CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42,
- MakeInstruction(BPF_RET + BPF_K, 1),
- MakeInstruction(BPF_RET + BPF_K, 0));
- RunTest(head);
-}
-
-TEST_F(ProgramTest, AtypicalBranch) {
- // Create a program with a single branch:
- // JUMP if eq 42 then $0 else $0
- // 0: RET 0
-
- CodeGen::Node ret = MakeInstruction(BPF_RET + BPF_K, 0);
- CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
-
- // N.B.: As the instructions in both sides of the branch are already
- // the same object, we do not actually have any "mergeable" branches.
- // This needs to be reflected in our choice of "flags".
- RunTest(head);
-}
-
-TEST_F(ProgramTest, Complex) {
- // Creates a basic BPF program that we'll use to test some of the code:
- // JUMP if eq 42 the $0 else $1 (insn6)
- // 0: LD 23 (insn5)
- // 1: JUMP if eq 42 then $2 else $4 (insn4)
- // 2: JUMP to $3 (insn2)
- // 3: LD 42 (insn1)
- // RET 42 (insn0)
- // 4: LD 42 (insn3)
- // RET 42 (insn3+)
- CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42);
- CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0);
- CodeGen::Node insn2 = insn1; // Implicit JUMP
-
- // We explicitly duplicate instructions to test that they're merged.
- CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42,
- MakeInstruction(BPF_RET + BPF_K, 42));
- EXPECT_EQ(insn2, insn3);
-
- CodeGen::Node insn4 =
- MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3);
- CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
-
- // Force a basic block that ends in neither a jump instruction nor a return
- // instruction. It only contains "insn5". This exercises one of the less
- // common code paths in the topo-sort algorithm.
- // This also gives us a diamond-shaped pattern in our graph, which stresses
- // another aspect of the topo-sort algorithm (namely, the ability to
- // correctly count the incoming branches for subtrees that are not disjunct).
- CodeGen::Node insn6 =
- MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4);
-
- RunTest(insn6);
-}
-
-TEST_F(ProgramTest, ConfusingTails) {
- // This simple program demonstrates https://crbug.com/351103/
- // The two "LOAD 0" instructions are blocks of their own. MergeTails() could
- // be tempted to merge them since they are the same. However, they are
- // not mergeable because they fall-through to non semantically equivalent
- // blocks.
- // Without the fix for this bug, this program should trigger the check in
- // CompileAndCompare: the serialized graphs from the program and its compiled
- // version will differ.
- //
- // 0) LOAD 1 // ???
- // 1) if A == 0x1; then JMP 2 else JMP 3
- // 2) LOAD 0 // System call number
- // 3) if A == 0x2; then JMP 4 else JMP 5
- // 4) LOAD 0 // System call number
- // 5) if A == 0x1; then JMP 6 else JMP 7
- // 6) RET 0
- // 7) RET 1
-
- CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
- CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
- CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
- CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
- CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
- CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
- CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
- CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
-
- RunTest(i0);
-}
-
-TEST_F(ProgramTest, ConfusingTailsBasic) {
- // Without the fix for https://crbug.com/351103/, (see
- // SampleProgramConfusingTails()), this would generate a cyclic graph and
- // crash as the two "LOAD 0" instructions would get merged.
- //
- // 0) LOAD 1 // ???
- // 1) if A == 0x1; then JMP 2 else JMP 3
- // 2) LOAD 0 // System call number
- // 3) if A == 0x2; then JMP 4 else JMP 5
- // 4) LOAD 0 // System call number
- // 5) RET 1
-
- CodeGen::Node i5 = MakeInstruction(BPF_RET + BPF_K, 1);
- CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
- CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
- CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
- CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
- CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
-
- RunTest(i0);
-}
-
-TEST_F(ProgramTest, ConfusingTailsMergeable) {
- // This is similar to SampleProgramConfusingTails(), except that
- // instructions 2 and 4 are now RET instructions.
- // In PointerCompare(), this exercises the path where two blocks are of the
- // same length and identical and the last instruction is a JMP or RET, so the
- // following blocks don't need to be looked at and the blocks are mergeable.
- //
- // 0) LOAD 1 // ???
- // 1) if A == 0x1; then JMP 2 else JMP 3
- // 2) RET 42
- // 3) if A == 0x2; then JMP 4 else JMP 5
- // 4) RET 42
- // 5) if A == 0x1; then JMP 6 else JMP 7
- // 6) RET 0
- // 7) RET 1
-
- CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
- CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
- CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
- CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42);
- CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
- CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42);
- CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
- CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
-
- RunTest(i0);
-}
-
-TEST_F(ProgramTest, InstructionFolding) {
- // Check that simple instructions are folded as expected.
- CodeGen::Node a = MakeInstruction(BPF_RET + BPF_K, 0);
- EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0));
- CodeGen::Node b = MakeInstruction(BPF_RET + BPF_K, 1);
- EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0));
- EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1));
- EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1));
-
- // Check that complex sequences are folded too.
- CodeGen::Node c =
- MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0,
- MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b));
- EXPECT_EQ(c, MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS, 0,
- MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b)));
-
- RunTest(c);
-}
-
-TEST_F(ProgramTest, FarBranches) {
- // BPF instructions use 8-bit fields for branch offsets, which means
- // branch targets must be within 255 instructions of the branch
- // instruction. CodeGen abstracts away this detail by inserting jump
- // instructions as needed, which we test here by generating programs
- // that should trigger any interesting boundary conditions.
-
- // Populate with 260 initial instruction nodes.
- std::vector<CodeGen::Node> nodes;
- nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0));
- for (size_t i = 1; i < 260; ++i) {
- nodes.push_back(
- MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back()));
- }
-
- // Exhaustively test branch offsets near BPF's limits.
- for (size_t jt = 250; jt < 260; ++jt) {
- for (size_t jf = 250; jf < 260; ++jf) {
- nodes.push_back(MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0,
- nodes.rbegin()[jt], nodes.rbegin()[jf]));
- RunTest(nodes.back());
- }
- }
-}
-
-TEST_F(ProgramTest, JumpReuse) {
- // As a code size optimization, we try to reuse jumps when possible
- // instead of emitting new ones. Here we make sure that optimization
- // is working as intended.
- //
- // NOTE: To simplify testing, we rely on implementation details
- // about what CodeGen::Node values indicate (i.e., vector indices),
- // but CodeGen users should treat them as opaque values.
-
- // Populate with 260 initial instruction nodes.
- std::vector<CodeGen::Node> nodes;
- nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0));
- for (size_t i = 1; i < 260; ++i) {
- nodes.push_back(
- MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back()));
- }
-
- // Branching to nodes[0] and nodes[1] should require 3 new
- // instructions: two far jumps plus the branch itself.
- CodeGen::Node one =
- MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0, nodes[0], nodes[1]);
- EXPECT_EQ(nodes.back() + 3, one); // XXX: Implementation detail!
- RunTest(one);
-
- // Branching again to the same target nodes should require only one
- // new instruction, as we can reuse the previous branch's jumps.
- CodeGen::Node two =
- MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, nodes[0], nodes[1]);
- EXPECT_EQ(one + 1, two); // XXX: Implementation detail!
- RunTest(two);
-}
-
-} // namespace
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/cons.h b/sandbox/linux/bpf_dsl/cons.h
deleted file mode 100644
index 07ac3dfc23..0000000000
--- a/sandbox/linux/bpf_dsl/cons.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_CONS_H_
-#define SANDBOX_LINUX_BPF_DSL_CONS_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace cons {
-
-// Namespace cons provides an abstraction for immutable "cons list"
-// data structures as commonly provided in functional programming
-// languages like Lisp or Haskell.
-//
-// A cons list is a linked list consisting of "cells", each of which
-// have a "head" and a "tail" element. A cell's head element contains
-// a user specified value, while the tail element contains a (possibly
-// null) pointer to another cell.
-//
-// An empty list (idiomatically referred to as "nil") can be
-// constructed as "cons::List<Foo>()" or simply as "nullptr" if Foo
-// can be inferred from context (e.g., calling a function that has a
-// "cons::List<Foo>" parameter).
-//
-// Existing lists (including empty lists) can be extended by
-// prepending new values to the front using the "Cons(head, tail)"
-// function, which will allocate a new cons cell. Notably, cons lists
-// support creating multiple lists that share a common tail sequence.
-//
-// Lastly, lists support iteration via C++11's range-based for loop
-// construct.
-//
-// Examples:
-//
-// // basic construction
-// const cons::List<char> kNil = nullptr;
-// cons::List<char> ba = Cons('b', Cons('a', kNil));
-//
-// // common tail sequence
-// cons::List<char> cba = Cons('c', ba);
-// cons::List<char> dba = Cons('d', ba);
-//
-// // iteration
-// for (const char& ch : cba) {
-// // iterates 'c', 'b', 'a'
-// }
-// for (const char& ch : dba) {
-// // iterates 'd', 'b', 'a'
-// }
-
-// Forward declarations.
-template <typename T>
-class Cell;
-template <typename T>
-class ListIterator;
-
-// List represents a (possibly null) pointer to a cons cell.
-template <typename T>
-using List = std::shared_ptr<const Cell<T>>;
-
-// Cons extends a cons list by prepending a new value to the front.
-template <typename T>
-List<T> Cons(const T& head, List<T> tail) {
- return std::make_shared<Cell<T>>(head, std::move(tail));
-}
-
-// Cell represents an individual "cons cell" within a cons list.
-template <typename T>
-class Cell {
- public:
- Cell(const T& head, List<T> tail) : head_(head), tail_(std::move(tail)) {}
-
- // Head returns this cell's head element.
- const T& head() const { return head_; }
-
- // Tail returns this cell's tail element.
- const List<T>& tail() const { return tail_; }
-
- private:
- T head_;
- List<T> tail_;
-
- DISALLOW_COPY_AND_ASSIGN(Cell);
-};
-
-// Begin returns a list iterator pointing to the first element of the
-// cons list. It's provided to support range-based for loops.
-template <typename T>
-ListIterator<T> begin(const List<T>& list) {
- return ListIterator<T>(list);
-}
-
-// End returns a list iterator pointing to the "past-the-end" element
-// of the cons list (i.e., nil). It's provided to support range-based
-// for loops.
-template <typename T>
-ListIterator<T> end(const List<T>& list) {
- return ListIterator<T>();
-}
-
-// ListIterator provides C++ forward iterator semantics for traversing
-// a cons list.
-template <typename T>
-class ListIterator {
- public:
- ListIterator() : list_() {}
- explicit ListIterator(const List<T>& list) : list_(list) {}
-
- const T& operator*() const { return list_->head(); }
-
- ListIterator& operator++() {
- list_ = list_->tail();
- return *this;
- }
-
- friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) {
- return lhs.list_ == rhs.list_;
- }
-
- private:
- List<T> list_;
-};
-
-template <typename T>
-bool operator!=(const ListIterator<T>& lhs, const ListIterator<T>& rhs) {
- return !(lhs == rhs);
-}
-
-} // namespace cons
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_CONS_H_
diff --git a/sandbox/linux/bpf_dsl/dump_bpf.cc b/sandbox/linux/bpf_dsl/dump_bpf.cc
deleted file mode 100644
index 2edf592f68..0000000000
--- a/sandbox/linux/bpf_dsl/dump_bpf.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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/dump_bpf.h"
-
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <string>
-
-#include "base/strings/stringprintf.h"
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-#include "sandbox/linux/bpf_dsl/trap_registry.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-#include "sandbox/linux/system_headers/linux_seccomp.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-namespace {
-
-const char* AluOpToken(uint32_t code) {
- switch (BPF_OP(code)) {
- case BPF_ADD:
- return "+";
- case BPF_SUB:
- return "-";
- case BPF_MUL:
- return "*";
- case BPF_DIV:
- return "/";
- case BPF_MOD:
- return "%";
- case BPF_OR:
- return "|";
- case BPF_XOR:
- return "^";
- case BPF_AND:
- return "&";
- case BPF_LSH:
- return "<<";
- case BPF_RSH:
- return ">>";
- default:
- return "???";
- }
-}
-
-const char* JmpOpToken(uint32_t code) {
- switch (BPF_OP(code)) {
- case BPF_JSET:
- return "&";
- case BPF_JEQ:
- return "==";
- case BPF_JGE:
- return ">=";
- default:
- return "???";
- }
-}
-
-const char* DataOffsetName(size_t off) {
- switch (off) {
- case SECCOMP_NR_IDX:
- return "System call number";
- case SECCOMP_ARCH_IDX:
- return "Architecture";
- case SECCOMP_IP_LSB_IDX:
- return "Instruction pointer (LSB)";
- case SECCOMP_IP_MSB_IDX:
- return "Instruction pointer (MSB)";
- default:
- return "???";
- }
-}
-
-void AppendInstruction(std::string* dst, size_t pc, const sock_filter& insn) {
- base::StringAppendF(dst, "%3zu) ", pc);
- switch (BPF_CLASS(insn.code)) {
- case BPF_LD:
- if (insn.code == BPF_LD + BPF_W + BPF_ABS) {
- base::StringAppendF(dst, "LOAD %" PRIu32 " // ", insn.k);
- size_t maybe_argno =
- (insn.k - offsetof(struct arch_seccomp_data, args)) /
- sizeof(uint64_t);
- if (maybe_argno < 6 && insn.k == SECCOMP_ARG_LSB_IDX(maybe_argno)) {
- base::StringAppendF(dst, "Argument %zu (LSB)\n", maybe_argno);
- } else if (maybe_argno < 6 &&
- insn.k == SECCOMP_ARG_MSB_IDX(maybe_argno)) {
- base::StringAppendF(dst, "Argument %zu (MSB)\n", maybe_argno);
- } else {
- base::StringAppendF(dst, "%s\n", DataOffsetName(insn.k));
- }
- } else {
- base::StringAppendF(dst, "Load ???\n");
- }
- break;
- case BPF_JMP:
- if (BPF_OP(insn.code) == BPF_JA) {
- base::StringAppendF(dst, "JMP %zu\n", pc + insn.k + 1);
- } else {
- base::StringAppendF(
- dst, "if A %s 0x%" PRIx32 "; then JMP %zu else JMP %zu\n",
- JmpOpToken(insn.code), insn.k, pc + insn.jt + 1, pc + insn.jf + 1);
- }
- break;
- case BPF_RET:
- base::StringAppendF(dst, "RET 0x%" PRIx32 " // ", insn.k);
- if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) {
- base::StringAppendF(dst, "Trap #%" PRIu32 "\n",
- insn.k & SECCOMP_RET_DATA);
- } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
- base::StringAppendF(dst, "errno = %" PRIu32 "\n",
- insn.k & SECCOMP_RET_DATA);
- } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
- base::StringAppendF(dst, "Trace #%" PRIu32 "\n",
- insn.k & SECCOMP_RET_DATA);
- } else if (insn.k == SECCOMP_RET_ALLOW) {
- base::StringAppendF(dst, "Allowed\n");
- } else if (insn.k == SECCOMP_RET_KILL) {
- base::StringAppendF(dst, "Kill\n");
- } else {
- base::StringAppendF(dst, "???\n");
- }
- break;
- case BPF_ALU:
- if (BPF_OP(insn.code) == BPF_NEG) {
- base::StringAppendF(dst, "A := -A\n");
- } else {
- base::StringAppendF(dst, "A := A %s 0x%" PRIx32 "\n",
- AluOpToken(insn.code), insn.k);
- }
- break;
- default:
- base::StringAppendF(dst, "???\n");
- break;
- }
-}
-
-} // namespace
-
-void DumpBPF::PrintProgram(const CodeGen::Program& program) {
- fputs(StringPrintProgram(program).c_str(), stderr);
-}
-
-std::string DumpBPF::StringPrintProgram(const CodeGen::Program& program) {
- std::string res;
- for (size_t i = 0; i < program.size(); i++) {
- AppendInstruction(&res, i + 1, program[i]);
- }
- return res;
-}
-
-} // namespace bpf_dsl
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/dump_bpf.h b/sandbox/linux/bpf_dsl/dump_bpf.h
deleted file mode 100644
index a7db58981b..0000000000
--- a/sandbox/linux/bpf_dsl/dump_bpf.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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 <string>
-
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-class SANDBOX_EXPORT DumpBPF {
- public:
- // PrintProgram writes |program| in a human-readable format to stderr.
- static void PrintProgram(const CodeGen::Program& program);
-
- // StringPrintProgram writes |program| in a human-readable format to
- // a std::string.
- static std::string StringPrintProgram(const CodeGen::Program& program);
-};
-
-} // namespace bpf_dsl
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/errorcode.h b/sandbox/linux/bpf_dsl/errorcode.h
deleted file mode 100644
index 611c27dd80..0000000000
--- a/sandbox/linux/bpf_dsl/errorcode.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
-#define SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
-
-#include "base/macros.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-// TODO(mdempsky): Find a proper home for ERR_{MIN,MAX}_ERRNO and
-// remove this header.
-class SANDBOX_EXPORT ErrorCode {
- public:
- enum {
- ERR_MIN_ERRNO = 0,
-#if defined(__mips__)
- // MIPS only supports errno up to 1133
- ERR_MAX_ERRNO = 1133,
-#else
- // TODO(markus): Android only supports errno up to 255
- // (crbug.com/181647).
- ERR_MAX_ERRNO = 4095,
-#endif
- };
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ErrorCode);
-};
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
diff --git a/sandbox/linux/bpf_dsl/linux_syscall_ranges.h b/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
deleted file mode 100644
index a747770c78..0000000000
--- a/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
-#define SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
-
-#if defined(__x86_64__)
-
-#define MIN_SYSCALL 0u
-#define MAX_PUBLIC_SYSCALL 1024u
-#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
-
-#elif defined(__i386__)
-
-#define MIN_SYSCALL 0u
-#define MAX_PUBLIC_SYSCALL 1024u
-#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
-
-#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
-
-// ARM EABI includes "ARM private" system calls starting at |__ARM_NR_BASE|,
-// and a "ghost syscall private to the kernel", cmpxchg,
-// at |__ARM_NR_BASE+0x00fff0|.
-// See </arch/arm/include/asm/unistd.h> in the Linux kernel.
-
-// __NR_SYSCALL_BASE is 0 in thumb and ARM EABI.
-#define MIN_SYSCALL 0u
-#define MAX_PUBLIC_SYSCALL (MIN_SYSCALL + 1024u)
-// __ARM_NR_BASE is __NR_SYSCALL_BASE + 0xf0000u
-#define MIN_PRIVATE_SYSCALL 0xf0000u
-#define MAX_PRIVATE_SYSCALL (MIN_PRIVATE_SYSCALL + 16u)
-#define MIN_GHOST_SYSCALL (MIN_PRIVATE_SYSCALL + 0xfff0u)
-#define MAX_SYSCALL (MIN_GHOST_SYSCALL + 4u)
-
-#elif defined(__mips__) && (_MIPS_SIM == _ABIO32)
-
-#include <asm/unistd.h> // for __NR_O32_Linux and __NR_Linux_syscalls
-#define MIN_SYSCALL __NR_O32_Linux
-#define MAX_PUBLIC_SYSCALL (MIN_SYSCALL + __NR_Linux_syscalls)
-#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
-
-#elif defined(__mips__) && (_MIPS_SIM == _ABI64)
-
-#error "Add support to header file"
-
-#elif defined(__aarch64__)
-
-#define MIN_SYSCALL 0u
-#define MAX_PUBLIC_SYSCALL 279u
-#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
-
-#else
-#error "Unsupported architecture"
-#endif
-
-#endif // SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
diff --git a/sandbox/linux/bpf_dsl/policy.cc b/sandbox/linux/bpf_dsl/policy.cc
deleted file mode 100644
index c20edc6da8..0000000000
--- a/sandbox/linux/bpf_dsl/policy.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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/policy.h"
-
-#include <errno.h>
-
-#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-ResultExpr Policy::InvalidSyscall() const {
- return Error(ENOSYS);
-}
-
-} // namespace bpf_dsl
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/policy.h b/sandbox/linux/bpf_dsl/policy.h
deleted file mode 100644
index 6c67589456..0000000000
--- a/sandbox/linux/bpf_dsl/policy.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_H_
-#define SANDBOX_LINUX_BPF_DSL_POLICY_H_
-
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-// Interface to implement to define a BPF sandbox policy.
-class SANDBOX_EXPORT Policy {
- public:
- Policy() {}
- virtual ~Policy() {}
-
- // User extension point for writing custom sandbox policies.
- // The returned ResultExpr will control how the kernel responds to the
- // specified system call number.
- 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;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Policy);
-};
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_POLICY_H_
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
deleted file mode 100644
index 7ce517a5d5..0000000000
--- a/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ /dev/null
@@ -1,466 +0,0 @@
-// Copyright (c) 2012 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/policy_compiler.h"
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/syscall.h>
-
-#include <limits>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/linux/bpf_dsl/policy.h"
-#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-#include "sandbox/linux/bpf_dsl/syscall_set.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-#include "sandbox/linux/system_headers/linux_seccomp.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-namespace {
-
-#if defined(__i386__) || defined(__x86_64__)
-const bool kIsIntel = true;
-#else
-const bool kIsIntel = false;
-#endif
-#if defined(__x86_64__) && defined(__ILP32__)
-const bool kIsX32 = true;
-#else
-const bool kIsX32 = false;
-#endif
-
-const int kSyscallsRequiredForUnsafeTraps[] = {
- __NR_rt_sigprocmask,
- __NR_rt_sigreturn,
-#if defined(__NR_sigprocmask)
- __NR_sigprocmask,
-#endif
-#if defined(__NR_sigreturn)
- __NR_sigreturn,
-#endif
-};
-
-bool HasExactlyOneBit(uint64_t x) {
- // Common trick; e.g., see http://stackoverflow.com/a/108329.
- return x != 0 && (x & (x - 1)) == 0;
-}
-
-ResultExpr DefaultPanic(const char* error) {
- return Kill();
-}
-
-// A Trap() handler that returns an "errno" value. The value is encoded
-// in the "aux" parameter.
-intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
- // TrapFnc functions report error by following the native kernel convention
- // of returning an exit code in the range of -1..-4096. They do not try to
- // set errno themselves. The glibc wrapper that triggered the SIGSYS will
- // ultimately do so for us.
- int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA;
- return -err;
-}
-
-bool HasUnsafeTraps(const Policy* policy) {
- DCHECK(policy);
- for (uint32_t sysnum : SyscallSet::ValidOnly()) {
- if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) {
- return true;
- }
- }
- return policy->InvalidSyscall()->HasUnsafeTraps();
-}
-
-} // namespace
-
-struct PolicyCompiler::Range {
- uint32_t from;
- CodeGen::Node node;
-};
-
-PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
- : policy_(policy),
- registry_(registry),
- escapepc_(0),
- panic_func_(DefaultPanic),
- gen_(),
- has_unsafe_traps_(HasUnsafeTraps(policy_)) {
- DCHECK(policy);
-}
-
-PolicyCompiler::~PolicyCompiler() {
-}
-
-CodeGen::Program PolicyCompiler::Compile() {
- CHECK(policy_->InvalidSyscall()->IsDeny())
- << "Policies should deny invalid system calls";
-
- // If our BPF program has unsafe traps, enable support for them.
- if (has_unsafe_traps_) {
- CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC";
-
- for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
- CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow())
- << "Policies that use UnsafeTrap() must unconditionally allow all "
- "required system calls";
- }
-
- CHECK(registry_->EnableUnsafeTraps())
- << "We'd rather die than enable unsafe traps";
- }
-
- // Assemble the BPF filter program.
- return gen_.Compile(AssemblePolicy());
-}
-
-void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
- escapepc_ = escapepc;
-}
-
-void PolicyCompiler::SetPanicFunc(PanicFunc panic_func) {
- panic_func_ = panic_func;
-}
-
-CodeGen::Node PolicyCompiler::AssemblePolicy() {
- // A compiled policy consists of three logical parts:
- // 1. Check that the "arch" field matches the expected architecture.
- // 2. If the policy involves unsafe traps, check if the syscall was
- // invoked by Syscall::Call, and then allow it unconditionally.
- // 3. Check the system call number and jump to the appropriate compiled
- // system call policy number.
- return CheckArch(MaybeAddEscapeHatch(DispatchSyscall()));
-}
-
-CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
- // If the architecture doesn't match SECCOMP_ARCH, disallow the
- // system call.
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX,
- gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
- CompileResult(panic_func_(
- "Invalid audit architecture in BPF filter"))));
-}
-
-CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
- // If no unsafe traps, then simply return |rest|.
- if (!has_unsafe_traps_) {
- return rest;
- }
-
- // We already enabled unsafe traps in Compile, but enable them again to give
- // the trap registry a second chance to complain before we add the backdoor.
- CHECK(registry_->EnableUnsafeTraps());
-
- // Allow system calls, if they originate from our magic return address.
- const uint32_t lopc = static_cast<uint32_t>(escapepc_);
- const uint32_t hipc = static_cast<uint32_t>(escapepc_ >> 32);
-
- // BPF cannot do native 64-bit comparisons, so we have to compare
- // both 32-bit halves of the instruction pointer. If they match what
- // we expect, we return ERR_ALLOWED. If either or both don't match,
- // we continue evalutating the rest of the sandbox policy.
- //
- // For simplicity, we check the full 64-bit instruction pointer even
- // on 32-bit architectures.
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX,
- gen_.MakeInstruction(
- BPF_JMP + BPF_JEQ + BPF_K, lopc,
- gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX,
- gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hipc,
- CompileResult(Allow()), rest)),
- rest));
-}
-
-CodeGen::Node PolicyCompiler::DispatchSyscall() {
- // Evaluate all possible system calls and group their Nodes into
- // ranges of identical codes.
- Ranges ranges;
- FindRanges(&ranges);
-
- // Compile the system call ranges to an optimized BPF jumptable
- CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end());
-
- // Grab the system call number, so that we can check it and then
- // execute the jump table.
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable));
-}
-
-CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) {
- if (kIsIntel) {
- // On Intel architectures, verify that system call numbers are in the
- // expected number range.
- CodeGen::Node invalidX32 =
- CompileResult(panic_func_("Illegal mixing of system call ABIs"));
- if (kIsX32) {
- // The newer x32 API always sets bit 30.
- return gen_.MakeInstruction(
- BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32);
- } else {
- // The older i386 and x86-64 APIs clear bit 30 on all system calls.
- return gen_.MakeInstruction(
- BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed);
- }
- }
-
- // TODO(mdempsky): Similar validation for other architectures?
- return passed;
-}
-
-void PolicyCompiler::FindRanges(Ranges* ranges) {
- // Please note that "struct seccomp_data" defines system calls as a signed
- // int32_t, but BPF instructions always operate on unsigned quantities. We
- // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
- // and then verifying that the rest of the number range (both positive and
- // negative) all return the same Node.
- const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall());
- uint32_t old_sysnum = 0;
- CodeGen::Node old_node =
- SyscallSet::IsValid(old_sysnum)
- ? CompileResult(policy_->EvaluateSyscall(old_sysnum))
- : invalid_node;
-
- for (uint32_t sysnum : SyscallSet::All()) {
- CodeGen::Node node =
- SyscallSet::IsValid(sysnum)
- ? CompileResult(policy_->EvaluateSyscall(static_cast<int>(sysnum)))
- : invalid_node;
- // N.B., here we rely on CodeGen folding (i.e., returning the same
- // node value for) identical code sequences, otherwise our jump
- // table will blow up in size.
- if (node != old_node) {
- ranges->push_back(Range{old_sysnum, old_node});
- old_sysnum = sysnum;
- old_node = node;
- }
- }
- ranges->push_back(Range{old_sysnum, old_node});
-}
-
-CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
- Ranges::const_iterator stop) {
- // We convert the list of system call ranges into jump table that performs
- // a binary search over the ranges.
- // As a sanity check, we need to have at least one distinct ranges for us
- // to be able to build a jump table.
- CHECK(start < stop) << "Invalid iterator range";
- const auto n = stop - start;
- if (n == 1) {
- // If we have narrowed things down to a single range object, we can
- // return from the BPF filter program.
- return start->node;
- }
-
- // Pick the range object that is located at the mid point of our list.
- // We compare our system call number against the lowest valid system call
- // number in this range object. If our number is lower, it is outside of
- // this range object. If it is greater or equal, it might be inside.
- Ranges::const_iterator mid = start + n / 2;
-
- // Sub-divide the list of ranges and continue recursively.
- CodeGen::Node jf = AssembleJumpTable(start, mid);
- CodeGen::Node jt = AssembleJumpTable(mid, stop);
- return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
-}
-
-CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
- return res->Compile(this);
-}
-
-CodeGen::Node PolicyCompiler::MaskedEqual(int argno,
- size_t width,
- uint64_t mask,
- uint64_t value,
- CodeGen::Node passed,
- CodeGen::Node failed) {
- // Sanity check that arguments make sense.
- CHECK(argno >= 0 && argno < 6) << "Invalid argument number " << argno;
- CHECK(width == 4 || width == 8) << "Invalid argument width " << width;
- CHECK_NE(0U, mask) << "Zero mask is invalid";
- CHECK_EQ(value, value & mask) << "Value contains masked out bits";
- if (sizeof(void*) == 4) {
- CHECK_EQ(4U, width) << "Invalid width on 32-bit platform";
- }
- if (width == 4) {
- CHECK_EQ(0U, mask >> 32) << "Mask exceeds argument size";
- CHECK_EQ(0U, value >> 32) << "Value exceeds argument size";
- }
-
- // We want to emit code to check "(arg & mask) == value" where arg, mask, and
- // value are 64-bit values, but the BPF machine is only 32-bit. We implement
- // this by independently testing the upper and lower 32-bits and continuing to
- // |passed| if both evaluate true, or to |failed| if either evaluate false.
- return MaskedEqualHalf(argno, width, mask, value, ArgHalf::UPPER,
- MaskedEqualHalf(argno, width, mask, value,
- ArgHalf::LOWER, passed, failed),
- failed);
-}
-
-CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno,
- size_t width,
- uint64_t full_mask,
- uint64_t full_value,
- ArgHalf half,
- CodeGen::Node passed,
- CodeGen::Node failed) {
- if (width == 4 && half == ArgHalf::UPPER) {
- // Special logic for sanity checking the upper 32-bits of 32-bit system
- // call arguments.
-
- // TODO(mdempsky): Compile Unexpected64bitArgument() just per program.
- CodeGen::Node invalid_64bit = Unexpected64bitArgument();
-
- const uint32_t upper = SECCOMP_ARG_MSB_IDX(argno);
- const uint32_t lower = SECCOMP_ARG_LSB_IDX(argno);
-
- if (sizeof(void*) == 4) {
- // On 32-bit platforms, the upper 32-bits should always be 0:
- // LDW [upper]
- // JEQ 0, passed, invalid
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- upper,
- gen_.MakeInstruction(
- BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit));
- }
-
- // On 64-bit platforms, the upper 32-bits may be 0 or ~0; but we only allow
- // ~0 if the sign bit of the lower 32-bits is set too:
- // LDW [upper]
- // JEQ 0, passed, (next)
- // JEQ ~0, (next), invalid
- // LDW [lower]
- // JSET (1<<31), passed, invalid
- //
- // TODO(mdempsky): The JSET instruction could perhaps jump to passed->next
- // instead, as the first instruction of passed should be "LDW [lower]".
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- upper,
- gen_.MakeInstruction(
- BPF_JMP + BPF_JEQ + BPF_K,
- 0,
- passed,
- gen_.MakeInstruction(
- BPF_JMP + BPF_JEQ + BPF_K,
- std::numeric_limits<uint32_t>::max(),
- gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- lower,
- gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K,
- 1U << 31,
- passed,
- invalid_64bit)),
- invalid_64bit)));
- }
-
- const uint32_t idx = (half == ArgHalf::UPPER) ? SECCOMP_ARG_MSB_IDX(argno)
- : SECCOMP_ARG_LSB_IDX(argno);
- const uint32_t mask = (half == ArgHalf::UPPER) ? full_mask >> 32 : full_mask;
- const uint32_t value =
- (half == ArgHalf::UPPER) ? full_value >> 32 : full_value;
-
- // Emit a suitable instruction sequence for (arg & mask) == value.
-
- // For (arg & 0) == 0, just return passed.
- if (mask == 0) {
- CHECK_EQ(0U, value);
- return passed;
- }
-
- // For (arg & ~0) == value, emit:
- // LDW [idx]
- // JEQ value, passed, failed
- if (mask == std::numeric_limits<uint32_t>::max()) {
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- idx,
- gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed));
- }
-
- // For (arg & mask) == 0, emit:
- // LDW [idx]
- // JSET mask, failed, passed
- // (Note: failed and passed are intentionally swapped.)
- if (value == 0) {
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- idx,
- gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, failed, passed));
- }
-
- // For (arg & x) == x where x is a single-bit value, emit:
- // LDW [idx]
- // JSET mask, passed, failed
- if (mask == value && HasExactlyOneBit(mask)) {
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- idx,
- gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, passed, failed));
- }
-
- // Generic fallback:
- // LDW [idx]
- // AND mask
- // JEQ value, passed, failed
- return gen_.MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS,
- idx,
- gen_.MakeInstruction(
- BPF_ALU + BPF_AND + BPF_K,
- mask,
- gen_.MakeInstruction(
- BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)));
-}
-
-CodeGen::Node PolicyCompiler::Unexpected64bitArgument() {
- return CompileResult(panic_func_("Unexpected 64bit argument detected"));
-}
-
-CodeGen::Node PolicyCompiler::Return(uint32_t ret) {
- if (has_unsafe_traps_ && (ret & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
- // When inside an UnsafeTrap() callback, we want to allow all system calls.
- // This means, we must conditionally disable the sandbox -- and that's not
- // something that kernel-side BPF filters can do, as they cannot inspect
- // any state other than the syscall arguments.
- // But if we redirect all error handlers to user-space, then we can easily
- // make this decision.
- // The performance penalty for this extra round-trip to user-space is not
- // actually that bad, as we only ever pay it for denied system calls; and a
- // typical program has very few of these.
- return Trap(ReturnErrno, reinterpret_cast<void*>(ret & SECCOMP_RET_DATA),
- true);
- }
-
- return gen_.MakeInstruction(BPF_RET + BPF_K, ret);
-}
-
-CodeGen::Node PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc,
- const void* aux,
- bool safe) {
- uint16_t trap_id = registry_->Add(fnc, aux, safe);
- return gen_.MakeInstruction(BPF_RET + BPF_K, SECCOMP_RET_TRAP + trap_id);
-}
-
-bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) {
- for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) {
- if (sysno == kSyscallsRequiredForUnsafeTraps[i]) {
- return true;
- }
- }
- return false;
-}
-
-} // namespace bpf_dsl
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.h b/sandbox/linux/bpf_dsl/policy_compiler.h
deleted file mode 100644
index 48b1d780d9..0000000000
--- a/sandbox/linux/bpf_dsl/policy_compiler.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
-#define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/linux/bpf_dsl/trap_registry.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-class Policy;
-
-// PolicyCompiler implements the bpf_dsl compiler, allowing users to
-// transform bpf_dsl policies into BPF programs to be executed by the
-// Linux kernel.
-class SANDBOX_EXPORT PolicyCompiler {
- public:
- using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error);
-
- PolicyCompiler(const Policy* policy, TrapRegistry* registry);
- ~PolicyCompiler();
-
- // Compile registers any trap handlers needed by the policy and
- // compiles the policy to a BPF program, which it returns.
- CodeGen::Program Compile();
-
- // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any
- // system calls, regardless of policy.
- void DangerousSetEscapePC(uint64_t escapepc);
-
- // SetPanicFunc sets the callback function used for handling faulty
- // system call conditions. The default behavior is to immediately kill
- // the process.
- // TODO(mdempsky): Move this into Policy?
- void SetPanicFunc(PanicFunc panic_func);
-
- // UnsafeTraps require some syscalls to always be allowed.
- // This helper function returns true for these calls.
- static bool IsRequiredForUnsafeTrap(int sysno);
-
- // Functions below are meant for use within bpf_dsl itself.
-
- // Return returns a CodeGen::Node that returns the specified seccomp
- // return value.
- CodeGen::Node Return(uint32_t ret);
-
- // Trap returns a CodeGen::Node to indicate the system call should
- // instead invoke a trap handler.
- CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
-
- // MaskedEqual returns a CodeGen::Node that represents a conditional branch.
- // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
- // to "value"; if equal, then "passed" will be executed, otherwise "failed".
- // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1)
- // If it is outside this range, the sandbox treats the system call just
- // the same as any other ABI violation (i.e., it panics).
- CodeGen::Node MaskedEqual(int argno,
- size_t width,
- uint64_t mask,
- uint64_t value,
- CodeGen::Node passed,
- CodeGen::Node failed);
-
- private:
- struct Range;
- typedef std::vector<Range> Ranges;
-
- // Used by MaskedEqualHalf to track which half of the argument it's
- // emitting instructions for.
- enum class ArgHalf {
- LOWER,
- UPPER,
- };
-
- // Compile the configured policy into a complete instruction sequence.
- CodeGen::Node AssemblePolicy();
-
- // Return an instruction sequence that checks the
- // arch_seccomp_data's "arch" field is valid, and then passes
- // control to |passed| if so.
- CodeGen::Node CheckArch(CodeGen::Node passed);
-
- // If |has_unsafe_traps_| is true, returns an instruction sequence
- // that allows all system calls from |escapepc_|, and otherwise
- // passes control to |rest|. Otherwise, simply returns |rest|.
- CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
-
- // Return an instruction sequence that loads and checks the system
- // call number, performs a binary search, and then dispatches to an
- // appropriate instruction sequence compiled from the current
- // policy.
- CodeGen::Node DispatchSyscall();
-
- // Return an instruction sequence that checks the system call number
- // (expected to be loaded in register A) and if valid, passes
- // control to |passed| (with register A still valid).
- CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
-
- // Finds all the ranges of system calls that need to be handled. Ranges are
- // sorted in ascending order of system call numbers. There are no gaps in the
- // ranges. System calls with identical CodeGen::Nodes are coalesced into a
- // single
- // range.
- void FindRanges(Ranges* ranges);
-
- // Returns a BPF program snippet that implements a jump table for the
- // given range of system call numbers. This function runs recursively.
- CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
- Ranges::const_iterator stop);
-
- // CompileResult compiles an individual result expression into a
- // CodeGen node.
- CodeGen::Node CompileResult(const ResultExpr& res);
-
- // Returns a BPF program that evaluates half of a conditional expression;
- // it should only ever be called from CondExpression().
- CodeGen::Node MaskedEqualHalf(int argno,
- size_t width,
- uint64_t full_mask,
- uint64_t full_value,
- ArgHalf half,
- CodeGen::Node passed,
- CodeGen::Node failed);
-
- // Returns the fatal CodeGen::Node that is used to indicate that somebody
- // attempted to pass a 64bit value in a 32bit system call argument.
- CodeGen::Node Unexpected64bitArgument();
-
- const Policy* policy_;
- TrapRegistry* registry_;
- uint64_t escapepc_;
- PanicFunc panic_func_;
-
- CodeGen gen_;
- bool has_unsafe_traps_;
-
- DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
-};
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
deleted file mode 100644
index af70f21cd7..0000000000
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
-#define SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
-
-#include <sys/types.h> // For __BIONIC__.
-// Old Bionic versions do not have sys/user.h. The if can be removed once we no
-// longer need to support these old Bionic versions.
-// All x86_64 builds use a new enough bionic to have sys/user.h.
-#if !defined(__BIONIC__) || defined(__x86_64__)
-#if !defined(__native_client_nonsfi__)
-#include <sys/user.h>
-#endif
-#if defined(__mips__)
-// sys/user.h in eglibc misses size_t definition
-#include <stddef.h>
-#endif
-#endif
-
-#include "sandbox/linux/system_headers/linux_seccomp.h" // For AUDIT_ARCH_*
-
-// Impose some reasonable maximum BPF program size. Realistically, the
-// kernel probably has much lower limits. But by limiting to less than
-// 30 bits, we can ease requirements on some of our data types.
-#define SECCOMP_MAX_PROGRAM_SIZE (1<<30)
-
-#if defined(__i386__)
-#define SECCOMP_ARCH AUDIT_ARCH_I386
-
-#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
-#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, REG_EAX)
-#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, REG_EAX)
-#define SECCOMP_IP(_ctx) SECCOMP_REG(_ctx, REG_EIP)
-#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, REG_EBX)
-#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, REG_ECX)
-#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, REG_EDX)
-#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, REG_ESI)
-#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, REG_EDI)
-#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, REG_EBP)
-#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
-#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
-#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 4)
-#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 0)
-#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 4)
-#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 0)
-
-
-#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
-// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
-// define regs_struct directly. This can be removed once we no longer need to
-// support these old Bionic versions and PNaCl toolchain.
-struct regs_struct {
- long int ebx;
- long int ecx;
- long int edx;
- long int esi;
- long int edi;
- long int ebp;
- long int eax;
- long int xds;
- long int xes;
- long int xfs;
- long int xgs;
- long int orig_eax;
- long int eip;
- long int xcs;
- long int eflags;
- long int esp;
- long int xss;
-};
-#else
-typedef user_regs_struct regs_struct;
-#endif
-
-#define SECCOMP_PT_RESULT(_regs) (_regs).eax
-#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_eax
-#define SECCOMP_PT_IP(_regs) (_regs).eip
-#define SECCOMP_PT_PARM1(_regs) (_regs).ebx
-#define SECCOMP_PT_PARM2(_regs) (_regs).ecx
-#define SECCOMP_PT_PARM3(_regs) (_regs).edx
-#define SECCOMP_PT_PARM4(_regs) (_regs).esi
-#define SECCOMP_PT_PARM5(_regs) (_regs).edi
-#define SECCOMP_PT_PARM6(_regs) (_regs).ebp
-
-#elif defined(__x86_64__)
-#define SECCOMP_ARCH AUDIT_ARCH_X86_64
-
-#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
-#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, REG_RAX)
-#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, REG_RAX)
-#define SECCOMP_IP(_ctx) SECCOMP_REG(_ctx, REG_RIP)
-#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, REG_RDI)
-#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, REG_RSI)
-#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, REG_RDX)
-#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, REG_R10)
-#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, REG_R8)
-#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, REG_R9)
-#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
-#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
-#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 4)
-#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 0)
-#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 4)
-#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 0)
-
-typedef user_regs_struct regs_struct;
-#define SECCOMP_PT_RESULT(_regs) (_regs).rax
-#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_rax
-#define SECCOMP_PT_IP(_regs) (_regs).rip
-#define SECCOMP_PT_PARM1(_regs) (_regs).rdi
-#define SECCOMP_PT_PARM2(_regs) (_regs).rsi
-#define SECCOMP_PT_PARM3(_regs) (_regs).rdx
-#define SECCOMP_PT_PARM4(_regs) (_regs).r10
-#define SECCOMP_PT_PARM5(_regs) (_regs).r8
-#define SECCOMP_PT_PARM6(_regs) (_regs).r9
-
-#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
-#define SECCOMP_ARCH AUDIT_ARCH_ARM
-
-// ARM sigcontext_t is different from i386/x86_64.
-// See </arch/arm/include/asm/sigcontext.h> in the Linux kernel.
-#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.arm_##_reg)
-// ARM EABI syscall convention.
-#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, r0)
-#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, r7)
-#define SECCOMP_IP(_ctx) SECCOMP_REG(_ctx, pc)
-#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, r0)
-#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, r1)
-#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, r2)
-#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, r3)
-#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, r4)
-#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, r5)
-#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
-#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
-#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 4)
-#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 0)
-#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 4)
-#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 0)
-
-#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
-// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
-// define regs_struct directly. This can be removed once we no longer need to
-// support these old Bionic versions and PNaCl toolchain.
-struct regs_struct {
- unsigned long uregs[18];
-};
-#else
-typedef user_regs regs_struct;
-#endif
-
-#define REG_cpsr uregs[16]
-#define REG_pc uregs[15]
-#define REG_lr uregs[14]
-#define REG_sp uregs[13]
-#define REG_ip uregs[12]
-#define REG_fp uregs[11]
-#define REG_r10 uregs[10]
-#define REG_r9 uregs[9]
-#define REG_r8 uregs[8]
-#define REG_r7 uregs[7]
-#define REG_r6 uregs[6]
-#define REG_r5 uregs[5]
-#define REG_r4 uregs[4]
-#define REG_r3 uregs[3]
-#define REG_r2 uregs[2]
-#define REG_r1 uregs[1]
-#define REG_r0 uregs[0]
-#define REG_ORIG_r0 uregs[17]
-
-#define SECCOMP_PT_RESULT(_regs) (_regs).REG_r0
-#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_r7
-#define SECCOMP_PT_IP(_regs) (_regs).REG_pc
-#define SECCOMP_PT_PARM1(_regs) (_regs).REG_r0
-#define SECCOMP_PT_PARM2(_regs) (_regs).REG_r1
-#define SECCOMP_PT_PARM3(_regs) (_regs).REG_r2
-#define SECCOMP_PT_PARM4(_regs) (_regs).REG_r3
-#define SECCOMP_PT_PARM5(_regs) (_regs).REG_r4
-#define SECCOMP_PT_PARM6(_regs) (_regs).REG_r5
-
-#elif defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
-#define SECCOMP_ARCH AUDIT_ARCH_MIPSEL
-#define SYSCALL_EIGHT_ARGS
-// MIPS sigcontext_t is different from i386/x86_64 and ARM.
-// See </arch/mips/include/uapi/asm/sigcontext.h> in the Linux kernel.
-#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[_reg])
-// Based on MIPS o32 ABI syscall convention.
-// On MIPS, when indirect syscall is being made (syscall(__NR_foo)),
-// real identificator (__NR_foo) is not in v0, but in a0
-#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 2)
-#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 2)
-#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
-#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 4)
-#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 5)
-#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 6)
-#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 7)
-// Only the first 4 arguments of syscall are in registers.
-// The rest are on the stack.
-#define SECCOMP_STACKPARM(_ctx, n) (((long *)SECCOMP_REG(_ctx, 29))[(n)])
-#define SECCOMP_PARM5(_ctx) SECCOMP_STACKPARM(_ctx, 4)
-#define SECCOMP_PARM6(_ctx) SECCOMP_STACKPARM(_ctx, 5)
-#define SECCOMP_PARM7(_ctx) SECCOMP_STACKPARM(_ctx, 6)
-#define SECCOMP_PARM8(_ctx) SECCOMP_STACKPARM(_ctx, 7)
-#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
-#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
-#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 4)
-#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
- instruction_pointer) + 0)
-#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 4)
-#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
- 8*(nr) + 0)
-
-// On Mips we don't have structures like user_regs or user_regs_struct in
-// sys/user.h that we could use, so we just define regs_struct directly.
-struct regs_struct {
- unsigned long long regs[32];
-};
-
-#define REG_a3 regs[7]
-#define REG_a2 regs[6]
-#define REG_a1 regs[5]
-#define REG_a0 regs[4]
-#define REG_v1 regs[3]
-#define REG_v0 regs[2]
-
-#define SECCOMP_PT_RESULT(_regs) (_regs).REG_v0
-#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_v0
-#define SECCOMP_PT_PARM1(_regs) (_regs).REG_a0
-#define SECCOMP_PT_PARM2(_regs) (_regs).REG_a1
-#define SECCOMP_PT_PARM3(_regs) (_regs).REG_a2
-#define SECCOMP_PT_PARM4(_regs) (_regs).REG_a3
-
-#elif defined(__aarch64__)
-struct regs_struct {
- unsigned long long regs[31];
- unsigned long long sp;
- unsigned long long pc;
- unsigned long long pstate;
-};
-
-#define SECCOMP_ARCH AUDIT_ARCH_AARCH64
-
-#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.regs[_reg])
-
-#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 0)
-#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 8)
-#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
-#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 0)
-#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 1)
-#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 2)
-#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 3)
-#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, 4)
-#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, 5)
-
-#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
-#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
-#define SECCOMP_IP_MSB_IDX \
- (offsetof(struct arch_seccomp_data, instruction_pointer) + 4)
-#define SECCOMP_IP_LSB_IDX \
- (offsetof(struct arch_seccomp_data, instruction_pointer) + 0)
-#define SECCOMP_ARG_MSB_IDX(nr) \
- (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4)
-#define SECCOMP_ARG_LSB_IDX(nr) \
- (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0)
-
-#define SECCOMP_PT_RESULT(_regs) (_regs).regs[0]
-#define SECCOMP_PT_SYSCALL(_regs) (_regs).regs[8]
-#define SECCOMP_PT_IP(_regs) (_regs).pc
-#define SECCOMP_PT_PARM1(_regs) (_regs).regs[0]
-#define SECCOMP_PT_PARM2(_regs) (_regs).regs[1]
-#define SECCOMP_PT_PARM3(_regs) (_regs).regs[2]
-#define SECCOMP_PT_PARM4(_regs) (_regs).regs[3]
-#define SECCOMP_PT_PARM5(_regs) (_regs).regs[4]
-#define SECCOMP_PT_PARM6(_regs) (_regs).regs[5]
-#else
-#error Unsupported target platform
-
-#endif
-
-#endif // SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
diff --git a/sandbox/linux/bpf_dsl/syscall_set.cc b/sandbox/linux/bpf_dsl/syscall_set.cc
deleted file mode 100644
index 3d61fa31fd..0000000000
--- a/sandbox/linux/bpf_dsl/syscall_set.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2012 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/syscall_set.h"
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
-
-namespace sandbox {
-
-namespace {
-
-#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
-// This is true for Mips O32 ABI.
-static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000");
-#else
-// This true for supported architectures (Intel and ARM EABI).
-static_assert(MIN_SYSCALL == 0u,
- "min syscall should always be zero");
-#endif
-
-// SyscallRange represents an inclusive range of system call numbers.
-struct SyscallRange {
- uint32_t first;
- uint32_t last;
-};
-
-const SyscallRange kValidSyscallRanges[] = {
- // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL
- // on Intel architectures, but leaves room for private syscalls on ARM.
- {MIN_SYSCALL, MAX_PUBLIC_SYSCALL},
-#if defined(__arm__)
- // ARM EABI includes "ARM private" system calls starting at
- // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at
- // MIN_GHOST_SYSCALL.
- {MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL},
- {MIN_GHOST_SYSCALL, MAX_SYSCALL},
-#endif
-};
-
-} // namespace
-
-SyscallSet::Iterator SyscallSet::begin() const {
- return Iterator(set_, false);
-}
-
-SyscallSet::Iterator SyscallSet::end() const {
- return Iterator(set_, true);
-}
-
-bool SyscallSet::IsValid(uint32_t num) {
- for (const SyscallRange& range : kValidSyscallRanges) {
- if (num >= range.first && num <= range.last) {
- return true;
- }
- }
- return false;
-}
-
-bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) {
- return (lhs.set_ == rhs.set_);
-}
-
-SyscallSet::Iterator::Iterator(Set set, bool done)
- : set_(set), done_(done), num_(0) {
- // If the set doesn't contain 0, we need to skip to the next element.
- if (!done && set_ == (IsValid(num_) ? Set::INVALID_ONLY : Set::VALID_ONLY)) {
- ++*this;
- }
-}
-
-uint32_t SyscallSet::Iterator::operator*() const {
- DCHECK(!done_);
- return num_;
-}
-
-SyscallSet::Iterator& SyscallSet::Iterator::operator++() {
- DCHECK(!done_);
-
- num_ = NextSyscall();
- if (num_ == 0) {
- done_ = true;
- }
-
- return *this;
-}
-
-// NextSyscall returns the next system call in the iterated system
-// call set after |num_|, or 0 if no such system call exists.
-uint32_t SyscallSet::Iterator::NextSyscall() const {
- const bool want_valid = (set_ != Set::INVALID_ONLY);
- const bool want_invalid = (set_ != Set::VALID_ONLY);
-
- for (const SyscallRange& range : kValidSyscallRanges) {
- if (want_invalid && range.first > 0 && num_ < range.first - 1) {
- // Even when iterating invalid syscalls, we only include the end points;
- // so skip directly to just before the next (valid) range.
- return range.first - 1;
- }
- if (want_valid && num_ < range.first) {
- return range.first;
- }
- if (want_valid && num_ < range.last) {
- return num_ + 1;
- }
- if (want_invalid && num_ <= range.last) {
- return range.last + 1;
- }
- }
-
- if (want_invalid) {
- // BPF programs only ever operate on unsigned quantities. So,
- // that's how we iterate; we return values from
- // 0..0xFFFFFFFFu. But there are places, where the kernel might
- // interpret system call numbers as signed quantities, so the
- // boundaries between signed and unsigned values are potential
- // problem cases. We want to explicitly return these values from
- // our iterator.
- if (num_ < 0x7FFFFFFFu)
- return 0x7FFFFFFFu;
- if (num_ < 0x80000000u)
- return 0x80000000u;
-
- if (num_ < 0xFFFFFFFFu)
- return 0xFFFFFFFFu;
- }
-
- return 0;
-}
-
-bool operator==(const SyscallSet::Iterator& lhs,
- const SyscallSet::Iterator& rhs) {
- DCHECK(lhs.set_ == rhs.set_);
- return (lhs.done_ == rhs.done_) && (lhs.num_ == rhs.num_);
-}
-
-bool operator!=(const SyscallSet::Iterator& lhs,
- const SyscallSet::Iterator& rhs) {
- return !(lhs == rhs);
-}
-
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/syscall_set.h b/sandbox/linux/bpf_dsl/syscall_set.h
deleted file mode 100644
index b9f076d932..0000000000
--- a/sandbox/linux/bpf_dsl/syscall_set.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
-#define SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
-
-#include <stdint.h>
-
-#include <iterator>
-
-#include "base/macros.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-
-// Iterates over the entire system call range from 0..0xFFFFFFFFu. This
-// iterator is aware of how system calls look like and will skip quickly
-// over ranges that can't contain system calls. It iterates more slowly
-// whenever it reaches a range that is potentially problematic, returning
-// the last invalid value before a valid range of system calls, and the
-// first invalid value after a valid range of syscalls. It iterates over
-// individual values whenever it is in the normal range for system calls
-// (typically MIN_SYSCALL..MAX_SYSCALL).
-//
-// Example usage:
-// for (uint32_t sysnum : SyscallSet::All()) {
-// // Do something with sysnum.
-// }
-class SANDBOX_EXPORT SyscallSet {
- public:
- class Iterator;
-
- SyscallSet(const SyscallSet& ss) : set_(ss.set_) {}
- ~SyscallSet() {}
-
- Iterator begin() const;
- Iterator end() const;
-
- // All returns a SyscallSet that contains both valid and invalid
- // system call numbers.
- static SyscallSet All() { return SyscallSet(Set::ALL); }
-
- // ValidOnly returns a SyscallSet that contains only valid system
- // call numbers.
- static SyscallSet ValidOnly() { return SyscallSet(Set::VALID_ONLY); }
-
- // InvalidOnly returns a SyscallSet that contains only invalid
- // system call numbers, but still omits numbers in the middle of a
- // range of invalid system call numbers.
- static SyscallSet InvalidOnly() { return SyscallSet(Set::INVALID_ONLY); }
-
- // IsValid returns whether |num| specifies a valid system call
- // number.
- static bool IsValid(uint32_t num);
-
- private:
- enum class Set { ALL, VALID_ONLY, INVALID_ONLY };
-
- explicit SyscallSet(Set set) : set_(set) {}
-
- Set set_;
-
- friend bool operator==(const SyscallSet&, const SyscallSet&);
- DISALLOW_ASSIGN(SyscallSet);
-};
-
-SANDBOX_EXPORT bool operator==(const SyscallSet& lhs, const SyscallSet& rhs);
-
-// Iterator provides C++ input iterator semantics for traversing a
-// SyscallSet.
-class SyscallSet::Iterator
- : public std::iterator<std::input_iterator_tag, uint32_t> {
- public:
- Iterator(const Iterator& it)
- : set_(it.set_), done_(it.done_), num_(it.num_) {}
- ~Iterator() {}
-
- uint32_t operator*() const;
- Iterator& operator++();
-
- private:
- Iterator(Set set, bool done);
-
- uint32_t NextSyscall() const;
-
- Set set_;
- bool done_;
- uint32_t num_;
-
- friend SyscallSet;
- friend bool operator==(const Iterator&, const Iterator&);
- DISALLOW_ASSIGN(Iterator);
-};
-
-SANDBOX_EXPORT bool operator==(const SyscallSet::Iterator& lhs,
- const SyscallSet::Iterator& rhs);
-SANDBOX_EXPORT bool operator!=(const SyscallSet::Iterator& lhs,
- const SyscallSet::Iterator& rhs);
-
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
diff --git a/sandbox/linux/bpf_dsl/syscall_set_unittest.cc b/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
deleted file mode 100644
index 5069e8e431..0000000000
--- a/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2012 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/syscall_set.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
-#include "sandbox/linux/tests/unit_tests.h"
-
-namespace sandbox {
-
-namespace {
-
-const SyscallSet kSyscallSets[] = {
- SyscallSet::All(),
- SyscallSet::InvalidOnly(),
-};
-
-SANDBOX_TEST(SyscallSet, Monotonous) {
- for (const SyscallSet& set : kSyscallSets) {
- uint32_t prev = 0;
- bool have_prev = false;
- for (uint32_t sysnum : set) {
- if (have_prev) {
- SANDBOX_ASSERT(sysnum > prev);
- } else if (set == SyscallSet::All()) {
- // The iterator should start at 0.
- SANDBOX_ASSERT(sysnum == 0);
- }
-
- prev = sysnum;
- have_prev = true;
- }
-
- // The iterator should always return 0xFFFFFFFFu as the last value.
- SANDBOX_ASSERT(have_prev);
- SANDBOX_ASSERT(prev == 0xFFFFFFFFu);
- }
-}
-
-// AssertRange checks that SyscallIterator produces all system call
-// numbers in the inclusive range [min, max].
-void AssertRange(uint32_t min, uint32_t max) {
- SANDBOX_ASSERT(min < max);
- uint32_t prev = min - 1;
- for (uint32_t sysnum : SyscallSet::All()) {
- if (sysnum >= min && sysnum <= max) {
- SANDBOX_ASSERT(prev == sysnum - 1);
- prev = sysnum;
- }
- }
- SANDBOX_ASSERT(prev == max);
-}
-
-SANDBOX_TEST(SyscallSet, ValidSyscallRanges) {
- AssertRange(MIN_SYSCALL, MAX_PUBLIC_SYSCALL);
-#if defined(__arm__)
- AssertRange(MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL);
- AssertRange(MIN_GHOST_SYSCALL, MAX_SYSCALL);
-#endif
-}
-
-SANDBOX_TEST(SyscallSet, InvalidSyscalls) {
- static const uint32_t kExpected[] = {
-#if defined(__mips__)
- 0,
- MIN_SYSCALL - 1,
-#endif
- MAX_PUBLIC_SYSCALL + 1,
-#if defined(__arm__)
- MIN_PRIVATE_SYSCALL - 1,
- MAX_PRIVATE_SYSCALL + 1,
- MIN_GHOST_SYSCALL - 1,
- MAX_SYSCALL + 1,
-#endif
- 0x7FFFFFFFu,
- 0x80000000u,
- 0xFFFFFFFFu,
- };
-
- for (const SyscallSet& set : kSyscallSets) {
- size_t i = 0;
- for (uint32_t sysnum : set) {
- if (!SyscallSet::IsValid(sysnum)) {
- SANDBOX_ASSERT(i < arraysize(kExpected));
- SANDBOX_ASSERT(kExpected[i] == sysnum);
- ++i;
- }
- }
- SANDBOX_ASSERT(i == arraysize(kExpected));
- }
-}
-
-SANDBOX_TEST(SyscallSet, ValidOnlyIsOnlyValid) {
- for (uint32_t sysnum : SyscallSet::ValidOnly()) {
- SANDBOX_ASSERT(SyscallSet::IsValid(sysnum));
- }
-}
-
-SANDBOX_TEST(SyscallSet, InvalidOnlyIsOnlyInvalid) {
- for (uint32_t sysnum : SyscallSet::InvalidOnly()) {
- SANDBOX_ASSERT(!SyscallSet::IsValid(sysnum));
- }
-}
-
-SANDBOX_TEST(SyscallSet, AllIsValidOnlyPlusInvalidOnly) {
- std::vector<uint32_t> merged;
- const SyscallSet valid_only = SyscallSet::ValidOnly();
- const SyscallSet invalid_only = SyscallSet::InvalidOnly();
- std::merge(valid_only.begin(),
- valid_only.end(),
- invalid_only.begin(),
- invalid_only.end(),
- std::back_inserter(merged));
-
- const SyscallSet all = SyscallSet::All();
- SANDBOX_ASSERT(merged == std::vector<uint32_t>(all.begin(), all.end()));
-}
-
-} // namespace
-
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/trap_registry.h b/sandbox/linux/bpf_dsl/trap_registry.h
deleted file mode 100644
index 0a5d2f14cc..0000000000
--- a/sandbox/linux/bpf_dsl/trap_registry.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
-#define SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "sandbox/sandbox_export.h"
-
-namespace sandbox {
-
-// This must match the kernel's seccomp_data structure.
-struct arch_seccomp_data {
- int nr;
- uint32_t arch;
- uint64_t instruction_pointer;
- uint64_t args[6];
-};
-
-namespace bpf_dsl {
-
-// TrapRegistry provides an interface for registering "trap handlers"
-// by associating them with non-zero 16-bit trap IDs. Trap IDs should
-// remain valid for the lifetime of the trap registry.
-class SANDBOX_EXPORT TrapRegistry {
- public:
- // TrapFnc is a pointer to a function that fulfills the trap handler
- // function signature.
- //
- // Trap handlers follow the calling convention of native system
- // calls; e.g., to report an error, they return an exit code in the
- // range -1..-4096 instead of directly modifying errno. However,
- // modifying errno is harmless, as the original value will be
- // restored afterwards.
- //
- // Trap handlers are executed from signal context and possibly an
- // async-signal context, so they must be async-signal safe:
- // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
- typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void* aux);
-
- // Add registers the specified trap handler tuple and returns a
- // non-zero trap ID that uniquely identifies the tuple for the life
- // time of the trap registry. If the same tuple is registered
- // multiple times, the same value will be returned each time.
- virtual uint16_t Add(TrapFnc fnc, const void* aux, bool safe) = 0;
-
- // EnableUnsafeTraps tries to enable unsafe traps and returns
- // whether it was successful. This is a one-way operation.
- //
- // CAUTION: Enabling unsafe traps effectively defeats the security
- // guarantees provided by the sandbox policy. TrapRegistry
- // implementations should ensure unsafe traps are only enabled
- // during testing.
- virtual bool EnableUnsafeTraps() = 0;
-
- protected:
- TrapRegistry() {}
-
- // TrapRegistry's destructor is intentionally non-virtual so that
- // implementations can omit their destructor. Instead we protect against
- // misuse by marking it protected.
- ~TrapRegistry() {}
-
- DISALLOW_COPY_AND_ASSIGN(TrapRegistry);
-};
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
diff --git a/sandbox/linux/bpf_dsl/verifier.cc b/sandbox/linux/bpf_dsl/verifier.cc
deleted file mode 100644
index b5383e5d04..0000000000
--- a/sandbox/linux/bpf_dsl/verifier.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) 2012 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/verifier.h"
-
-#include <stdint.h>
-#include <string.h>
-
-#include "base/macros.h"
-#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-#include "sandbox/linux/bpf_dsl/trap_registry.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-#include "sandbox/linux/system_headers/linux_seccomp.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-
-namespace {
-
-struct State {
- State(const std::vector<struct sock_filter>& p,
- const struct arch_seccomp_data& d)
- : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {}
- const std::vector<struct sock_filter>& program;
- const struct arch_seccomp_data& data;
- unsigned int ip;
- uint32_t accumulator;
- bool acc_is_valid;
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(State);
-};
-
-void Ld(State* state, const struct sock_filter& insn, const char** err) {
- if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS ||
- insn.jt != 0 || insn.jf != 0) {
- *err = "Invalid BPF_LD instruction";
- return;
- }
- if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
- // We only allow loading of properly aligned 32bit quantities.
- memcpy(&state->accumulator,
- reinterpret_cast<const char*>(&state->data) + insn.k, 4);
- } else {
- *err = "Invalid operand in BPF_LD instruction";
- return;
- }
- state->acc_is_valid = true;
- return;
-}
-
-void Jmp(State* state, const struct sock_filter& insn, const char** err) {
- if (BPF_OP(insn.code) == BPF_JA) {
- if (state->ip + insn.k + 1 >= state->program.size() ||
- state->ip + insn.k + 1 <= state->ip) {
- compilation_failure:
- *err = "Invalid BPF_JMP instruction";
- return;
- }
- state->ip += insn.k;
- } else {
- if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid ||
- state->ip + insn.jt + 1 >= state->program.size() ||
- state->ip + insn.jf + 1 >= state->program.size()) {
- goto compilation_failure;
- }
- switch (BPF_OP(insn.code)) {
- case BPF_JEQ:
- if (state->accumulator == insn.k) {
- state->ip += insn.jt;
- } else {
- state->ip += insn.jf;
- }
- break;
- case BPF_JGT:
- if (state->accumulator > insn.k) {
- state->ip += insn.jt;
- } else {
- state->ip += insn.jf;
- }
- break;
- case BPF_JGE:
- if (state->accumulator >= insn.k) {
- state->ip += insn.jt;
- } else {
- state->ip += insn.jf;
- }
- break;
- case BPF_JSET:
- if (state->accumulator & insn.k) {
- state->ip += insn.jt;
- } else {
- state->ip += insn.jf;
- }
- break;
- default:
- goto compilation_failure;
- }
- }
-}
-
-uint32_t Ret(State*, const struct sock_filter& insn, const char** err) {
- if (BPF_SRC(insn.code) != BPF_K) {
- *err = "Invalid BPF_RET instruction";
- return 0;
- }
- return insn.k;
-}
-
-void Alu(State* state, const struct sock_filter& insn, const char** err) {
- if (BPF_OP(insn.code) == BPF_NEG) {
- state->accumulator = -state->accumulator;
- return;
- } else {
- if (BPF_SRC(insn.code) != BPF_K) {
- *err = "Unexpected source operand in arithmetic operation";
- return;
- }
- switch (BPF_OP(insn.code)) {
- case BPF_ADD:
- state->accumulator += insn.k;
- break;
- case BPF_SUB:
- state->accumulator -= insn.k;
- break;
- case BPF_MUL:
- state->accumulator *= insn.k;
- break;
- case BPF_DIV:
- if (!insn.k) {
- *err = "Illegal division by zero";
- break;
- }
- state->accumulator /= insn.k;
- break;
- case BPF_MOD:
- if (!insn.k) {
- *err = "Illegal division by zero";
- break;
- }
- state->accumulator %= insn.k;
- break;
- case BPF_OR:
- state->accumulator |= insn.k;
- break;
- case BPF_XOR:
- state->accumulator ^= insn.k;
- break;
- case BPF_AND:
- state->accumulator &= insn.k;
- break;
- case BPF_LSH:
- if (insn.k > 32) {
- *err = "Illegal shift operation";
- break;
- }
- state->accumulator <<= insn.k;
- break;
- case BPF_RSH:
- if (insn.k > 32) {
- *err = "Illegal shift operation";
- break;
- }
- state->accumulator >>= insn.k;
- break;
- default:
- *err = "Invalid operator in arithmetic operation";
- break;
- }
- }
-}
-
-} // namespace
-
-uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
- const struct arch_seccomp_data& data,
- const char** err) {
- *err = NULL;
- if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
- *err = "Invalid program length";
- return 0;
- }
- for (State state(program, data); !*err; ++state.ip) {
- if (state.ip >= program.size()) {
- *err = "Invalid instruction pointer in BPF program";
- break;
- }
- const struct sock_filter& insn = program[state.ip];
- switch (BPF_CLASS(insn.code)) {
- case BPF_LD:
- Ld(&state, insn, err);
- break;
- case BPF_JMP:
- Jmp(&state, insn, err);
- break;
- case BPF_RET: {
- uint32_t r = Ret(&state, insn, err);
- switch (r & SECCOMP_RET_ACTION) {
- case SECCOMP_RET_ALLOW:
- case SECCOMP_RET_ERRNO:
- case SECCOMP_RET_KILL:
- case SECCOMP_RET_TRACE:
- case SECCOMP_RET_TRAP:
- break;
- case SECCOMP_RET_INVALID: // Should never show up in BPF program
- default:
- *err = "Unexpected return code found in BPF program";
- return 0;
- }
- return r;
- }
- case BPF_ALU:
- Alu(&state, insn, err);
- break;
- default:
- *err = "Unexpected instruction in BPF program";
- break;
- }
- }
- return 0;
-}
-
-} // namespace bpf_dsl
-} // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/verifier.h b/sandbox/linux/bpf_dsl/verifier.h
deleted file mode 100644
index 9b25ab1d71..0000000000
--- a/sandbox/linux/bpf_dsl/verifier.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012 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.
-
-#ifndef SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
-#define SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/macros.h"
-#include "sandbox/sandbox_export.h"
-
-struct sock_filter;
-
-namespace sandbox {
-struct arch_seccomp_data;
-
-namespace bpf_dsl {
-
-// TODO(mdempsky): This class doesn't perform any verification any more, so it
-// deserves a new name.
-class SANDBOX_EXPORT Verifier {
- public:
- // Evaluate a given BPF program for a particular set of system call
- // parameters. If evaluation failed for any reason, "err" will be set to
- // a non-NULL error string. Otherwise, the BPF program's result will be
- // returned by the function and "err" is NULL.
- // We do not actually implement the full BPF state machine, but only the
- // parts that can actually be generated by our BPF compiler. If this code
- // is used for purposes other than verifying the output of the sandbox's
- // BPF compiler, we might have to extend this BPF interpreter.
- static uint32_t EvaluateBPF(const std::vector<struct sock_filter>& program,
- const struct arch_seccomp_data& data,
- const char** err);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(Verifier);
-};
-
-} // namespace bpf_dsl
-} // namespace sandbox
-
-#endif // SANDBOX_LINUX_BPF_DSL_VERIFIER_H__