15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdint.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <set>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/compiler_specific.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/errorcode.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "sandbox/linux/seccomp-bpf/trap.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "sandbox/sandbox_export.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistruct sock_filter;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace sandbox {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CodeGen;
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class SandboxBPFPolicy;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SandboxUnittestHelper;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Instruction;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass SANDBOX_EXPORT SandboxBPF {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum SandboxStatus {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATUS_UNKNOWN,      // Status prior to calling supportsSeccompSandbox()
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATUS_UNSUPPORTED,  // The kernel does not appear to support sandboxing
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATUS_UNAVAILABLE,  // Currently unavailable but might work again later
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATUS_AVAILABLE,    // Sandboxing is available but not currently active
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATUS_ENABLED       // The sandbox is now active
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Depending on the level of kernel support, seccomp-bpf may require the
39c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // process to be single-threaded in order to enable it. When calling
40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // StartSandbox(), the program should indicate whether or not the sandbox
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // should try and engage with multi-thread support.
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  enum SandboxThreadState {
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    PROCESS_INVALID,
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    PROCESS_SINGLE_THREADED,  // The program is currently single-threaded.
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // Note: PROCESS_MULTI_THREADED requires experimental kernel support that
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // has not been contributed to upstream Linux.
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    PROCESS_MULTI_THREADED,   // The program may be multi-threaded.
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // A vector of BPF instructions that need to be installed as a filter
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // program in the kernel.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::vector<struct sock_filter> Program;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Constructors and destructors.
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NOTE: Setting a policy and starting the sandbox is a one-way operation.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       The kernel does not provide any option for unloading a loaded
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       sandbox. Strictly speaking, that means we should disallow calling
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       the destructor, if StartSandbox() has ever been called. In practice,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       this makes it needlessly complicated to operate on "Sandbox"
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       objects. So, we instead opted to allow object destruction. But it
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       should be noted that during its lifetime, the object probably made
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       irreversible state changes to the runtime environment. These changes
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //       stay in effect even after the destructor has been run.
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SandboxBPF();
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ~SandboxBPF();
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Checks whether a particular system call number is valid on the current
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // architecture. E.g. on ARM there's a non-contiguous range of private
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // system calls.
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool IsValidSyscallNumber(int sysnum);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There are a lot of reasons why the Seccomp sandbox might not be available.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This could be because the kernel does not support Seccomp mode, or it
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // could be because another sandbox is already active.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "proc_fd" should be a file descriptor for "/proc", or -1 if not
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // provided by the caller.
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static SandboxStatus SupportsSeccompSandbox(int proc_fd);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Determines if the kernel has support for the seccomp() system call to
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // synchronize BPF filters across a thread group.
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static SandboxStatus SupportsSeccompThreadFilterSynchronization();
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The sandbox needs to be able to access files in "/proc/self". If this
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // directory is not accessible when "startSandbox()" gets called, the caller
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // can provide an already opened file descriptor by calling "set_proc_fd()".
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The sandbox becomes the new owner of this file descriptor and will
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // eventually close it when "StartSandbox()" executes.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void set_proc_fd(int proc_fd);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Set the BPF policy as |policy|. Ownership of |policy| is transfered here
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // to the sandbox object.
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void SetSandboxPolicy(SandboxBPFPolicy* policy);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can use ErrorCode to request calling of a trap handler. This method
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // performs the required wrapping of the callback function into an
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ErrorCode object.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The "aux" field can carry a pointer to arbitrary data. See EvaluateSyscall
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // for a description of how to pass data from SetSandboxPolicy() to a Trap()
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handler.
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static ErrorCode Trap(Trap::TrapFnc fnc, const void* aux);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Calls a user-space trap handler and disables all sandboxing for system
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // calls made from this trap handler.
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This feature is available only if explicitly enabled by the user having
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // set the CHROME_SANDBOX_DEBUGGING environment variable.
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns an ET_INVALID ErrorCode, if called when not enabled.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NOTE: This feature, by definition, disables all security features of
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   the sandbox. It should never be used in production, but it can be
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   very useful to diagnose code that is incompatible with the sandbox.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   If even a single system call returns "UnsafeTrap", the security of
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   entire sandbox should be considered compromised.
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static ErrorCode UnsafeTrap(Trap::TrapFnc fnc, const void* aux);
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // UnsafeTraps require some syscalls to always be allowed.
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // This helper function returns true for these calls.
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static bool IsRequiredForUnsafeTrap(int sysno);
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // From within an UnsafeTrap() it is often useful to be able to execute
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the system call that triggered the trap. The ForwardSyscall() method
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // makes this easy. It is more efficient than calling glibc's syscall()
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // function, as it avoid the extra round-trip to the signal handler. And
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it automatically does the correct thing to report kernel-style error
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // conditions, rather than setting errno. See the comments for TrapFnc for
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // details. In other words, the return value from ForwardSyscall() is
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // directly suitable as a return value for a trap handler.
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We can also use ErrorCode to request evaluation of a conditional
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // statement based on inspection of system call parameters.
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This method wrap an ErrorCode object around the conditional statement.
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // to "value"; if equal, then "passed" will be returned, otherwise "failed".
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If it is outside this range, the sandbox treats the system call just
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the same as any other ABI violation (i.e. it aborts with an error
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // message).
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ErrorCode CondMaskedEqual(int argno,
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            ErrorCode::ArgType is_32bit,
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            uint64_t mask,
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            uint64_t value,
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            const ErrorCode& passed,
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            const ErrorCode& failed);
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Legacy variant of CondMaskedEqual that supports a few comparison
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // operations, which get converted into masked-equality comparisons.
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ErrorCode Cond(int argno,
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 ErrorCode::ArgType is_32bit,
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 ErrorCode::Operation op,
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 uint64_t value,
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 const ErrorCode& passed,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 const ErrorCode& failed);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Kill the program and print an error message.
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static ErrorCode Kill(const char* msg);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the main public entry point. It finds all system calls that
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need rewriting, sets up the resources needed by the sandbox, and
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // enters Seccomp mode.
159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // The calling process must specify its current SandboxThreadState, as a way
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // to tell the sandbox which type of kernel support it should engage.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It is possible to stack multiple sandboxes by creating separate "Sandbox"
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // objects and calling "StartSandbox()" on each of them. Please note, that
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // this requires special care, though, as newly stacked sandboxes can never
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // relax restrictions imposed by earlier sandboxes. Furthermore, installing
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // a new policy requires making system calls, that might already be
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // disallowed.
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Finally, stacking does add more kernel overhead than having a single
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // combined policy. So, it should only be used if there are no alternatives.
169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool StartSandbox(SandboxThreadState thread_state) WARN_UNUSED_RESULT;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Assembles a BPF filter program from the current policy. After calling this
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // function, you must not call any other sandboxing function.
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Typically, AssembleFilter() is only used by unit tests and by sandbox
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // internals. It should not be used by production code.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For performance reasons, we normally only run the assembled BPF program
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // through the verifier, iff the program was built in debug mode.
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // But by setting "force_verification", the caller can request that the
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // verifier is run unconditionally. This is useful for unittests.
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Program* AssembleFilter(bool force_verification);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the fatal ErrorCode that is used to indicate that somebody
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // attempted to pass a 64bit value in a 32bit system call argument.
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This method is primarily needed for testing purposes.
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  static ErrorCode Unexpected64bitArgument();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class CodeGen;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class SandboxUnittestHelper;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class ErrorCode;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Range {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Range(uint32_t f, uint32_t t, const ErrorCode& e)
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        : from(f), to(t), err(e) {}
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    uint32_t from, to;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ErrorCode err;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::vector<Range> Ranges;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<uint32_t, ErrorCode> ErrMap;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef std::set<ErrorCode, struct ErrorCode::LessThan> Conds;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Used by CondExpressionHalf to track which half of the argument it's
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // emitting instructions for.
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  enum ArgHalf {
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LowerHalf,
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UpperHalf,
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get a file descriptor pointing to "/proc", if currently available.
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int proc_fd() { return proc_fd_; }
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates a subprocess and runs "code_in_sandbox" inside of the specified
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // policy. The caller has to make sure that "this" has not yet been
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // initialized with any other policies.
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool RunFunctionInPolicy(void (*code_in_sandbox)(),
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           scoped_ptr<SandboxBPFPolicy> policy);
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Performs a couple of sanity checks to verify that the kernel supports the
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // features that we need for successful sandboxing.
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The caller has to make sure that "this" has not yet been initialized with
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any other policies.
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool KernelSupportSeccompBPF();
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Verify that the current policy passes some basic sanity checks.
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void PolicySanityChecks(SandboxBPFPolicy* policy);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Assembles and installs a filter based on the policy that has previously
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // been configured with SetSandboxPolicy().
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void InstallFilter(bool must_sync_threads);
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Compile the configured policy into a complete instruction sequence.
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // (See MaybeAddEscapeHatch for |has_unsafe_traps|.)
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Instruction* CompilePolicy(CodeGen* gen, bool* has_unsafe_traps);
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Return an instruction sequence that checks the
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // arch_seccomp_data's "arch" field is valid, and then passes
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // control to |passed| if so.
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Instruction* CheckArch(CodeGen* gen, Instruction* passed);
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If the |rest| instruction sequence contains any unsafe traps,
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // then sets |*has_unsafe_traps| to true and returns an instruction
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // sequence that allows all system calls from Syscall::Call(), and
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // otherwise passes control to |rest|.
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If |rest| contains no unsafe traps, then |rest| is returned
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // directly and |*has_unsafe_traps| is set to false.
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Instruction* MaybeAddEscapeHatch(CodeGen* gen,
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   bool* has_unsafe_traps,
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   Instruction* rest);
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Return an instruction sequence that loads and checks the system
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // call number, performs a binary search, and then dispatches to an
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // appropriate instruction sequence compiled from the current
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // policy.
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Instruction* DispatchSyscall(CodeGen* gen);
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Return an instruction sequence that checks the system call number
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // (expected to be loaded in register A) and if valid, passes
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // control to |passed| (with register A still valid).
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Instruction* CheckSyscallNumber(CodeGen* gen, Instruction* passed);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Verify the correctness of a compiled program by comparing it against the
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // current policy. This function should only ever be called by unit tests and
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // by the sandbox internals. It should not be used by production code.
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void VerifyProgram(const Program& program, bool has_unsafe_traps);
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Finds all the ranges of system calls that need to be handled. Ranges are
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // sorted in ascending order of system call numbers. There are no gaps in the
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ranges. System calls with identical ErrorCodes are coalesced into a single
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // range.
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void FindRanges(Ranges* ranges);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns a BPF program snippet that implements a jump table for the
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // given range of system call numbers. This function runs recursively.
274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Instruction* AssembleJumpTable(CodeGen* gen,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 Ranges::const_iterator start,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 Ranges::const_iterator stop);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns a BPF program snippet that makes the BPF filter program exit
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // with the given ErrorCode "err". N.B. the ErrorCode may very well be a
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // conditional expression; if so, this function will recursively call
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // CondExpression() and possibly RetExpression() to build a complex set of
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // instructions.
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Instruction* RetExpression(CodeGen* gen, const ErrorCode& err);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns a BPF program that evaluates the conditional expression in
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // "cond" and returns the appropriate value from the BPF filter program.
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This function recursively calls RetExpression(); it should only ever be
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // called from RetExpression().
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Instruction* CondExpression(CodeGen* gen, const ErrorCode& cond);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Returns a BPF program that evaluates half of a conditional expression;
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // it should only ever be called from CondExpression().
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Instruction* CondExpressionHalf(CodeGen* gen,
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  const ErrorCode& cond,
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  ArgHalf half,
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  Instruction* passed,
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  Instruction* failed);
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SandboxStatus status_;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool quiet_;
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int proc_fd_;
303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<const SandboxBPFPolicy> policy_;
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Conds* conds_;
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool sandbox_has_started_;
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace sandbox
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
313