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 |