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