Home | History | Annotate | Download | only in seccomp-bpf
      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 <map>
      9 #include <set>
     10 #include <vector>
     11 
     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 
     16 
     17 namespace playground2 {
     18 
     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;
     24 
     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.
     29 //
     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 Sandbox::Program.
     33 //
     34 // Instructions can be chained at the time when they are created, or they
     35 // can be joined later by calling JoinInstructions().
     36 //
     37 //   CodeGen gen;
     38 //   Instruction *dag, *branch;
     39 //   dag =
     40 //     gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
     41 //                         offsetof(struct arch_seccomp_data, nr),
     42 //   branch =
     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)));
     47 //
     48 //   // Simplified code follows; in practice, it is important to avoid calling
     49 //   // any C++ destructors after starting the sandbox.
     50 //   Sandbox::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);
     55 //
     56 class CodeGen {
     57  public:
     58   CodeGen();
     59   ~CodeGen();
     60 
     61   // This is a helper method that can be used for debugging purposes. It is
     62   // not normally called.
     63   static void PrintProgram(const Sandbox::Program& program);
     64 
     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
     67   // deleted.
     68   // For details on the possible parameters refer to <linux/filter.h>
     69   Instruction *MakeInstruction(uint16_t code, uint32_t k,
     70                                Instruction *next = NULL);
     71   Instruction *MakeInstruction(uint16_t code, const ErrorCode& err);
     72   Instruction *MakeInstruction(uint16_t code, uint32_t k,
     73                                Instruction *jt, Instruction *jf);
     74 
     75   // Join two (sequences of) instructions. This is useful, if the "next"
     76   // parameter had not originally been given in the call to MakeInstruction(),
     77   // or if a (conditional) jump still has an unsatisfied target.
     78   void JoinInstructions(Instruction *head, Instruction *tail);
     79 
     80   // Traverse the graph of instructions and visit each instruction once.
     81   // Traversal order is implementation-defined. It is acceptable to make
     82   // changes to the graph from within the callback function. These changes
     83   // do not affect traversal.
     84   // The "fnc" function gets called with both the instruction and the opaque
     85   // "aux" pointer.
     86   void Traverse(Instruction *, void (*fnc)(Instruction *, void *aux),
     87                 void *aux);
     88 
     89   // Compiles the graph of instructions into a BPF program that can be passed
     90   // to the kernel. Please note that this function modifies the graph in place
     91   // and must therefore only be called once per graph.
     92   void Compile(Instruction *instructions, Sandbox::Program *program);
     93 
     94  private:
     95   friend class CodeGenUnittestHelper;
     96 
     97   // Find all the instructions that are the target of BPF_JMPs.
     98   void FindBranchTargets(const Instruction& instructions,
     99                          BranchTargets *branch_targets);
    100 
    101   // Combine instructions between "head" and "tail" into a new basic block.
    102   // Basic blocks are defined as sequences of instructions whose only branch
    103   // target is the very first instruction; furthermore, any BPF_JMP or BPF_RET
    104   // instruction must be at the very end of the basic block.
    105   BasicBlock *MakeBasicBlock(Instruction *head, Instruction *tail);
    106 
    107   // Creates a basic block and adds it to "basic_blocks"; sets "first_block"
    108   // if it is still NULL.
    109   void AddBasicBlock(Instruction *head, Instruction *tail,
    110                      const BranchTargets& branch_targets,
    111                      TargetsToBlocks *basic_blocks, BasicBlock **first_block);
    112 
    113   // Cuts the DAG of instructions into basic blocks.
    114   BasicBlock *CutGraphIntoBasicBlocks(Instruction *instructions,
    115                                       const BranchTargets& branch_targets,
    116                                       TargetsToBlocks *blocks);
    117 
    118   // Find common tail sequences of basic blocks and coalesce them.
    119   void MergeTails(TargetsToBlocks *blocks);
    120 
    121   // For each basic block, compute the number of incoming branches.
    122   void ComputeIncomingBranches(BasicBlock *block,
    123                                const TargetsToBlocks& targets_to_blocks,
    124                                IncomingBranches *incoming_branches);
    125 
    126   // Topologically sort the basic blocks so that all jumps are forward jumps.
    127   // This is a requirement for any well-formed BPF program.
    128   void TopoSortBasicBlocks(BasicBlock *first_block,
    129                            const TargetsToBlocks& blocks,
    130                            BasicBlocks *basic_blocks);
    131 
    132   // Convert jt_ptr_ and jf_ptr_ fields in BPF_JMP instructions to valid
    133   // jt_ and jf_ jump offsets. This can result in BPF_JA instructions being
    134   // inserted, if we need to jump over more than 256 instructions.
    135   void ComputeRelativeJumps(BasicBlocks *basic_blocks,
    136                             const TargetsToBlocks& targets_to_blocks);
    137 
    138   // Concatenate instructions from all basic blocks into a BPF program that
    139   // can be passed to the kernel.
    140   void ConcatenateBasicBlocks(const BasicBlocks&, Sandbox::Program *program);
    141 
    142   // We stick all instructions and basic blocks into pools that get destroyed
    143   // when the CodeGen object is destroyed. This way, we neither need to worry
    144   // about explicitly managing ownership, nor do we need to worry about using
    145   // smart pointers in the presence of circular references.
    146   Instructions instructions_;
    147   BasicBlocks  basic_blocks_;
    148 
    149   // Compile() must only ever be called once as it makes destructive changes
    150   // to the DAG.
    151   bool compiled_;
    152 };
    153 
    154 }  // namespace
    155 
    156 #endif  // SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__
    157