1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_ 6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_ 7 8 #include <stdint.h> 9 10 #include "base/files/scoped_file.h" 11 #include "base/macros.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "sandbox/linux/bpf_dsl/codegen.h" 14 #include "sandbox/sandbox_export.h" 15 16 namespace sandbox { 17 struct arch_seccomp_data; 18 namespace bpf_dsl { 19 class Policy; 20 } 21 22 // This class can be used to apply a syscall sandboxing policy expressed in a 23 // bpf_dsl::Policy object to the current process. 24 // Syscall sandboxing policies get inherited by subprocesses and, once applied, 25 // can never be removed for the lifetime of the process. 26 class SANDBOX_EXPORT SandboxBPF { 27 public: 28 enum class SeccompLevel { 29 SINGLE_THREADED, 30 MULTI_THREADED, 31 }; 32 33 // Ownership of |policy| is transfered here to the sandbox object. 34 // nullptr is allowed for unit tests. 35 explicit SandboxBPF(bpf_dsl::Policy* policy); 36 // NOTE: Setting a policy and starting the sandbox is a one-way operation. 37 // The kernel does not provide any option for unloading a loaded sandbox. The 38 // sandbox remains engaged even when the object is destructed. 39 ~SandboxBPF(); 40 41 // Detect if the kernel supports the specified seccomp level. 42 // See StartSandbox() for a description of these. 43 static bool SupportsSeccompSandbox(SeccompLevel level); 44 45 // This is the main public entry point. It sets up the resources needed by 46 // the sandbox, and enters Seccomp mode. 47 // The calling process must provide a |level| to tell the sandbox which type 48 // of kernel support it should engage. 49 // SINGLE_THREADED will only sandbox the calling thread. Since it would be a 50 // security risk, the sandbox will also check that the current process is 51 // single threaded and crash if it isn't the case. 52 // MULTI_THREADED requires more recent kernel support and allows to sandbox 53 // all the threads of the current process. Be mindful of potential races, 54 // with other threads using disallowed system calls either before or after 55 // the sandbox is engaged. 56 // 57 // It is possible to stack multiple sandboxes by creating separate "Sandbox" 58 // objects and calling "StartSandbox()" on each of them. Please note, that 59 // this requires special care, though, as newly stacked sandboxes can never 60 // relax restrictions imposed by earlier sandboxes. Furthermore, installing 61 // a new policy requires making system calls, that might already be 62 // disallowed. 63 // Finally, stacking does add more kernel overhead than having a single 64 // combined policy. So, it should only be used if there are no alternatives. 65 bool StartSandbox(SeccompLevel level) WARN_UNUSED_RESULT; 66 67 // The sandbox needs to be able to access files in "/proc/self/". If 68 // this directory is not accessible when "StartSandbox()" gets called, the 69 // caller must provide an already opened file descriptor by calling 70 // "SetProcFd()". 71 // The sandbox becomes the new owner of this file descriptor and will 72 // close it when "StartSandbox()" executes or when the sandbox object 73 // disappears. 74 void SetProcFd(base::ScopedFD proc_fd); 75 76 // Checks whether a particular system call number is valid on the current 77 // architecture. 78 static bool IsValidSyscallNumber(int sysnum); 79 80 // UnsafeTraps require some syscalls to always be allowed. 81 // This helper function returns true for these calls. 82 static bool IsRequiredForUnsafeTrap(int sysno); 83 84 // From within an UnsafeTrap() it is often useful to be able to execute 85 // the system call that triggered the trap. The ForwardSyscall() method 86 // makes this easy. It is more efficient than calling glibc's syscall() 87 // function, as it avoid the extra round-trip to the signal handler. And 88 // it automatically does the correct thing to report kernel-style error 89 // conditions, rather than setting errno. See the comments for TrapFnc for 90 // details. In other words, the return value from ForwardSyscall() is 91 // directly suitable as a return value for a trap handler. 92 static intptr_t ForwardSyscall(const struct arch_seccomp_data& args); 93 94 private: 95 friend class SandboxBPFTestRunner; 96 97 // Assembles a BPF filter program from the current policy. After calling this 98 // function, you must not call any other sandboxing function. 99 CodeGen::Program AssembleFilter(); 100 101 // Assembles and installs a filter based on the policy that has previously 102 // been configured with SetSandboxPolicy(). 103 void InstallFilter(bool must_sync_threads); 104 105 base::ScopedFD proc_fd_; 106 bool sandbox_has_started_; 107 scoped_ptr<bpf_dsl::Policy> policy_; 108 109 DISALLOW_COPY_AND_ASSIGN(SandboxBPF); 110 }; 111 112 } // namespace sandbox 113 114 #endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_ 115