// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// 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/macros.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();
// 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(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
// 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();
const Policy* policy_;
TrapRegistry* registry_;
uint64_t escapepc_;
PanicFunc panic_func_;
CodeGen gen_;
bool has_unsafe_traps_;
DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
};
} // namespace bpf_dsl
} // namespace sandbox
#endif // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_