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
19namespace sandbox {
20namespace bpf_dsl {
21class 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.
26class 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