| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ | 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
| 6 #define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ | 6 #define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
| 7 | 7 |
| 8 #include <stddef.h> |
| 8 #include <stdint.h> | 9 #include <stdint.h> |
| 9 | 10 |
| 10 #include <map> | 11 #include <map> |
| 11 #include <vector> | 12 #include <vector> |
| 12 | 13 |
| 14 #include "base/macros.h" |
| 15 #include "base/tuple.h" |
| 13 #include "sandbox/sandbox_export.h" | 16 #include "sandbox/sandbox_export.h" |
| 14 | 17 |
| 15 struct sock_filter; | 18 struct sock_filter; |
| 16 | 19 |
| 17 namespace sandbox { | 20 namespace sandbox { |
| 18 struct BasicBlock; | |
| 19 struct Instruction; | |
| 20 | |
| 21 typedef std::vector<Instruction*> Instructions; | |
| 22 typedef std::vector<BasicBlock*> BasicBlocks; | |
| 23 typedef std::map<const Instruction*, int> BranchTargets; | |
| 24 typedef std::map<const Instruction*, BasicBlock*> TargetsToBlocks; | |
| 25 typedef std::map<const BasicBlock*, int> IncomingBranches; | |
| 26 | 21 |
| 27 // The code generator instantiates a basic compiler that can convert a | 22 // The code generator instantiates a basic compiler that can convert a |
| 28 // graph of BPF instructions into a well-formed stream of BPF instructions. | 23 // graph of BPF instructions into a well-formed stream of BPF instructions. |
| 29 // Most notably, it ensures that jumps are always forward and don't exceed | 24 // Most notably, it ensures that jumps are always forward and don't exceed |
| 30 // the limit of 255 instructions imposed by the instruction set. | 25 // the limit of 255 instructions imposed by the instruction set. |
| 31 // | 26 // |
| 32 // Callers would typically create a new CodeGen object and then use it to | 27 // Callers would typically create a new CodeGen object and then use it to |
| 33 // build a DAG of Instructions. They'll eventually call Compile() to convert | 28 // build a DAG of Instructions. They'll eventually call Compile() to convert |
| 34 // this DAG to a Program. | 29 // this DAG to a Program. |
| 35 // | 30 // |
| (...skipping 19 matching lines...) Expand all Loading... |
| 55 // prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | 50 // prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); |
| 56 // | 51 // |
| 57 class SANDBOX_EXPORT CodeGen { | 52 class SANDBOX_EXPORT CodeGen { |
| 58 public: | 53 public: |
| 59 // A vector of BPF instructions that need to be installed as a filter | 54 // A vector of BPF instructions that need to be installed as a filter |
| 60 // program in the kernel. | 55 // program in the kernel. |
| 61 typedef std::vector<struct sock_filter> Program; | 56 typedef std::vector<struct sock_filter> Program; |
| 62 | 57 |
| 63 // Addr represents a logical location within the program being compiled. | 58 // Addr represents a logical location within the program being compiled. |
| 64 // Identical code suffixes may be collapsed to a single location. | 59 // Identical code suffixes may be collapsed to a single location. |
| 65 using Addr = Instruction*; | 60 using Addr = Program::size_type; |
| 66 | 61 |
| 67 // kNullAddr represents the "null" address value; i.e., the reserved | 62 // kNullAddr represents the "null" address value; i.e., the reserved |
| 68 // address value guaranteed to not equal any actual address values. | 63 // address value guaranteed to not equal any actual address values. |
| 69 static const Addr kNullAddr; | 64 static const Addr kNullAddr = -1; |
| 70 | 65 |
| 71 CodeGen(); | 66 CodeGen(); |
| 72 ~CodeGen(); | 67 ~CodeGen(); |
| 73 | 68 |
| 74 // Create a new instruction. Instructions form a DAG. The instruction objects | 69 // MakeInstruction creates a new node in the instruction DAG and |
| 75 // are owned by the CodeGen object. They do not need to be explicitly | 70 // returns the node's address, or returns the address of an existing |
| 76 // deleted. | 71 // equivalent node if one exists. |
| 72 // |
| 77 // For details on the possible parameters refer to <linux/filter.h> | 73 // For details on the possible parameters refer to <linux/filter.h> |
| 74 // Note: Callers need not worry about explicitly creating "jump |
| 75 // always" instructions (i.e., BPF_JMP+BPF_JA), as CodeGen inserts |
| 76 // these as needed. |
| 78 Addr MakeInstruction(uint16_t code, | 77 Addr MakeInstruction(uint16_t code, |
| 79 uint32_t k, | 78 uint32_t k, |
| 80 Addr jt = kNullAddr, | 79 Addr jt = kNullAddr, |
| 81 Addr jf = kNullAddr); | 80 Addr jf = kNullAddr); |
| 82 | 81 |
| 83 // Compiles the graph of instructions into a BPF program that can be passed | 82 // Compile linearizes the instruction DAG into an equivalent flat |
| 84 // to the kernel. Please note that this function modifies the graph in place | 83 // BPF program that can be passed to the kernel. |
| 85 // and must therefore only be called once per graph. | 84 void Compile(Addr instructions, Program* program); |
| 86 void Compile(Addr head, Program* program); | |
| 87 | 85 |
| 88 private: | 86 private: |
| 89 friend class CodeGenUnittestHelper; | 87 using CacheKey = Tuple4<uint16_t, uint32_t, Addr, Addr>; |
| 88 struct CacheKeyLess { |
| 89 bool operator()(const CacheKey& lhs, const CacheKey& rhs) const; |
| 90 }; |
| 90 | 91 |
| 91 // Find all the instructions that are the target of BPF_JMPs. | 92 // Offset returns how many instructions exist in |program_| after |target|. |
| 92 void FindBranchTargets(const Instruction& instructions, | 93 size_t Offset(Addr target) const; |
| 93 BranchTargets* branch_targets); | |
| 94 | 94 |
| 95 // Combine instructions between "head" and "tail" into a new basic block. | 95 // Jump appends a jump-always instruction. |
| 96 // Basic blocks are defined as sequences of instructions whose only branch | 96 Addr Jump(Addr next); |
| 97 // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET | |
| 98 // instruction must be at the very end of the basic block. | |
| 99 BasicBlock* MakeBasicBlock(Instruction* head, Instruction* tail); | |
| 100 | 97 |
| 101 // Creates a basic block and adds it to "basic_blocks"; sets "first_block" | 98 // Append adds a new instruction to the end of |program_|. |
| 102 // if it is still NULL. | 99 Addr Append(uint16_t code, uint32_t k, size_t jt, size_t jf); |
| 103 void AddBasicBlock(Instruction* head, | |
| 104 Instruction* tail, | |
| 105 const BranchTargets& branch_targets, | |
| 106 TargetsToBlocks* basic_blocks, | |
| 107 BasicBlock** first_block); | |
| 108 | 100 |
| 109 // Cuts the DAG of instructions into basic blocks. | 101 void CheckValid(Addr addr) const; |
| 110 BasicBlock* CutGraphIntoBasicBlocks(Instruction* instructions, | |
| 111 const BranchTargets& branch_targets, | |
| 112 TargetsToBlocks* blocks); | |
| 113 | 102 |
| 114 // Find common tail sequences of basic blocks and coalesce them. | 103 // NOTE: program_ is the compiled program in *reverse*. |
| 115 void MergeTails(TargetsToBlocks* blocks); | 104 Program program_; |
| 116 | 105 |
| 117 // For each basic block, compute the number of incoming branches. | 106 std::map<CacheKey, Addr, CacheKeyLess> cache_; |
| 118 void ComputeIncomingBranches(BasicBlock* block, | |
| 119 const TargetsToBlocks& targets_to_blocks, | |
| 120 IncomingBranches* incoming_branches); | |
| 121 | 107 |
| 122 // Topologically sort the basic blocks so that all jumps are forward jumps. | 108 DISALLOW_COPY_AND_ASSIGN(CodeGen); |
| 123 // This is a requirement for any well-formed BPF program. | |
| 124 void TopoSortBasicBlocks(BasicBlock* first_block, | |
| 125 const TargetsToBlocks& blocks, | |
| 126 BasicBlocks* basic_blocks); | |
| 127 | |
| 128 // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid | |
| 129 // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being | |
| 130 // inserted, if we need to jump over more than 256 instructions. | |
| 131 void ComputeRelativeJumps(BasicBlocks* basic_blocks, | |
| 132 const TargetsToBlocks& targets_to_blocks); | |
| 133 | |
| 134 // Concatenate instructions from all basic blocks into a BPF program that | |
| 135 // can be passed to the kernel. | |
| 136 void ConcatenateBasicBlocks(const BasicBlocks&, Program* program); | |
| 137 | |
| 138 // We stick all instructions and basic blocks into pools that get destroyed | |
| 139 // when the CodeGen object is destroyed. This way, we neither need to worry | |
| 140 // about explicitly managing ownership, nor do we need to worry about using | |
| 141 // smart pointers in the presence of circular references. | |
| 142 Instructions instructions_; | |
| 143 BasicBlocks basic_blocks_; | |
| 144 | |
| 145 // Compile() must only ever be called once as it makes destructive changes | |
| 146 // to the DAG. | |
| 147 bool compiled_; | |
| 148 }; | 109 }; |
| 149 | 110 |
| 150 } // namespace sandbox | 111 } // namespace sandbox |
| 151 | 112 |
| 152 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ | 113 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
| OLD | NEW |