| Index: sandbox/linux/seccomp-bpf/codegen.h
|
| diff --git a/sandbox/linux/seccomp-bpf/codegen.h b/sandbox/linux/seccomp-bpf/codegen.h
|
| index fd229f7b8e2ad5f823dd86ffd474b5f143276b07..bca404694d3c042cfc9118c5013ddbad8855bb51 100644
|
| --- a/sandbox/linux/seccomp-bpf/codegen.h
|
| +++ b/sandbox/linux/seccomp-bpf/codegen.h
|
| @@ -5,28 +5,23 @@
|
| #ifndef SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__
|
| #define SANDBOX_LINUX_SECCOMP_BPF_CODEGEN_H__
|
|
|
| +#include <stddef.h>
|
| #include <stdint.h>
|
|
|
| #include <map>
|
| #include <vector>
|
|
|
| +#include "base/macros.h"
|
| +#include "base/tuple.h"
|
| #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 implements a basic assembler that can convert a
|
| // graph of BPF instructions into a well-formed array of BPF
|
| -// instructions. Most notably, it ensures that jumps are always
|
| +// instructions. Most notably, it ensures that jumps are always
|
| // forward and don't exceed the limit of 255 instructions imposed by
|
| // the instruction set.
|
| //
|
| @@ -62,19 +57,18 @@ class SANDBOX_EXPORT CodeGen {
|
| typedef std::vector<struct sock_filter> Program;
|
|
|
| // Node represents a node within the instruction DAG being compiled.
|
| - // Nodes are owned by the CodeGen object and need not be explicitly
|
| - // deleted.
|
| - using Node = Instruction*;
|
| + using Node = Program::size_type;
|
|
|
| // kNullNode represents the "null" node; i.e., the reserved node
|
| // value guaranteed to not equal any actual nodes.
|
| - static const Node kNullNode;
|
| + static const Node kNullNode = -1;
|
|
|
| CodeGen();
|
| ~CodeGen();
|
|
|
| // MakeInstruction creates a node representing the specified
|
| - // instruction. For details on the possible parameters refer to
|
| + // instruction, or returns and existing equivalent node if one
|
| + // exists. For details on the possible parameters refer to
|
| // https://www.kernel.org/doc/Documentation/networking/filter.txt.
|
| // TODO(mdempsky): Reconsider using default arguments here.
|
| Node MakeInstruction(uint16_t code,
|
| @@ -82,72 +76,39 @@ class SANDBOX_EXPORT CodeGen {
|
| Node jt = kNullNode,
|
| Node jf = kNullNode);
|
|
|
| - // Compile linearizes the instruction DAG into a BPF program that
|
| - // can be executed by a BPF virtual machine. Please note that this
|
| - // function modifies the graph in place and must therefore only be
|
| - // called once per graph.
|
| + // Compile linearizes the instruction DAG rooted at |head| into a
|
| + // program that can be executed by a BPF virtual machine.
|
| void Compile(Node head, 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_;
|
| + using MemoKey = Tuple4<uint16_t, uint32_t, Node, Node>;
|
| + struct MemoKeyLess {
|
| + bool operator()(const MemoKey& lhs, const MemoKey& rhs) const;
|
| + };
|
| +
|
| + // AppendInstruction adds a new instruction, ensuring that |jt| and
|
| + // |jf| are within range as necessary for |code|.
|
| + Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf);
|
| +
|
| + // WithinRange returns a node equivalent to |next| that is at most
|
| + // |range| instructions away from the (logical) beginning of the
|
| + // program.
|
| + Node WithinRange(Node next, size_t range);
|
| +
|
| + // Append appends a new instruction to the physical end (i.e.,
|
| + // logical beginning) of |program_|.
|
| + Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf);
|
| +
|
| + // Offset returns how many instructions exist in |program_| after |target|.
|
| + size_t Offset(Node target) const;
|
| +
|
| + // NOTE: program_ is the compiled program in *reverse*, so that
|
| + // indices remain stable as we add instructions.
|
| + Program program_;
|
| +
|
| + std::map<MemoKey, Node, MemoKeyLess> memos_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CodeGen);
|
| };
|
|
|
| } // namespace sandbox
|
|
|