1f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Copyright 2014 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_BPF_DSL_H_ 6f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_ 7f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include <stddef.h> 9f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <stdint.h> 10f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 11f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <utility> 12f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <vector> 13f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 14f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/macros.h" 15f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/memory/ref_counted.h" 16f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h" 17f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/bpf_dsl/cons.h" 18f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/bpf_dsl/trap_registry.h" 19f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/sandbox_export.h" 20f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 21f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// The sandbox::bpf_dsl namespace provides a domain-specific language 22f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// to make writing BPF policies more expressive. In general, the 23f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// object types all have value semantics (i.e., they can be copied 24f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// around, returned from or passed to function calls, etc. without any 25f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// surprising side effects), though not all support assignment. 26f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 27f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// An idiomatic and demonstrative (albeit silly) example of this API 28f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// would be: 29f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 30f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 31f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 32f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// using namespace sandbox::bpf_dsl; 33f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 34f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// class SillyPolicy : public Policy { 35f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// public: 36f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// SillyPolicy() {} 37f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ~SillyPolicy() override {} 38f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ResultExpr EvaluateSyscall(int sysno) const override { 39f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// if (sysno == __NR_fcntl) { 40f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Arg<int> fd(0), cmd(1); 41f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Arg<unsigned long> flags(2); 42f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK; 4324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// return If(AllOf(fd == 0, 4424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// cmd == F_SETFL, 4524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// (flags & ~kGoodFlags) == 0), 46f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Allow()) 4724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// .ElseIf(AnyOf(cmd == F_DUPFD, cmd == F_DUPFD_CLOEXEC), 48f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Error(EMFILE)) 49f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// .Else(Trap(SetFlagHandler, NULL)); 50f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// } else { 51f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// return Allow(); 52f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// } 53f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// } 54f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 55f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// private: 56f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// DISALLOW_COPY_AND_ASSIGN(SillyPolicy); 57f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// }; 58f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 59f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// More generally, the DSL currently supports the following grammar: 60f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 6124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// result = Allow() | Error(errno) | Kill() | Trace(aux) 62f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux) 63f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// | If(bool, result)[.ElseIf(bool, result)].Else(result) 64f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// | Switch(arg)[.Case(val, result)].Default(result) 6524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// bool = BoolConst(boolean) | Not(bool) | AllOf(bool...) | AnyOf(bool...) 66f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// | arg == val | arg != val 67f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// arg = Arg<T>(num) | arg & mask 68f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 69f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// The semantics of each function and operator are intended to be 70f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// intuitive, but are described in more detail below. 71f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 72f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// (Credit to Sean Parent's "Inheritance is the Base Class of Evil" 73f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// talk at Going Native 2013 for promoting value semantics via shared 74f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// pointers to immutable state.) 75f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 76f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace sandbox { 77f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace bpf_dsl { 78f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 79f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ResultExpr is an opaque reference to an immutable result expression tree. 80f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotypedef scoped_refptr<const internal::ResultExprImpl> ResultExpr; 81f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 82f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// BoolExpr is an opaque reference to an immutable boolean expression tree. 83f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotypedef scoped_refptr<const internal::BoolExprImpl> BoolExpr; 84f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 85f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Allow specifies a result that the system call should be allowed to 86f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// execute normally. 87f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT ResultExpr Allow(); 88f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 89f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Error specifies a result that the system call should fail with 90f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// error number |err|. As a special case, Error(0) will result in the 91f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// system call appearing to have succeeded, but without having any 92f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// side effects. 93f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT ResultExpr Error(int err); 94f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 9524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// Kill specifies a result to kill the process (task) immediately. 9624854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT ResultExpr Kill(); 97f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 98f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Trace specifies a result to notify a tracing process via the 99f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call. 100f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG. 101f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT ResultExpr Trace(uint16_t aux); 102f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 103f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Trap specifies a result that the system call should be handled by 104f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// trapping back into userspace and invoking |trap_func|, passing 105f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// |aux| as the second parameter. 106f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT ResultExpr 107f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Trap(TrapRegistry::TrapFnc trap_func, const void* aux); 108f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 109f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// UnsafeTrap is like Trap, except the policy is marked as "unsafe" 110f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// and allowed to use SandboxSyscall to invoke any system call. 111f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 112f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// NOTE: This feature, by definition, disables all security features of 113f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// the sandbox. It should never be used in production, but it can be 114f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// very useful to diagnose code that is incompatible with the sandbox. 115f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// If even a single system call returns "UnsafeTrap", the security of 116f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// entire sandbox should be considered compromised. 117f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT ResultExpr 118f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux); 119f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 120f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// BoolConst converts a bool value into a BoolExpr. 121f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT BoolExpr BoolConst(bool value); 122f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 12324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// Not returns a BoolExpr representing the logical negation of |cond|. 12424854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr Not(const BoolExpr& cond); 12524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 12624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// AllOf returns a BoolExpr representing the logical conjunction ("and") 12724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// of zero or more BoolExprs. 12824854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr AllOf(); 12924854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr AllOf(const BoolExpr& lhs, const BoolExpr& rhs); 13024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkotemplate <typename... Rest> 13124854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr AllOf(const BoolExpr& first, const Rest&... rest); 13224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 13324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// AnyOf returns a BoolExpr representing the logical disjunction ("or") 13424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// of zero or more BoolExprs. 13524854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr AnyOf(); 13624854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr AnyOf(const BoolExpr& lhs, const BoolExpr& rhs); 13724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkotemplate <typename... Rest> 13824854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoSANDBOX_EXPORT BoolExpr AnyOf(const BoolExpr& first, const Rest&... rest); 139f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 140f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 141f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass SANDBOX_EXPORT Arg { 142f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko public: 143f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Initializes the Arg to represent the |num|th system call 144f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // argument (indexed from 0), which is of type |T|. 145f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko explicit Arg(int num); 146f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 147f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {} 148f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 149f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Returns an Arg representing the current argument, but after 150f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // bitwise-and'ing it with |rhs|. 151f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko friend Arg operator&(const Arg& lhs, uint64_t rhs) { 152f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return Arg(lhs.num_, lhs.mask_ & rhs); 153f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 154f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 155f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Returns a boolean expression comparing whether the system call argument 156f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // (after applying any bitmasks, if appropriate) equals |rhs|. 157f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); } 158f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 159f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Returns a boolean expression comparing whether the system call argument 160f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // (after applying any bitmasks, if appropriate) does not equal |rhs|. 16124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko friend BoolExpr operator!=(const Arg& lhs, T rhs) { return Not(lhs == rhs); } 162f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 163f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko private: 164f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} 165f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 166f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko BoolExpr EqualTo(T val) const; 167f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 168f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko int num_; 169f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko uint64_t mask_; 170f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 171f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DISALLOW_ASSIGN(Arg); 172f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 173f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 174f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// If begins a conditional result expression predicated on the 175f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// specified boolean expression. 176f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT Elser If(const BoolExpr& cond, const ResultExpr& then_result); 177f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 178f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass SANDBOX_EXPORT Elser { 179f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko public: 180f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Elser(const Elser& elser); 181f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ~Elser(); 182f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 183f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // ElseIf extends the conditional result expression with another 184f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // "if then" clause, predicated on the specified boolean expression. 185f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Elser ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const; 186f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 187f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Else terminates a conditional result expression using |else_result| as 188f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // the default fallback result expression. 189f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ResultExpr Else(const ResultExpr& else_result) const; 190f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 191f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko private: 192f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko typedef std::pair<BoolExpr, ResultExpr> Clause; 193f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 194f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko explicit Elser(cons::List<Clause> clause_list); 195f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 196f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko cons::List<Clause> clause_list_; 197f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 198f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko friend Elser If(const BoolExpr&, const ResultExpr&); 199f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko template <typename T> 200f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko friend Caser<T> Switch(const Arg<T>&); 201f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DISALLOW_ASSIGN(Elser); 202f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 203f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 204f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Switch begins a switch expression dispatched according to the 205f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// specified argument value. 206f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 207f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg); 208f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 209f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 210f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass SANDBOX_EXPORT Caser { 211f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko public: 212f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {} 213f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ~Caser() {} 214f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 215f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Case adds a single-value "case" clause to the switch. 21624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko Caser<T> Case(T value, const ResultExpr& result) const; 217f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 218f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Cases adds a multiple-value "case" clause to the switch. 219f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way 220f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // of using this function. 22124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko template <typename... Values> 22224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko Caser<T> CasesImpl(const ResultExpr& result, const Values&... values) const; 223f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 224f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Terminate the switch with a "default" clause. 22524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko ResultExpr Default(const ResultExpr& result) const; 226f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 227f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko private: 228f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {} 229f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 230f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Arg<T> arg_; 231f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Elser elser_; 232f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 233f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko template <typename U> 234f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko friend Caser<U> Switch(const Arg<U>&); 235f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DISALLOW_ASSIGN(Caser); 236f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 237f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 238f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Recommended usage is to put 239f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// #define CASES SANDBOX_BPF_DSL_CASES 240f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// near the top of the .cc file (e.g., nearby any "using" statements), then 241f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// use like: 242f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Switch(arg).CASES((3, 5, 7), result)...; 243f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#define SANDBOX_BPF_DSL_CASES(values, result) \ 24424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko CasesImpl(result, SANDBOX_BPF_DSL_CASES_HELPER values) 24524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 24624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// Helper macro to strip parentheses. 24724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#define SANDBOX_BPF_DSL_CASES_HELPER(...) __VA_ARGS__ 248f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 249f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ===================================================================== 250f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Official API ends here. 251f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ===================================================================== 252f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 253f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace internal { 254f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 255f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Make argument-dependent lookup work. This is necessary because although 256f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// BoolExpr is defined in bpf_dsl, since it's merely a typedef for 257f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only 258f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// searches the "internal" nested namespace. 25924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkousing bpf_dsl::Not; 26024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkousing bpf_dsl::AllOf; 26124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkousing bpf_dsl::AnyOf; 262f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 263f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Returns a boolean expression that represents whether system call 264f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// argument |num| of size |size| is equal to |val|, when masked 265f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// according to |mask|. Users should use the Arg template class below 266f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// instead of using this API directly. 267f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT BoolExpr 268f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ArgEq(int num, size_t size, uint64_t mask, uint64_t val); 269f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 270f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Returns the default mask for a system call argument of the specified size. 271f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT uint64_t DefaultMask(size_t size); 272f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 273f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace internal 274f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 275f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 276f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoArg<T>::Arg(int num) 277f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko : num_(num), mask_(internal::DefaultMask(sizeof(T))) { 278f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 279f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 280f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Definition requires ArgEq to have been declared. Moved out-of-line 281f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// to minimize how much internal clutter users have to ignore while 282f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// reading the header documentation. 283f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 284f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Additionally, we use this helper member function to avoid linker errors 285f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// caused by defining operator== out-of-line. For a more detailed explanation, 286f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// see http://www.parashift.com/c++-faq-lite/template-friends.html. 287f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 288f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoBoolExpr Arg<T>::EqualTo(T val) const { 28924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko if (sizeof(T) == 4) { 29024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko // Prevent sign-extension of negative int32_t values. 29124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint32_t>(val)); 29224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko } 293f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val)); 294f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 295f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 296f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 297f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex VakulenkoSANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) { 298f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return Caser<T>(arg, Elser(nullptr)); 299f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 300f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 301f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 30224854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoCaser<T> Caser<T>::Case(T value, const ResultExpr& result) const { 303f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return SANDBOX_BPF_DSL_CASES((value), result); 304f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 305f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 306f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 30724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkotemplate <typename... Values> 30824854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoCaser<T> Caser<T>::CasesImpl(const ResultExpr& result, 30924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko const Values&... values) const { 310f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Theoretically we could evaluate arg_ just once and emit a more efficient 311f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // dispatch table, but for now we simply translate into an equivalent 312f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If/ElseIf/Else chain. 313f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 31424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko return Caser<T>(arg_, elser_.ElseIf(AnyOf((arg_ == values)...), result)); 315f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 316f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 317f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkotemplate <typename T> 31824854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoResultExpr Caser<T>::Default(const ResultExpr& result) const { 319f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return elser_.Else(result); 320f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 321f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 32224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkotemplate <typename... Rest> 32324854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoBoolExpr AllOf(const BoolExpr& first, const Rest&... rest) { 32424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko return AllOf(first, AllOf(rest...)); 32524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko} 32624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 32724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkotemplate <typename... Rest> 32824854748fba09df2a29f0d08d558c3acea70e7a1Alex VakulenkoBoolExpr AnyOf(const BoolExpr& first, const Rest&... rest) { 32924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko return AnyOf(first, AnyOf(rest...)); 33024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko} 33124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko 332f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace bpf_dsl 333f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace sandbox 334f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 335f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_ 336