| 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 <stddef.h> | |
| 9 #include <stdint.h> | |
| 10 | |
| 11 #include <map> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/macros.h" | |
| 15 #include "base/tuple.h" | |
| 16 #include "sandbox/sandbox_export.h" | |
| 17 | |
| 18 struct sock_filter; | |
| 19 | |
| 20 namespace sandbox { | |
| 21 | |
| 22 // The code generator implements a basic assembler that can convert a | |
| 23 // graph of BPF instructions into a well-formed array of BPF | |
| 24 // instructions. Most notably, it ensures that jumps are always | |
| 25 // forward and don't exceed the limit of 255 instructions imposed by | |
| 26 // the instruction set. | |
| 27 // | |
| 28 // Callers would typically create a new CodeGen object and then use it | |
| 29 // to build a DAG of instruction nodes. They'll eventually call | |
| 30 // Compile() to convert this DAG to a Program. | |
| 31 // | |
| 32 // CodeGen gen; | |
| 33 // CodeGen::Node allow, branch, dag; | |
| 34 // | |
| 35 // allow = | |
| 36 // gen.MakeInstruction(BPF_RET+BPF_K, | |
| 37 // ErrorCode(ErrorCode::ERR_ALLOWED).err())); | |
| 38 // branch = | |
| 39 // gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid, | |
| 40 // Trap(GetPidHandler, NULL), allow); | |
| 41 // dag = | |
| 42 // gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS, | |
| 43 // offsetof(struct arch_seccomp_data, nr), branch); | |
| 44 // | |
| 45 // // Simplified code follows; in practice, it is important to avoid calling | |
| 46 // // any C++ destructors after starting the sandbox. | |
| 47 // CodeGen::Program program; | |
| 48 // gen.Compile(dag, program); | |
| 49 // const struct sock_fprog prog = { | |
| 50 // static_cast<unsigned short>(program->size()), &program[0] }; | |
| 51 // prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); | |
| 52 // | |
| 53 class SANDBOX_EXPORT CodeGen { | |
| 54 public: | |
| 55 // A vector of BPF instructions that need to be installed as a filter | |
| 56 // program in the kernel. | |
| 57 typedef std::vector<struct sock_filter> Program; | |
| 58 | |
| 59 // Node represents a node within the instruction DAG being compiled. | |
| 60 using Node = Program::size_type; | |
| 61 | |
| 62 // kNullNode represents the "null" node; i.e., the reserved node | |
| 63 // value guaranteed to not equal any actual nodes. | |
| 64 static const Node kNullNode = -1; | |
| 65 | |
| 66 CodeGen(); | |
| 67 ~CodeGen(); | |
| 68 | |
| 69 // MakeInstruction creates a node representing the specified | |
| 70 // instruction, or returns and existing equivalent node if one | |
| 71 // exists. For details on the possible parameters refer to | |
| 72 // https://www.kernel.org/doc/Documentation/networking/filter.txt. | |
| 73 // TODO(mdempsky): Reconsider using default arguments here. | |
| 74 Node MakeInstruction(uint16_t code, | |
| 75 uint32_t k, | |
| 76 Node jt = kNullNode, | |
| 77 Node jf = kNullNode); | |
| 78 | |
| 79 // Compile linearizes the instruction DAG rooted at |head| into a | |
| 80 // program that can be executed by a BPF virtual machine. | |
| 81 void Compile(Node head, Program* program); | |
| 82 | |
| 83 private: | |
| 84 using MemoKey = Tuple<uint16_t, uint32_t, Node, Node>; | |
| 85 struct MemoKeyLess { | |
| 86 bool operator()(const MemoKey& lhs, const MemoKey& rhs) const; | |
| 87 }; | |
| 88 | |
| 89 // AppendInstruction adds a new instruction, ensuring that |jt| and | |
| 90 // |jf| are within range as necessary for |code|. | |
| 91 Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf); | |
| 92 | |
| 93 // WithinRange returns a node equivalent to |next| that is at most | |
| 94 // |range| instructions away from the (logical) beginning of the | |
| 95 // program. | |
| 96 Node WithinRange(Node next, size_t range); | |
| 97 | |
| 98 // Append appends a new instruction to the physical end (i.e., | |
| 99 // logical beginning) of |program_|. | |
| 100 Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf); | |
| 101 | |
| 102 // Offset returns how many instructions exist in |program_| after |target|. | |
| 103 size_t Offset(Node target) const; | |
| 104 | |
| 105 // NOTE: program_ is the compiled program in *reverse*, so that | |
| 106 // indices remain stable as we add instructions. | |
| 107 Program program_; | |
| 108 | |
| 109 // equivalent_ stores the most recent semantically-equivalent node for each | |
| 110 // instruction in program_. A node is defined as semantically-equivalent to N | |
| 111 // if it has the same instruction code and constant as N and its successor | |
| 112 // nodes (if any) are semantically-equivalent to N's successor nodes, or | |
| 113 // if it's an unconditional jump to a node semantically-equivalent to N. | |
| 114 std::vector<Node> equivalent_; | |
| 115 | |
| 116 std::map<MemoKey, Node, MemoKeyLess> memos_; | |
| 117 | |
| 118 DISALLOW_COPY_AND_ASSIGN(CodeGen); | |
| 119 }; | |
| 120 | |
| 121 } // namespace sandbox | |
| 122 | |
| 123 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__ | |
| OLD | NEW |