Home | History | Annotate | Download | only in bpf_dsl
      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_POLICY_COMPILER_H_
      6 #define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
      7 
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include <vector>
     12 
     13 #include "base/macros.h"
     14 #include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
     15 #include "sandbox/linux/bpf_dsl/codegen.h"
     16 #include "sandbox/linux/bpf_dsl/trap_registry.h"
     17 #include "sandbox/sandbox_export.h"
     18 
     19 namespace sandbox {
     20 namespace bpf_dsl {
     21 class Policy;
     22 
     23 // PolicyCompiler implements the bpf_dsl compiler, allowing users to
     24 // transform bpf_dsl policies into BPF programs to be executed by the
     25 // Linux kernel.
     26 class SANDBOX_EXPORT PolicyCompiler {
     27  public:
     28   using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error);
     29 
     30   PolicyCompiler(const Policy* policy, TrapRegistry* registry);
     31   ~PolicyCompiler();
     32 
     33   // Compile registers any trap handlers needed by the policy and
     34   // compiles the policy to a BPF program, which it returns.
     35   CodeGen::Program Compile();
     36 
     37   // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any
     38   // system calls, regardless of policy.
     39   void DangerousSetEscapePC(uint64_t escapepc);
     40 
     41   // SetPanicFunc sets the callback function used for handling faulty
     42   // system call conditions.  The default behavior is to immediately kill
     43   // the process.
     44   // TODO(mdempsky): Move this into Policy?
     45   void SetPanicFunc(PanicFunc panic_func);
     46 
     47   // UnsafeTraps require some syscalls to always be allowed.
     48   // This helper function returns true for these calls.
     49   static bool IsRequiredForUnsafeTrap(int sysno);
     50 
     51   // Functions below are meant for use within bpf_dsl itself.
     52 
     53   // Return returns a CodeGen::Node that returns the specified seccomp
     54   // return value.
     55   CodeGen::Node Return(uint32_t ret);
     56 
     57   // Trap returns a CodeGen::Node to indicate the system call should
     58   // instead invoke a trap handler.
     59   CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
     60 
     61   // MaskedEqual returns a CodeGen::Node that represents a conditional branch.
     62   // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
     63   // to "value"; if equal, then "passed" will be executed, otherwise "failed".
     64   // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1)
     65   // If it is outside this range, the sandbox treats the system call just
     66   // the same as any other ABI violation (i.e., it panics).
     67   CodeGen::Node MaskedEqual(int argno,
     68                             size_t width,
     69                             uint64_t mask,
     70                             uint64_t value,
     71                             CodeGen::Node passed,
     72                             CodeGen::Node failed);
     73 
     74  private:
     75   struct Range;
     76   typedef std::vector<Range> Ranges;
     77 
     78   // Used by MaskedEqualHalf to track which half of the argument it's
     79   // emitting instructions for.
     80   enum class ArgHalf {
     81     LOWER,
     82     UPPER,
     83   };
     84 
     85   // Compile the configured policy into a complete instruction sequence.
     86   CodeGen::Node AssemblePolicy();
     87 
     88   // Return an instruction sequence that checks the
     89   // arch_seccomp_data's "arch" field is valid, and then passes
     90   // control to |passed| if so.
     91   CodeGen::Node CheckArch(CodeGen::Node passed);
     92 
     93   // If |has_unsafe_traps_| is true, returns an instruction sequence
     94   // that allows all system calls from |escapepc_|, and otherwise
     95   // passes control to |rest|. Otherwise, simply returns |rest|.
     96   CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
     97 
     98   // Return an instruction sequence that loads and checks the system
     99   // call number, performs a binary search, and then dispatches to an
    100   // appropriate instruction sequence compiled from the current
    101   // policy.
    102   CodeGen::Node DispatchSyscall();
    103 
    104   // Return an instruction sequence that checks the system call number
    105   // (expected to be loaded in register A) and if valid, passes
    106   // control to |passed| (with register A still valid).
    107   CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
    108 
    109   // Finds all the ranges of system calls that need to be handled. Ranges are
    110   // sorted in ascending order of system call numbers. There are no gaps in the
    111   // ranges. System calls with identical CodeGen::Nodes are coalesced into a
    112   // single
    113   // range.
    114   void FindRanges(Ranges* ranges);
    115 
    116   // Returns a BPF program snippet that implements a jump table for the
    117   // given range of system call numbers. This function runs recursively.
    118   CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
    119                                   Ranges::const_iterator stop);
    120 
    121   // CompileResult compiles an individual result expression into a
    122   // CodeGen node.
    123   CodeGen::Node CompileResult(const ResultExpr& res);
    124 
    125   // Returns a BPF program that evaluates half of a conditional expression;
    126   // it should only ever be called from CondExpression().
    127   CodeGen::Node MaskedEqualHalf(int argno,
    128                                 size_t width,
    129                                 uint64_t full_mask,
    130                                 uint64_t full_value,
    131                                 ArgHalf half,
    132                                 CodeGen::Node passed,
    133                                 CodeGen::Node failed);
    134 
    135   // Returns the fatal CodeGen::Node that is used to indicate that somebody
    136   // attempted to pass a 64bit value in a 32bit system call argument.
    137   CodeGen::Node Unexpected64bitArgument();
    138 
    139   const Policy* policy_;
    140   TrapRegistry* registry_;
    141   uint64_t escapepc_;
    142   PanicFunc panic_func_;
    143 
    144   CodeGen gen_;
    145   bool has_unsafe_traps_;
    146 
    147   DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
    148 };
    149 
    150 }  // namespace bpf_dsl
    151 }  // namespace sandbox
    152 
    153 #endif  // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
    154