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