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.
5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__
6 #define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__
12 #include "sandbox/linux/seccomp-bpf/basicblock.h"
13 #include "sandbox/linux/seccomp-bpf/instruction.h"
14 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
15 #include "sandbox/sandbox_export.h"
19 typedef std::vector
<Instruction
*> Instructions
;
20 typedef std::vector
<BasicBlock
*> BasicBlocks
;
21 typedef std::map
<const Instruction
*, int> BranchTargets
;
22 typedef std::map
<const Instruction
*, BasicBlock
*> TargetsToBlocks
;
23 typedef std::map
<const BasicBlock
*, int> IncomingBranches
;
25 // The code generator instantiates a basic compiler that can convert a
26 // graph of BPF instructions into a well-formed stream of BPF instructions.
27 // Most notably, it ensures that jumps are always forward and don't exceed
28 // the limit of 255 instructions imposed by the instruction set.
30 // Callers would typically create a new CodeGen object and then use it to
31 // build a DAG of Instructions. They'll eventually call Compile() to convert
32 // this DAG to a SandboxBPF::Program.
34 // Instructions can be chained at the time when they are created, or they
35 // can be joined later by calling JoinInstructions().
38 // Instruction *dag, *branch;
40 // gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
41 // offsetof(struct arch_seccomp_data, nr),
43 // gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid,
44 // Trap(GetPidHandler, NULL), NULL);
45 // gen.JoinInstructions(branch,
46 // gen.MakeInstruction(BPF_RET+BPF_K, ErrorCode(ErrorCode::ERR_ALLOWED)));
48 // // Simplified code follows; in practice, it is important to avoid calling
49 // // any C++ destructors after starting the sandbox.
50 // SandboxBPF::Program program;
51 // gen.Compile(dag, program);
52 // const struct sock_fprog prog = {
53 // static_cast<unsigned short>(program->size()), &program[0] };
54 // prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
56 class SANDBOX_EXPORT CodeGen
{
61 // This is a helper method that can be used for debugging purposes. It is
62 // not normally called.
63 static void PrintProgram(const SandboxBPF::Program
& program
);
65 // Create a new instruction. Instructions form a DAG. The instruction objects
66 // are owned by the CodeGen object. They do not need to be explicitly
68 // For details on the possible parameters refer to <linux/filter.h>
69 Instruction
* MakeInstruction(uint16_t code
,
71 Instruction
* next
= NULL
);
72 Instruction
* MakeInstruction(uint16_t code
, const ErrorCode
& err
);
73 Instruction
* MakeInstruction(uint16_t code
,
78 // Join two (sequences of) instructions. This is useful, if the "next"
79 // parameter had not originally been given in the call to MakeInstruction(),
80 // or if a (conditional) jump still has an unsatisfied target.
81 void JoinInstructions(Instruction
* head
, Instruction
* tail
);
83 // Traverse the graph of instructions and visit each instruction once.
84 // Traversal order is implementation-defined. It is acceptable to make
85 // changes to the graph from within the callback function. These changes
86 // do not affect traversal.
87 // The "fnc" function gets called with both the instruction and the opaque
89 void Traverse(Instruction
*, void (*fnc
)(Instruction
*, void* aux
), void* aux
);
91 // Compiles the graph of instructions into a BPF program that can be passed
92 // to the kernel. Please note that this function modifies the graph in place
93 // and must therefore only be called once per graph.
94 void Compile(Instruction
* instructions
, SandboxBPF::Program
* program
);
97 friend class CodeGenUnittestHelper
;
99 // Find all the instructions that are the target of BPF_JMPs.
100 void FindBranchTargets(const Instruction
& instructions
,
101 BranchTargets
* branch_targets
);
103 // Combine instructions between "head" and "tail" into a new basic block.
104 // Basic blocks are defined as sequences of instructions whose only branch
105 // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET
106 // instruction must be at the very end of the basic block.
107 BasicBlock
* MakeBasicBlock(Instruction
* head
, Instruction
* tail
);
109 // Creates a basic block and adds it to "basic_blocks"; sets "first_block"
110 // if it is still NULL.
111 void AddBasicBlock(Instruction
* head
,
113 const BranchTargets
& branch_targets
,
114 TargetsToBlocks
* basic_blocks
,
115 BasicBlock
** first_block
);
117 // Cuts the DAG of instructions into basic blocks.
118 BasicBlock
* CutGraphIntoBasicBlocks(Instruction
* instructions
,
119 const BranchTargets
& branch_targets
,
120 TargetsToBlocks
* blocks
);
122 // Find common tail sequences of basic blocks and coalesce them.
123 void MergeTails(TargetsToBlocks
* blocks
);
125 // For each basic block, compute the number of incoming branches.
126 void ComputeIncomingBranches(BasicBlock
* block
,
127 const TargetsToBlocks
& targets_to_blocks
,
128 IncomingBranches
* incoming_branches
);
130 // Topologically sort the basic blocks so that all jumps are forward jumps.
131 // This is a requirement for any well-formed BPF program.
132 void TopoSortBasicBlocks(BasicBlock
* first_block
,
133 const TargetsToBlocks
& blocks
,
134 BasicBlocks
* basic_blocks
);
136 // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid
137 // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being
138 // inserted, if we need to jump over more than 256 instructions.
139 void ComputeRelativeJumps(BasicBlocks
* basic_blocks
,
140 const TargetsToBlocks
& targets_to_blocks
);
142 // Concatenate instructions from all basic blocks into a BPF program that
143 // can be passed to the kernel.
144 void ConcatenateBasicBlocks(const BasicBlocks
&, SandboxBPF::Program
* program
);
146 // We stick all instructions and basic blocks into pools that get destroyed
147 // when the CodeGen object is destroyed. This way, we neither need to worry
148 // about explicitly managing ownership, nor do we need to worry about using
149 // smart pointers in the presence of circular references.
150 Instructions instructions_
;
151 BasicBlocks basic_blocks_
;
153 // Compile() must only ever be called once as it makes destructive changes
158 } // namespace sandbox
160 #endif // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__