OLD | NEW |
(Empty) | |
| 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_SECCOMP_BPF_CODEGEN_H__ |
| 6 #define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
| 7 |
| 8 #include <stdint.h> |
| 9 |
| 10 #include <map> |
| 11 #include <vector> |
| 12 |
| 13 #include "sandbox/sandbox_export.h" |
| 14 |
| 15 struct sock_filter; |
| 16 |
| 17 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 |
| 27 // The code generator instantiates a basic compiler that can convert a |
| 28 // 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 |
| 30 // the limit of 255 instructions imposed by the instruction set. |
| 31 // |
| 32 // 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 |
| 34 // this DAG to a Program. |
| 35 // |
| 36 // CodeGen gen; |
| 37 // Instruction *allow, *branch, *dag; |
| 38 // |
| 39 // allow = |
| 40 // gen.MakeInstruction(BPF_RET+BPF_K, |
| 41 // ErrorCode(ErrorCode::ERR_ALLOWED).err())); |
| 42 // branch = |
| 43 // gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid, |
| 44 // Trap(GetPidHandler, NULL), allow); |
| 45 // dag = |
| 46 // gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS, |
| 47 // offsetof(struct arch_seccomp_data, nr), branch); |
| 48 // |
| 49 // // Simplified code follows; in practice, it is important to avoid calling |
| 50 // // any C++ destructors after starting the sandbox. |
| 51 // CodeGen::Program program; |
| 52 // gen.Compile(dag, program); |
| 53 // const struct sock_fprog prog = { |
| 54 // static_cast<unsigned short>(program->size()), &program[0] }; |
| 55 // prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); |
| 56 // |
| 57 class SANDBOX_EXPORT CodeGen { |
| 58 public: |
| 59 // A vector of BPF instructions that need to be installed as a filter |
| 60 // program in the kernel. |
| 61 typedef std::vector<struct sock_filter> Program; |
| 62 |
| 63 CodeGen(); |
| 64 ~CodeGen(); |
| 65 |
| 66 // This is a helper method that can be used for debugging purposes. It is |
| 67 // not normally called. |
| 68 static void PrintProgram(const Program& program); |
| 69 |
| 70 // Create a new instruction. Instructions form a DAG. The instruction objects |
| 71 // are owned by the CodeGen object. They do not need to be explicitly |
| 72 // deleted. |
| 73 // For details on the possible parameters refer to <linux/filter.h> |
| 74 Instruction* MakeInstruction(uint16_t code, |
| 75 uint32_t k, |
| 76 Instruction* next = nullptr); |
| 77 Instruction* MakeInstruction(uint16_t code, |
| 78 uint32_t k, |
| 79 Instruction* jt, |
| 80 Instruction* jf); |
| 81 |
| 82 // Compiles the graph of instructions into a BPF program that can be passed |
| 83 // to the kernel. Please note that this function modifies the graph in place |
| 84 // and must therefore only be called once per graph. |
| 85 void Compile(Instruction* instructions, Program* program); |
| 86 |
| 87 private: |
| 88 friend class CodeGenUnittestHelper; |
| 89 |
| 90 // Find all the instructions that are the target of BPF_JMPs. |
| 91 void FindBranchTargets(const Instruction& instructions, |
| 92 BranchTargets* branch_targets); |
| 93 |
| 94 // Combine instructions between "head" and "tail" into a new basic block. |
| 95 // Basic blocks are defined as sequences of instructions whose only branch |
| 96 // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET |
| 97 // instruction must be at the very end of the basic block. |
| 98 BasicBlock* MakeBasicBlock(Instruction* head, Instruction* tail); |
| 99 |
| 100 // Creates a basic block and adds it to "basic_blocks"; sets "first_block" |
| 101 // if it is still NULL. |
| 102 void AddBasicBlock(Instruction* head, |
| 103 Instruction* tail, |
| 104 const BranchTargets& branch_targets, |
| 105 TargetsToBlocks* basic_blocks, |
| 106 BasicBlock** first_block); |
| 107 |
| 108 // Cuts the DAG of instructions into basic blocks. |
| 109 BasicBlock* CutGraphIntoBasicBlocks(Instruction* instructions, |
| 110 const BranchTargets& branch_targets, |
| 111 TargetsToBlocks* blocks); |
| 112 |
| 113 // Find common tail sequences of basic blocks and coalesce them. |
| 114 void MergeTails(TargetsToBlocks* blocks); |
| 115 |
| 116 // For each basic block, compute the number of incoming branches. |
| 117 void ComputeIncomingBranches(BasicBlock* block, |
| 118 const TargetsToBlocks& targets_to_blocks, |
| 119 IncomingBranches* incoming_branches); |
| 120 |
| 121 // Topologically sort the basic blocks so that all jumps are forward jumps. |
| 122 // This is a requirement for any well-formed BPF program. |
| 123 void TopoSortBasicBlocks(BasicBlock* first_block, |
| 124 const TargetsToBlocks& blocks, |
| 125 BasicBlocks* basic_blocks); |
| 126 |
| 127 // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid |
| 128 // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being |
| 129 // inserted, if we need to jump over more than 256 instructions. |
| 130 void ComputeRelativeJumps(BasicBlocks* basic_blocks, |
| 131 const TargetsToBlocks& targets_to_blocks); |
| 132 |
| 133 // Concatenate instructions from all basic blocks into a BPF program that |
| 134 // can be passed to the kernel. |
| 135 void ConcatenateBasicBlocks(const BasicBlocks&, Program* program); |
| 136 |
| 137 // We stick all instructions and basic blocks into pools that get destroyed |
| 138 // when the CodeGen object is destroyed. This way, we neither need to worry |
| 139 // about explicitly managing ownership, nor do we need to worry about using |
| 140 // smart pointers in the presence of circular references. |
| 141 Instructions instructions_; |
| 142 BasicBlocks basic_blocks_; |
| 143 |
| 144 // Compile() must only ever be called once as it makes destructive changes |
| 145 // to the DAG. |
| 146 bool compiled_; |
| 147 }; |
| 148 |
| 149 } // namespace sandbox |
| 150 |
| 151 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
OLD | NEW |