1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_ 6 #define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <vector> 12 13 #include "base/macros.h" 14 #include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h" 15 #include "sandbox/linux/bpf_dsl/codegen.h" 16 #include "sandbox/linux/bpf_dsl/trap_registry.h" 17 #include "sandbox/sandbox_export.h" 18 19 namespace sandbox { 20 namespace bpf_dsl { 21 class Policy; 22 23 // PolicyCompiler implements the bpf_dsl compiler, allowing users to 24 // transform bpf_dsl policies into BPF programs to be executed by the 25 // Linux kernel. 26 class SANDBOX_EXPORT PolicyCompiler { 27 public: 28 using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error); 29 30 PolicyCompiler(const Policy* policy, TrapRegistry* registry); 31 ~PolicyCompiler(); 32 33 // Compile registers any trap handlers needed by the policy and 34 // compiles the policy to a BPF program, which it returns. 35 CodeGen::Program Compile(); 36 37 // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any 38 // system calls, regardless of policy. 39 void DangerousSetEscapePC(uint64_t escapepc); 40 41 // SetPanicFunc sets the callback function used for handling faulty 42 // system call conditions. The default behavior is to immediately kill 43 // the process. 44 // TODO(mdempsky): Move this into Policy? 45 void SetPanicFunc(PanicFunc panic_func); 46 47 // UnsafeTraps require some syscalls to always be allowed. 48 // This helper function returns true for these calls. 49 static bool IsRequiredForUnsafeTrap(int sysno); 50 51 // Functions below are meant for use within bpf_dsl itself. 52 53 // Return returns a CodeGen::Node that returns the specified seccomp 54 // return value. 55 CodeGen::Node Return(uint32_t ret); 56 57 // Trap returns a CodeGen::Node to indicate the system call should 58 // instead invoke a trap handler. 59 CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe); 60 61 // MaskedEqual returns a CodeGen::Node that represents a conditional branch. 62 // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared 63 // to "value"; if equal, then "passed" will be executed, otherwise "failed". 64 // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1) 65 // If it is outside this range, the sandbox treats the system call just 66 // the same as any other ABI violation (i.e., it panics). 67 CodeGen::Node MaskedEqual(int argno, 68 size_t width, 69 uint64_t mask, 70 uint64_t value, 71 CodeGen::Node passed, 72 CodeGen::Node failed); 73 74 private: 75 struct Range; 76 typedef std::vector<Range> Ranges; 77 78 // Used by MaskedEqualHalf to track which half of the argument it's 79 // emitting instructions for. 80 enum class ArgHalf { 81 LOWER, 82 UPPER, 83 }; 84 85 // Compile the configured policy into a complete instruction sequence. 86 CodeGen::Node AssemblePolicy(); 87 88 // Return an instruction sequence that checks the 89 // arch_seccomp_data's "arch" field is valid, and then passes 90 // control to |passed| if so. 91 CodeGen::Node CheckArch(CodeGen::Node passed); 92 93 // If |has_unsafe_traps_| is true, returns an instruction sequence 94 // that allows all system calls from |escapepc_|, and otherwise 95 // passes control to |rest|. Otherwise, simply returns |rest|. 96 CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest); 97 98 // Return an instruction sequence that loads and checks the system 99 // call number, performs a binary search, and then dispatches to an 100 // appropriate instruction sequence compiled from the current 101 // policy. 102 CodeGen::Node DispatchSyscall(); 103 104 // Return an instruction sequence that checks the system call number 105 // (expected to be loaded in register A) and if valid, passes 106 // control to |passed| (with register A still valid). 107 CodeGen::Node CheckSyscallNumber(CodeGen::Node passed); 108 109 // Finds all the ranges of system calls that need to be handled. Ranges are 110 // sorted in ascending order of system call numbers. There are no gaps in the 111 // ranges. System calls with identical CodeGen::Nodes are coalesced into a 112 // single 113 // range. 114 void FindRanges(Ranges* ranges); 115 116 // Returns a BPF program snippet that implements a jump table for the 117 // given range of system call numbers. This function runs recursively. 118 CodeGen::Node AssembleJumpTable(Ranges::const_iterator start, 119 Ranges::const_iterator stop); 120 121 // CompileResult compiles an individual result expression into a 122 // CodeGen node. 123 CodeGen::Node CompileResult(const ResultExpr& res); 124 125 // Returns a BPF program that evaluates half of a conditional expression; 126 // it should only ever be called from CondExpression(). 127 CodeGen::Node MaskedEqualHalf(int argno, 128 size_t width, 129 uint64_t full_mask, 130 uint64_t full_value, 131 ArgHalf half, 132 CodeGen::Node passed, 133 CodeGen::Node failed); 134 135 // Returns the fatal CodeGen::Node that is used to indicate that somebody 136 // attempted to pass a 64bit value in a 32bit system call argument. 137 CodeGen::Node Unexpected64bitArgument(); 138 139 const Policy* policy_; 140 TrapRegistry* registry_; 141 uint64_t escapepc_; 142 PanicFunc panic_func_; 143 144 CodeGen gen_; 145 bool has_unsafe_traps_; 146 147 DISALLOW_COPY_AND_ASSIGN(PolicyCompiler); 148 }; 149 150 } // namespace bpf_dsl 151 } // namespace sandbox 152 153 #endif // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_ 154