• 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_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