1f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
3f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// found in the LICENSE file.
4f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
5f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
6f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
7f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include <stddef.h>
9f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <stdint.h>
10f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
11f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <vector>
12f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
13f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/macros.h"
14f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
15f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/bpf_dsl/codegen.h"
1624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include "sandbox/linux/bpf_dsl/trap_registry.h"
17f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/sandbox_export.h"
18f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
19f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace sandbox {
20f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace bpf_dsl {
21f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass Policy;
22f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
23f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// PolicyCompiler implements the bpf_dsl compiler, allowing users to
24f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// transform bpf_dsl policies into BPF programs to be executed by the
25f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Linux kernel.
26f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass SANDBOX_EXPORT PolicyCompiler {
27f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko public:
2824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error);
2924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko
30f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  PolicyCompiler(const Policy* policy, TrapRegistry* registry);
31f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  ~PolicyCompiler();
32f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
33f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Compile registers any trap handlers needed by the policy and
34f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // compiles the policy to a BPF program, which it returns.
3524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Program Compile();
36f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
37f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any
38f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // system calls, regardless of policy.
39f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  void DangerousSetEscapePC(uint64_t escapepc);
40f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
4124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // SetPanicFunc sets the callback function used for handling faulty
4224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // system call conditions.  The default behavior is to immediately kill
4324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // the process.
4424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // TODO(mdempsky): Move this into Policy?
4524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  void SetPanicFunc(PanicFunc panic_func);
46f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
47f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // UnsafeTraps require some syscalls to always be allowed.
48f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // This helper function returns true for these calls.
49f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  static bool IsRequiredForUnsafeTrap(int sysno);
50f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
5124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // Functions below are meant for use within bpf_dsl itself.
5224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko
5324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // Return returns a CodeGen::Node that returns the specified seccomp
5424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // return value.
5524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Node Return(uint32_t ret);
5624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko
5724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // Trap returns a CodeGen::Node to indicate the system call should
5824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // instead invoke a trap handler.
5924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
6024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko
6124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // MaskedEqual returns a CodeGen::Node that represents a conditional branch.
62f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
6324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // to "value"; if equal, then "passed" will be executed, otherwise "failed".
6424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1)
65f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // If it is outside this range, the sandbox treats the system call just
6624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // the same as any other ABI violation (i.e., it panics).
6724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Node MaskedEqual(int argno,
6824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                            size_t width,
69f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko                            uint64_t mask,
70f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko                            uint64_t value,
7124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                            CodeGen::Node passed,
7224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                            CodeGen::Node failed);
73f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
74f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko private:
75f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  struct Range;
76f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  typedef std::vector<Range> Ranges;
77f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
7824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // Used by MaskedEqualHalf to track which half of the argument it's
79f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // emitting instructions for.
8024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  enum class ArgHalf {
8124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko    LOWER,
8224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko    UPPER,
83f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  };
84f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
85f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Compile the configured policy into a complete instruction sequence.
86f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node AssemblePolicy();
87f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
88f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Return an instruction sequence that checks the
89f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // arch_seccomp_data's "arch" field is valid, and then passes
90f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // control to |passed| if so.
91f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node CheckArch(CodeGen::Node passed);
92f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
93f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // If |has_unsafe_traps_| is true, returns an instruction sequence
94f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // that allows all system calls from |escapepc_|, and otherwise
95f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // passes control to |rest|. Otherwise, simply returns |rest|.
96f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
97f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
98f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Return an instruction sequence that loads and checks the system
99f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // call number, performs a binary search, and then dispatches to an
100f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // appropriate instruction sequence compiled from the current
101f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // policy.
102f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node DispatchSyscall();
103f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
104f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Return an instruction sequence that checks the system call number
105f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // (expected to be loaded in register A) and if valid, passes
106f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // control to |passed| (with register A still valid).
107f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
108f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
109f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Finds all the ranges of system calls that need to be handled. Ranges are
110f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // sorted in ascending order of system call numbers. There are no gaps in the
11124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // ranges. System calls with identical CodeGen::Nodes are coalesced into a
11224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // single
113f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // range.
114f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  void FindRanges(Ranges* ranges);
115f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
116f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Returns a BPF program snippet that implements a jump table for the
117f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // given range of system call numbers. This function runs recursively.
118f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
119f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko                                  Ranges::const_iterator stop);
120f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
121f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // CompileResult compiles an individual result expression into a
122f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // CodeGen node.
123f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen::Node CompileResult(const ResultExpr& res);
124f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
125f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Returns a BPF program that evaluates half of a conditional expression;
126f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // it should only ever be called from CondExpression().
12724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Node MaskedEqualHalf(int argno,
12824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                                size_t width,
12924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                                uint64_t full_mask,
13024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                                uint64_t full_value,
13124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                                ArgHalf half,
13224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                                CodeGen::Node passed,
13324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko                                CodeGen::Node failed);
13424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko
13524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // Returns the fatal CodeGen::Node that is used to indicate that somebody
13624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  // attempted to pass a 64bit value in a 32bit system call argument.
13724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Node Unexpected64bitArgument();
138f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
139f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  const Policy* policy_;
140f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  TrapRegistry* registry_;
141f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  uint64_t escapepc_;
14224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  PanicFunc panic_func_;
143f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
144f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  CodeGen gen_;
145f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  bool has_unsafe_traps_;
146f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
147f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
148f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko};
149f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
150f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}  // namespace bpf_dsl
151f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}  // namespace sandbox
152f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
153f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#endif  // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
154