Chromium Code Reviews| 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 implements a basic assembler that can convert a | 22 // The code generator implements a basic assembler that can convert a |
| 28 // graph of BPF instructions into a well-formed array of BPF | 23 // graph of BPF instructions into a well-formed array of BPF |
| 29 // instructions. Most notably, it ensures that jumps are always | 24 // instructions. Most notably, it ensures that jumps are always |
| 30 // forward and don't exceed the limit of 255 instructions imposed by | 25 // forward and don't exceed the limit of 255 instructions imposed by |
| 31 // the instruction set. | 26 // the instruction set. |
| 32 // | 27 // |
| 33 // Callers would typically create a new CodeGen object and then use it | 28 // Callers would typically create a new CodeGen object and then use it |
| 34 // to build a DAG of instruction nodes. They'll eventually call | 29 // to build a DAG of instruction nodes. They'll eventually call |
| 35 // Compile() to convert this DAG to a Program. | 30 // Compile() to convert this DAG to a Program. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 57 // | 52 // |
| 58 class SANDBOX_EXPORT CodeGen { | 53 class SANDBOX_EXPORT CodeGen { |
| 59 public: | 54 public: |
| 60 // A vector of BPF instructions that need to be installed as a filter | 55 // A vector of BPF instructions that need to be installed as a filter |
| 61 // program in the kernel. | 56 // program in the kernel. |
| 62 typedef std::vector<struct sock_filter> Program; | 57 typedef std::vector<struct sock_filter> Program; |
| 63 | 58 |
| 64 // Node represents a node within the instruction DAG being compiled. | 59 // Node represents a node within the instruction DAG being compiled. |
| 65 // Nodes are owned by the CodeGen object and need not be explicitly | 60 // Nodes are owned by the CodeGen object and need not be explicitly |
| 66 // deleted. | 61 // deleted. |
| 67 using Node = Instruction*; | 62 using Node = Program::size_type; |
| 68 | 63 |
| 69 // kNullNode represents the "null" node; i.e., the reserved node | 64 // kNullNode represents the "null" node; i.e., the reserved node |
| 70 // value guaranteed to not equal any actual nodes. | 65 // value guaranteed to not equal any actual nodes. |
| 71 static const Node kNullNode; | 66 static const Node kNullNode = -1; |
| 72 | 67 |
| 73 CodeGen(); | 68 CodeGen(); |
| 74 ~CodeGen(); | 69 ~CodeGen(); |
| 75 | 70 |
| 76 // MakeInstruction creates a node representing the specified | 71 // MakeInstruction creates a node representing the specified |
| 77 // instruction. For details on the possible parameters refer to | 72 // instruction, or returns and existing equivalent node if one |
| 73 // exists. For details on the possible parameters refer to | |
| 78 // https://www.kernel.org/doc/Documentation/networking/filter.txt. | 74 // https://www.kernel.org/doc/Documentation/networking/filter.txt. |
| 79 // TODO(mdempsky): Reconsider using default arguments here. | 75 // TODO(mdempsky): Reconsider using default arguments here. |
| 80 Node MakeInstruction(uint16_t code, | 76 Node MakeInstruction(uint16_t code, |
| 81 uint32_t k, | 77 uint32_t k, |
| 82 Node jt = kNullNode, | 78 Node jt = kNullNode, |
| 83 Node jf = kNullNode); | 79 Node jf = kNullNode); |
| 84 | 80 |
| 85 // Compile linearizes the instruction DAG into a BPF program that | 81 // Compile linearizes the instruction DAG into a BPF program that |
| 86 // can be executed by a BPF virtual machine. Please note that this | 82 // can be executed by a BPF virtual machine. Please note that this |
| 87 // function modifies the graph in place and must therefore only be | 83 // function modifies the graph in place and must therefore only be |
| 88 // called once per graph. | 84 // called once per graph. |
| 89 void Compile(Node head, Program* program); | 85 void Compile(Node head, Program* program); |
| 90 | 86 |
| 91 private: | 87 private: |
| 92 friend class CodeGenUnittestHelper; | 88 using CacheKey = Tuple4<uint16_t, uint32_t, Node, Node>; |
| 89 struct CacheKeyLess { | |
| 90 bool operator()(const CacheKey& lhs, const CacheKey& rhs) const; | |
| 91 }; | |
| 93 | 92 |
| 94 // Find all the instructions that are the target of BPF_JMPs. | 93 // Offset returns how many instructions exist in |program_| after |target|. |
| 95 void FindBranchTargets(const Instruction& instructions, | 94 size_t Offset(Node target) const; |
| 96 BranchTargets* branch_targets); | |
| 97 | 95 |
| 98 // Combine instructions between "head" and "tail" into a new basic block. | 96 // Jump appends a jump-always instruction. |
| 99 // Basic blocks are defined as sequences of instructions whose only branch | 97 Node Jump(Node next); |
| 100 // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET | |
| 101 // instruction must be at the very end of the basic block. | |
| 102 BasicBlock* MakeBasicBlock(Instruction* head, Instruction* tail); | |
| 103 | 98 |
| 104 // Creates a basic block and adds it to "basic_blocks"; sets "first_block" | 99 // Append adds a new instruction to the end of |program_|. |
|
jln (very slow on Chromium)
2014/11/19 00:32:05
I would further clarify what "Appends" mean: since
mdempsky
2014/11/19 03:05:23
Done.
| |
| 105 // if it is still NULL. | 100 Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf); |
| 106 void AddBasicBlock(Instruction* head, | |
| 107 Instruction* tail, | |
| 108 const BranchTargets& branch_targets, | |
| 109 TargetsToBlocks* basic_blocks, | |
| 110 BasicBlock** first_block); | |
| 111 | 101 |
| 112 // Cuts the DAG of instructions into basic blocks. | 102 void CheckValid(Node addr) const; |
| 113 BasicBlock* CutGraphIntoBasicBlocks(Instruction* instructions, | |
| 114 const BranchTargets& branch_targets, | |
| 115 TargetsToBlocks* blocks); | |
| 116 | 103 |
| 117 // Find common tail sequences of basic blocks and coalesce them. | 104 // NOTE: program_ is the compiled program in *reverse*. |
| 118 void MergeTails(TargetsToBlocks* blocks); | 105 Program program_; |
| 119 | 106 |
| 120 // For each basic block, compute the number of incoming branches. | 107 std::map<CacheKey, Node, CacheKeyLess> cache_; |
| 121 void ComputeIncomingBranches(BasicBlock* block, | |
| 122 const TargetsToBlocks& targets_to_blocks, | |
| 123 IncomingBranches* incoming_branches); | |
| 124 | 108 |
| 125 // Topologically sort the basic blocks so that all jumps are forward jumps. | 109 DISALLOW_COPY_AND_ASSIGN(CodeGen); |
| 126 // This is a requirement for any well-formed BPF program. | |
| 127 void TopoSortBasicBlocks(BasicBlock* first_block, | |
| 128 const TargetsToBlocks& blocks, | |
| 129 BasicBlocks* basic_blocks); | |
| 130 | |
| 131 // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid | |
| 132 // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being | |
| 133 // inserted, if we need to jump over more than 256 instructions. | |
| 134 void ComputeRelativeJumps(BasicBlocks* basic_blocks, | |
| 135 const TargetsToBlocks& targets_to_blocks); | |
| 136 | |
| 137 // Concatenate instructions from all basic blocks into a BPF program that | |
| 138 // can be passed to the kernel. | |
| 139 void ConcatenateBasicBlocks(const BasicBlocks&, Program* program); | |
| 140 | |
| 141 // We stick all instructions and basic blocks into pools that get destroyed | |
| 142 // when the CodeGen object is destroyed. This way, we neither need to worry | |
| 143 // about explicitly managing ownership, nor do we need to worry about using | |
| 144 // smart pointers in the presence of circular references. | |
| 145 Instructions instructions_; | |
| 146 BasicBlocks basic_blocks_; | |
| 147 | |
| 148 // Compile() must only ever be called once as it makes destructive changes | |
| 149 // to the DAG. | |
| 150 bool compiled_; | |
| 151 }; | 110 }; |
| 152 | 111 |
| 153 } // namespace sandbox | 112 } // namespace sandbox |
| 154 | 113 |
| 155 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ | 114 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
| OLD | NEW |