Index: sandbox/linux/seccomp-bpf/codegen.h |
diff --git a/sandbox/linux/seccomp-bpf/codegen.h b/sandbox/linux/seccomp-bpf/codegen.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..817b17cbfadf3331a975a0544c4da986086a5d89 |
--- /dev/null |
+++ b/sandbox/linux/seccomp-bpf/codegen.h |
@@ -0,0 +1,151 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
+#define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |
+ |
+#include <stdint.h> |
+ |
+#include <map> |
+#include <vector> |
+ |
+#include "sandbox/sandbox_export.h" |
+ |
+struct sock_filter; |
+ |
+namespace sandbox { |
+struct BasicBlock; |
+struct Instruction; |
+ |
+typedef std::vector<Instruction*> Instructions; |
+typedef std::vector<BasicBlock*> BasicBlocks; |
+typedef std::map<const Instruction*, int> BranchTargets; |
+typedef std::map<const Instruction*, BasicBlock*> TargetsToBlocks; |
+typedef std::map<const BasicBlock*, int> IncomingBranches; |
+ |
+// The code generator instantiates a basic compiler that can convert a |
+// graph of BPF instructions into a well-formed stream of BPF instructions. |
+// Most notably, it ensures that jumps are always forward and don't exceed |
+// the limit of 255 instructions imposed by the instruction set. |
+// |
+// Callers would typically create a new CodeGen object and then use it to |
+// build a DAG of Instructions. They'll eventually call Compile() to convert |
+// this DAG to a Program. |
+// |
+// CodeGen gen; |
+// Instruction *allow, *branch, *dag; |
+// |
+// allow = |
+// gen.MakeInstruction(BPF_RET+BPF_K, |
+// ErrorCode(ErrorCode::ERR_ALLOWED).err())); |
+// branch = |
+// gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid, |
+// Trap(GetPidHandler, NULL), allow); |
+// dag = |
+// gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS, |
+// offsetof(struct arch_seccomp_data, nr), branch); |
+// |
+// // Simplified code follows; in practice, it is important to avoid calling |
+// // any C++ destructors after starting the sandbox. |
+// CodeGen::Program program; |
+// gen.Compile(dag, program); |
+// const struct sock_fprog prog = { |
+// static_cast<unsigned short>(program->size()), &program[0] }; |
+// prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); |
+// |
+class SANDBOX_EXPORT CodeGen { |
+ public: |
+ // A vector of BPF instructions that need to be installed as a filter |
+ // program in the kernel. |
+ typedef std::vector<struct sock_filter> Program; |
+ |
+ CodeGen(); |
+ ~CodeGen(); |
+ |
+ // This is a helper method that can be used for debugging purposes. It is |
+ // not normally called. |
+ static void PrintProgram(const Program& program); |
+ |
+ // Create a new instruction. Instructions form a DAG. The instruction objects |
+ // are owned by the CodeGen object. They do not need to be explicitly |
+ // deleted. |
+ // For details on the possible parameters refer to <linux/filter.h> |
+ Instruction* MakeInstruction(uint16_t code, |
+ uint32_t k, |
+ Instruction* next = nullptr); |
+ Instruction* MakeInstruction(uint16_t code, |
+ uint32_t k, |
+ Instruction* jt, |
+ Instruction* jf); |
+ |
+ // Compiles the graph of instructions into a BPF program that can be passed |
+ // to the kernel. Please note that this function modifies the graph in place |
+ // and must therefore only be called once per graph. |
+ void Compile(Instruction* instructions, Program* program); |
+ |
+ private: |
+ friend class CodeGenUnittestHelper; |
+ |
+ // Find all the instructions that are the target of BPF_JMPs. |
+ void FindBranchTargets(const Instruction& instructions, |
+ BranchTargets* branch_targets); |
+ |
+ // Combine instructions between "head" and "tail" into a new basic block. |
+ // Basic blocks are defined as sequences of instructions whose only branch |
+ // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET |
+ // instruction must be at the very end of the basic block. |
+ BasicBlock* MakeBasicBlock(Instruction* head, Instruction* tail); |
+ |
+ // Creates a basic block and adds it to "basic_blocks"; sets "first_block" |
+ // if it is still NULL. |
+ void AddBasicBlock(Instruction* head, |
+ Instruction* tail, |
+ const BranchTargets& branch_targets, |
+ TargetsToBlocks* basic_blocks, |
+ BasicBlock** first_block); |
+ |
+ // Cuts the DAG of instructions into basic blocks. |
+ BasicBlock* CutGraphIntoBasicBlocks(Instruction* instructions, |
+ const BranchTargets& branch_targets, |
+ TargetsToBlocks* blocks); |
+ |
+ // Find common tail sequences of basic blocks and coalesce them. |
+ void MergeTails(TargetsToBlocks* blocks); |
+ |
+ // For each basic block, compute the number of incoming branches. |
+ void ComputeIncomingBranches(BasicBlock* block, |
+ const TargetsToBlocks& targets_to_blocks, |
+ IncomingBranches* incoming_branches); |
+ |
+ // Topologically sort the basic blocks so that all jumps are forward jumps. |
+ // This is a requirement for any well-formed BPF program. |
+ void TopoSortBasicBlocks(BasicBlock* first_block, |
+ const TargetsToBlocks& blocks, |
+ BasicBlocks* basic_blocks); |
+ |
+ // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid |
+ // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being |
+ // inserted, if we need to jump over more than 256 instructions. |
+ void ComputeRelativeJumps(BasicBlocks* basic_blocks, |
+ const TargetsToBlocks& targets_to_blocks); |
+ |
+ // Concatenate instructions from all basic blocks into a BPF program that |
+ // can be passed to the kernel. |
+ void ConcatenateBasicBlocks(const BasicBlocks&, Program* program); |
+ |
+ // We stick all instructions and basic blocks into pools that get destroyed |
+ // when the CodeGen object is destroyed. This way, we neither need to worry |
+ // about explicitly managing ownership, nor do we need to worry about using |
+ // smart pointers in the presence of circular references. |
+ Instructions instructions_; |
+ BasicBlocks basic_blocks_; |
+ |
+ // Compile() must only ever be called once as it makes destructive changes |
+ // to the DAG. |
+ bool compiled_; |
+}; |
+ |
+} // namespace sandbox |
+ |
+#endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ |