185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Copyright 2014 The Chromium Authors. All rights reserved. 285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Use of this source code is governed by a BSD-style license that can be 385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// found in the LICENSE file. 485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_ 685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_ 785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include <stdint.h> 985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 1085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include <utility> 1185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include <vector> 1285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 1385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include "base/macros.h" 1485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include "base/memory/ref_counted.h" 1585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include "sandbox/linux/bpf_dsl/cons.h" 1685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 1785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include "sandbox/linux/seccomp-bpf/trap.h" 1885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#include "sandbox/sandbox_export.h" 1985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 2085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnernamespace sandbox { 2185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass ErrorCode; 2285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SandboxBPF; 2385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 2485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 2585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// The sandbox::bpf_dsl namespace provides a domain-specific language 2685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// to make writing BPF policies more expressive. In general, the 2785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// object types all have value semantics (i.e., they can be copied 2885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// around, returned from or passed to function calls, etc. without any 2985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// surprising side effects), though not all support assignment. 3085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 3185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// An idiomatic and demonstrative (albeit silly) example of this API 3285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// would be: 3385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 3485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 3585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 3685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// using namespace sandbox::bpf_dsl; 3785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 3885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// class SillyPolicy : public SandboxBPFDSLPolicy { 3985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// public: 4085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// SillyPolicy() {} 4185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// virtual ~SillyPolicy() {} 4285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { 4385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// if (sysno == __NR_fcntl) { 4485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Arg<int> fd(0), cmd(1); 4585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Arg<unsigned long> flags(2); 4685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK; 4785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// return If(fd == 0 && cmd == F_SETFL && (flags & ~kGoodFlags) == 0, 4885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Allow()) 4985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// .ElseIf(cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC, 5085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Error(EMFILE)) 5185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// .Else(Trap(SetFlagHandler, NULL)); 5285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// } else { 5385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// return Allow(); 5485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// } 5585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// } 5685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 5785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// private: 5885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// DISALLOW_COPY_AND_ASSIGN(SillyPolicy); 5985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// }; 6085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 6185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// More generally, the DSL currently supports the following grammar: 6285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 6385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// result = Allow() | Error(errno) | Kill(msg) | Trace(aux) 6485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux) 6585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// | If(bool, result)[.ElseIf(bool, result)].Else(result) 6685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// | Switch(arg)[.Case(val, result)].Default(result) 6785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// bool = BoolConst(boolean) | !bool | bool && bool | bool || bool 6885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// | arg == val | arg != val 6985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// arg = Arg<T>(num) | arg & mask 7085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 7185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// The semantics of each function and operator are intended to be 7285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// intuitive, but are described in more detail below. 7385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 7485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// (Credit to Sean Parent's "Inheritance is the Base Class of Evil" 7585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// talk at Going Native 2013 for promoting value semantics via shared 7685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// pointers to immutable state.) 7785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 7885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnernamespace sandbox { 7985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnernamespace bpf_dsl { 8085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 8185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Forward declarations of classes; see below for proper documentation. 8285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass Elser; 8385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 8485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass Caser; 8585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnernamespace internal { 8685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass ResultExprImpl; 8785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass BoolExprImpl; 8885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 8985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 9085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// ResultExpr is an opaque reference to an immutable result expression tree. 9185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertypedef scoped_refptr<const internal::ResultExprImpl> ResultExpr; 9285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 9385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// BoolExpr is an opaque reference to an immutable boolean expression tree. 9485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertypedef scoped_refptr<const internal::BoolExprImpl> BoolExpr; 9585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 9685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Helper class to make writing policies easier. 9785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SANDBOX_EXPORT SandboxBPFDSLPolicy : public SandboxBPFPolicy { 9885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner public: 9985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner SandboxBPFDSLPolicy() : SandboxBPFPolicy() {} 10085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ~SandboxBPFDSLPolicy() {} 10185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 10285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // User extension point for writing custom sandbox policies. 10385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ResultExpr EvaluateSyscall(int sysno) const = 0; 10485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 10585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Optional overload for specifying alternate behavior for invalid 10685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // system calls. The default is to return ENOSYS. 10785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ResultExpr InvalidSyscall() const; 10885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 10985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Override implementations from SandboxBPFPolicy. Marked as FINAL 11085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // to prevent mixups with child classes accidentally overloading 11185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // these instead of the above methods. 11285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ErrorCode EvaluateSyscall(SandboxBPF* sb, 11385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner int sysno) const OVERRIDE FINAL; 11485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ErrorCode InvalidSyscall(SandboxBPF* sb) const OVERRIDE FINAL; 11585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 11685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Helper method so policies can just write Trap(func, aux). 11785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner static ResultExpr Trap(Trap::TrapFnc trap_func, const void* aux); 11885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 11985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner private: 12085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner DISALLOW_COPY_AND_ASSIGN(SandboxBPFDSLPolicy); 12185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner}; 12285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 12385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Allow specifies a result that the system call should be allowed to 12485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// execute normally. 12585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT ResultExpr Allow(); 12685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 12785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Error specifies a result that the system call should fail with 12885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// error number |err|. As a special case, Error(0) will result in the 12985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// system call appearing to have succeeded, but without having any 13085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// side effects. 13185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT ResultExpr Error(int err); 13285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 13385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Kill specifies a result to kill the program and print an error message. 13485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT ResultExpr Kill(const char* msg); 13585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 13685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Trace specifies a result to notify a tracing process via the 13785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call. 13885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG. 13985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT ResultExpr Trace(uint16_t aux); 14085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 14185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Trap specifies a result that the system call should be handled by 14285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// trapping back into userspace and invoking |trap_func|, passing 14385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// |aux| as the second parameter. 14485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT ResultExpr Trap(Trap::TrapFnc trap_func, const void* aux); 14585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 14685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// UnsafeTrap is like Trap, except the policy is marked as "unsafe" 14785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// and allowed to use SandboxSyscall to invoke any system call. 14885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 14985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// NOTE: This feature, by definition, disables all security features of 15085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// the sandbox. It should never be used in production, but it can be 15185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// very useful to diagnose code that is incompatible with the sandbox. 15285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// If even a single system call returns "UnsafeTrap", the security of 15385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// entire sandbox should be considered compromised. 15485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT ResultExpr UnsafeTrap(Trap::TrapFnc trap_func, const void* aux); 15585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 15685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// BoolConst converts a bool value into a BoolExpr. 15785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT BoolExpr BoolConst(bool value); 15885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 15985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Various ways to combine boolean expressions into more complex expressions. 16085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// They follow standard boolean algebra laws. 16185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT BoolExpr operator!(const BoolExpr& cond); 16285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT BoolExpr operator&&(const BoolExpr& lhs, const BoolExpr& rhs); 16385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT BoolExpr operator||(const BoolExpr& lhs, const BoolExpr& rhs); 16485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 16585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 16685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SANDBOX_EXPORT Arg { 16785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner public: 16885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Initializes the Arg to represent the |num|th system call 16985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // argument (indexed from 0), which is of type |T|. 17085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner explicit Arg(int num); 17185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 17285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {} 17385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 17485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Returns an Arg representing the current argument, but after 17585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // bitwise-and'ing it with |rhs|. 17685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend Arg operator&(const Arg& lhs, uint64_t rhs) { 17785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner return Arg(lhs.num_, lhs.mask_ & rhs); 17885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner } 17985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 18085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Returns a boolean expression comparing whether the system call argument 18185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // (after applying any bitmasks, if appropriate) equals |rhs|. 18285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); } 18385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 18485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Returns a boolean expression comparing whether the system call argument 18585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // (after applying any bitmasks, if appropriate) does not equal |rhs|. 18685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend BoolExpr operator!=(const Arg& lhs, T rhs) { return !(lhs == rhs); } 18785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 18885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner private: 18985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Arg(int num, uint64_t mask) : num_(num), mask_(mask) {} 19085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 19185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner BoolExpr EqualTo(T val) const; 19285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 19385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner int num_; 19485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner uint64_t mask_; 19585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 19685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner DISALLOW_ASSIGN(Arg); 19785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner}; 19885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 19985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// If begins a conditional result expression predicated on the 20085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// specified boolean expression. 20185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT Elser If(const BoolExpr& cond, const ResultExpr& then_result); 20285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 20385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SANDBOX_EXPORT Elser { 20485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner public: 20585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Elser(const Elser& elser); 20685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ~Elser(); 20785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 20885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // ElseIf extends the conditional result expression with another 20985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // "if then" clause, predicated on the specified boolean expression. 21085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Elser ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const; 21185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 21285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Else terminates a conditional result expression using |else_result| as 21385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // the default fallback result expression. 21485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ResultExpr Else(const ResultExpr& else_result) const; 21585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 21685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner private: 21785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner typedef std::pair<BoolExpr, ResultExpr> Clause; 21885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 21985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner explicit Elser(Cons<Clause>::List clause_list); 22085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 22185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Cons<Clause>::List clause_list_; 22285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 22385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend Elser If(const BoolExpr&, const ResultExpr&); 22485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner template <typename T> 22585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend Caser<T> Switch(const Arg<T>&); 22685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner DISALLOW_ASSIGN(Elser); 22785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner}; 22885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 22985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Switch begins a switch expression dispatched according to the 23085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// specified argument value. 23185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 23285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg); 23385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 23485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 23585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SANDBOX_EXPORT Caser { 23685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner public: 23785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {} 23885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ~Caser() {} 23985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 24085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Case adds a single-value "case" clause to the switch. 24185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Caser<T> Case(T value, ResultExpr result) const; 24285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 24385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Cases adds a multiple-value "case" clause to the switch. 24485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way 24585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // of using this function. 24685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Caser<T> Cases(const std::vector<T>& values, ResultExpr result) const; 24785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 24885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Terminate the switch with a "default" clause. 24985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ResultExpr Default(ResultExpr result) const; 25085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 25185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner private: 25285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {} 25385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 25485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Arg<T> arg_; 25585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Elser elser_; 25685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 25785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner template <typename U> 25885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend Caser<U> Switch(const Arg<U>&); 25985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner DISALLOW_ASSIGN(Caser); 26085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner}; 26185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 26285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Recommended usage is to put 26385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// #define CASES SANDBOX_BPF_DSL_CASES 26485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// near the top of the .cc file (e.g., nearby any "using" statements), then 26585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// use like: 26685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Switch(arg).CASES((3, 5, 7), result)...; 26785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#define SANDBOX_BPF_DSL_CASES(values, result) \ 26885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner Cases(SANDBOX_BPF_DSL_CASES_HELPER values, result) 26985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 27085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Helper macro to construct a std::vector from an initializer list. 27185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// TODO(mdempsky): Convert to use C++11 initializer lists instead. 27285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#define SANDBOX_BPF_DSL_CASES_HELPER(value, ...) \ 27385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ({ \ 27485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner const __typeof__(value) bpf_dsl_cases_values[] = {value, __VA_ARGS__}; \ 27585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner std::vector<__typeof__(value)>( \ 27685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner bpf_dsl_cases_values, \ 27785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner bpf_dsl_cases_values + arraysize(bpf_dsl_cases_values)); \ 27885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner }) 27985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 28085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// ===================================================================== 28185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Official API ends here. 28285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// ===================================================================== 28385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 28485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Definitions below are necessary here only for C++03 compatibility. 28585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Once C++11 is available, they should be moved into bpf_dsl.cc via extern 28685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// templates. 28785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnernamespace internal { 28885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 28985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Make argument-dependent lookup work. This is necessary because although 29085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// BoolExpr is defined in bpf_dsl, since it's merely a typedef for 29185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only 29285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// searches the "internal" nested namespace. 29385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerusing bpf_dsl::operator!; 29485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerusing bpf_dsl::operator||; 29585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerusing bpf_dsl::operator&&; 29685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 29785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Returns a boolean expression that represents whether system call 29885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// argument |num| of size |size| is equal to |val|, when masked 29985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// according to |mask|. Users should use the Arg template class below 30085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// instead of using this API directly. 30185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT BoolExpr 30285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ArgEq(int num, size_t size, uint64_t mask, uint64_t val); 30385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 30485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Returns the default mask for a system call argument of the specified size. 30585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT uint64_t DefaultMask(size_t size); 30685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 30785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Internal interface implemented by BoolExpr implementations. 30885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SANDBOX_EXPORT BoolExprImpl : public base::RefCounted<BoolExprImpl> { 30985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner public: 31085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner BoolExprImpl() {} 31185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ErrorCode Compile(SandboxBPF* sb, 31285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ErrorCode true_ec, 31385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ErrorCode false_ec) const = 0; 31485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 31585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner protected: 31685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ~BoolExprImpl() {} 31785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 31885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner private: 31985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend class base::RefCounted<BoolExprImpl>; 32085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner DISALLOW_COPY_AND_ASSIGN(BoolExprImpl); 32185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner}; 32285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 32385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Internal interface implemented by ResultExpr implementations. 32485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnerclass SANDBOX_EXPORT ResultExprImpl : public base::RefCounted<ResultExprImpl> { 32585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner public: 32685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ResultExprImpl() {} 32785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ErrorCode Compile(SandboxBPF* sb) const = 0; 32885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 32985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner protected: 33085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner virtual ~ResultExprImpl() {} 33185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 33285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner private: 33385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner friend class base::RefCounted<ResultExprImpl>; 33485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner DISALLOW_COPY_AND_ASSIGN(ResultExprImpl); 33585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner}; 33685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 33785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} // namespace internal 33885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 33985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 34085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerArg<T>::Arg(int num) 34185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner : num_(num), mask_(internal::DefaultMask(sizeof(T))) { 34285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 34385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 34485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Definition requires ArgEq to have been declared. Moved out-of-line 34585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// to minimize how much internal clutter users have to ignore while 34685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// reading the header documentation. 34785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// 34885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// Additionally, we use this helper member function to avoid linker errors 34985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// caused by defining operator== out-of-line. For a more detailed explanation, 35085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner// see http://www.parashift.com/c++-faq-lite/template-friends.html. 35185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 35285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerBoolExpr Arg<T>::EqualTo(T val) const { 35385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val)); 35485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 35585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 35685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 35785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerSANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) { 35885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner return Caser<T>(arg, Elser(Cons<Elser::Clause>::List())); 35985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 36085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 36185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 36285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerCaser<T> Caser<T>::Case(T value, ResultExpr result) const { 36385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner return SANDBOX_BPF_DSL_CASES((value), result); 36485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 36585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 36685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 36785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerCaser<T> Caser<T>::Cases(const std::vector<T>& values, 36885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner ResultExpr result) const { 36985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // Theoretically we could evaluate arg_ just once and emit a more efficient 37085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // dispatch table, but for now we simply translate into an equivalent 37185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner // If/ElseIf/Else chain. 37285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 37385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner typedef typename std::vector<T>::const_iterator Iter; 37485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner BoolExpr test = BoolConst(false); 37585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner for (Iter i = values.begin(), end = values.end(); i != end; ++i) { 37685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner test = test || (arg_ == *i); 37785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner } 37885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner return Caser<T>(arg_, elser_.ElseIf(test, result)); 37985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 38085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 38185125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turnertemplate <typename T> 38285125480c07e11d5dd98f69b71bded86ee903075David 'Digit' TurnerResultExpr Caser<T>::Default(ResultExpr result) const { 38385125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner return elser_.Else(result); 38485125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} 38585125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 38685125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} // namespace bpf_dsl 38785125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner} // namespace sandbox 38885125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner 38985125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_ 39085125480c07e11d5dd98f69b71bded86ee903075David 'Digit' Turner