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