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