// 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 #include #include #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 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_