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