• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BPF_DSL_CODEGEN_H__
6 #define SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <map>
12 #include <tuple>
13 #include <vector>
14 
15 #include "base/macros.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 = gen.Compile(dag);
48 //   const struct sock_fprog prog = {
49 //     static_cast<unsigned short>(program.size()), &program[0] };
50 //   prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
51 //
52 class SANDBOX_EXPORT CodeGen {
53  public:
54   // A vector of BPF instructions that need to be installed as a filter
55   // program in the kernel.
56   typedef std::vector<struct sock_filter> Program;
57 
58   // Node represents a node within the instruction DAG being compiled.
59   using Node = Program::size_type;
60 
61   // kNullNode represents the "null" node; i.e., the reserved node
62   // value guaranteed to not equal any actual nodes.
63   static const Node kNullNode = -1;
64 
65   CodeGen();
66   ~CodeGen();
67 
68   // MakeInstruction creates a node representing the specified
69   // instruction, or returns and existing equivalent node if one
70   // exists. For details on the possible parameters refer to
71   // https://www.kernel.org/doc/Documentation/networking/filter.txt.
72   // TODO(mdempsky): Reconsider using default arguments here.
73   Node MakeInstruction(uint16_t code,
74                        uint32_t k,
75                        Node jt = kNullNode,
76                        Node jf = kNullNode);
77 
78   // Compile linearizes the instruction DAG rooted at |head| into a
79   // program that can be executed by a BPF virtual machine.
80   Program Compile(Node head);
81 
82  private:
83   using MemoKey = std::tuple<uint16_t, uint32_t, Node, Node>;
84 
85   // AppendInstruction adds a new instruction, ensuring that |jt| and
86   // |jf| are within range as necessary for |code|.
87   Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf);
88 
89   // WithinRange returns a node equivalent to |next| that is at most
90   // |range| instructions away from the (logical) beginning of the
91   // program.
92   Node WithinRange(Node next, size_t range);
93 
94   // Append appends a new instruction to the physical end (i.e.,
95   // logical beginning) of |program_|.
96   Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf);
97 
98   // Offset returns how many instructions exist in |program_| after |target|.
99   size_t Offset(Node target) const;
100 
101   // NOTE: program_ is the compiled program in *reverse*, so that
102   // indices remain stable as we add instructions.
103   Program program_;
104 
105   // equivalent_ stores the most recent semantically-equivalent node for each
106   // instruction in program_. A node is defined as semantically-equivalent to N
107   // if it has the same instruction code and constant as N and its successor
108   // nodes (if any) are semantically-equivalent to N's successor nodes, or
109   // if it's an unconditional jump to a node semantically-equivalent to N.
110   std::vector<Node> equivalent_;
111 
112   std::map<MemoKey, Node> memos_;
113 
114   DISALLOW_COPY_AND_ASSIGN(CodeGen);
115 };
116 
117 }  // namespace sandbox
118 
119 #endif  // SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
120