Index: sandbox/linux/seccomp-bpf/sandbox_bpf.h |
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h |
index a7f2d5ff5c52e4739c695037ab113fca9b6267c5..1a9c1f8955d9f6dce3394a42114e7496533816a3 100644 |
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.h |
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h |
@@ -2,12 +2,12 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
-#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_ |
+#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_ |
#include <stdint.h> |
-#include "base/compiler_specific.h" |
+#include "base/files/scoped_file.h" |
#include "base/macros.h" |
#include "base/memory/scoped_ptr.h" |
#include "sandbox/linux/seccomp-bpf/codegen.h" |
@@ -19,67 +19,63 @@ namespace bpf_dsl { |
class Policy; |
} |
+// This class can be used to apply a syscall sandboxing policy expressed in a |
+// bpf_dsl::Policy object to the current process. |
+// Syscall sandboxing policies get inherited by subprocesses and, once applied, |
+// can never be removed for the lifetime of the process. |
class SANDBOX_EXPORT SandboxBPF { |
public: |
- enum SandboxStatus { |
- STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() |
- STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing |
- STATUS_UNAVAILABLE, // Currently unavailable but might work again later |
- STATUS_AVAILABLE, // Sandboxing is available but not currently active |
- STATUS_ENABLED // The sandbox is now active |
+ enum class SeccompLevel { |
+ SINGLE_THREADED, |
+ MULTI_THREADED, |
}; |
- // Depending on the level of kernel support, seccomp-bpf may require the |
- // process to be single-threaded in order to enable it. When calling |
- // StartSandbox(), the program should indicate whether or not the sandbox |
- // should try and engage with multi-thread support. |
- enum SandboxThreadState { |
- PROCESS_INVALID, |
- PROCESS_SINGLE_THREADED, // The program is currently single-threaded. |
- // Note: PROCESS_MULTI_THREADED requires experimental kernel support that |
- // has not been contributed to upstream Linux. |
- PROCESS_MULTI_THREADED, // The program may be multi-threaded. |
- }; |
- |
- // Constructors and destructors. |
+ // Ownership of |policy| is transfered here to the sandbox object. |
+ // nullptr is allowed for unit tests. |
+ explicit SandboxBPF(bpf_dsl::Policy* policy); |
// NOTE: Setting a policy and starting the sandbox is a one-way operation. |
- // The kernel does not provide any option for unloading a loaded |
- // sandbox. Strictly speaking, that means we should disallow calling |
- // the destructor, if StartSandbox() has ever been called. In practice, |
- // this makes it needlessly complicated to operate on "Sandbox" |
- // objects. So, we instead opted to allow object destruction. But it |
- // should be noted that during its lifetime, the object probably made |
- // irreversible state changes to the runtime environment. These changes |
- // stay in effect even after the destructor has been run. |
- SandboxBPF(); |
+ // The kernel does not provide any option for unloading a loaded sandbox. The |
+ // sandbox remains engaged even when the object is destructed. |
~SandboxBPF(); |
- // Checks whether a particular system call number is valid on the current |
- // architecture. E.g. on ARM there's a non-contiguous range of private |
- // system calls. |
- static bool IsValidSyscallNumber(int sysnum); |
- |
- // There are a lot of reasons why the Seccomp sandbox might not be available. |
- // This could be because the kernel does not support Seccomp mode, or it |
- // could be because another sandbox is already active. |
- // "proc_fd" should be a file descriptor for "/proc", or -1 if not |
- // provided by the caller. |
- static SandboxStatus SupportsSeccompSandbox(int proc_fd); |
- |
- // Determines if the kernel has support for the seccomp() system call to |
- // synchronize BPF filters across a thread group. |
- static SandboxStatus SupportsSeccompThreadFilterSynchronization(); |
+ // Detect if the kernel supports the specified seccomp level. |
+ // See StartSandbox() for a description of these. |
+ static bool SupportsSeccompSandbox(SeccompLevel level); |
+ |
+ // This is the main public entry point. It sets up the resources needed by |
+ // the sandbox, and enters Seccomp mode. |
+ // The calling process must provide a |level| to tell the sandbox which type |
+ // of kernel support it should engage. |
+ // SINGLE_THREADED will only sandbox the calling thread. Since it would be a |
+ // security risk, the sandbox will also check that the current process is |
+ // single threaded and crash if it isn't the case. |
+ // MULTI_THREADED requires more recent kernel support and allows to sandbox |
+ // all the threads of the current process. Be mindful of potential races, |
+ // with other threads using disallowed system calls either before or after |
+ // the sandbox is engaged. |
+ // |
+ // It is possible to stack multiple sandboxes by creating separate "Sandbox" |
+ // objects and calling "StartSandbox()" on each of them. Please note, that |
+ // this requires special care, though, as newly stacked sandboxes can never |
+ // relax restrictions imposed by earlier sandboxes. Furthermore, installing |
+ // a new policy requires making system calls, that might already be |
+ // disallowed. |
+ // Finally, stacking does add more kernel overhead than having a single |
+ // combined policy. So, it should only be used if there are no alternatives. |
+ bool StartSandbox(SeccompLevel level) WARN_UNUSED_RESULT; |
- // The sandbox needs to be able to access files in "/proc/self". If this |
- // directory is not accessible when "startSandbox()" gets called, the caller |
- // can provide an already opened file descriptor by calling "set_proc_fd()". |
+ // The sandbox needs to be able to access files in "/proc/self/task/". If |
+ // this directory is not accessible when "StartSandbox()" gets called, the |
+ // caller must provide an already opened file descriptor by calling |
+ // "SetProcTaskFd()". |
// The sandbox becomes the new owner of this file descriptor and will |
- // eventually close it when "StartSandbox()" executes. |
- void set_proc_fd(int proc_fd); |
+ // close it when "StartSandbox()" executes or when the sandbox object |
+ // disappears. |
+ void SetProcTaskFd(base::ScopedFD proc_task_fd); |
- // Set the BPF policy as |policy|. Ownership of |policy| is transfered here |
- // to the sandbox object. |
- void SetSandboxPolicy(bpf_dsl::Policy* policy); |
+ // Checks whether a particular system call number is valid on the current |
+ // architecture. |
+ static bool IsValidSyscallNumber(int sysnum); |
// UnsafeTraps require some syscalls to always be allowed. |
// This helper function returns true for these calls. |
@@ -95,21 +91,6 @@ class SANDBOX_EXPORT SandboxBPF { |
// directly suitable as a return value for a trap handler. |
static intptr_t ForwardSyscall(const struct arch_seccomp_data& args); |
- // This is the main public entry point. It finds all system calls that |
- // need rewriting, sets up the resources needed by the sandbox, and |
- // enters Seccomp mode. |
- // The calling process must specify its current SandboxThreadState, as a way |
- // to tell the sandbox which type of kernel support it should engage. |
- // It is possible to stack multiple sandboxes by creating separate "Sandbox" |
- // objects and calling "StartSandbox()" on each of them. Please note, that |
- // this requires special care, though, as newly stacked sandboxes can never |
- // relax restrictions imposed by earlier sandboxes. Furthermore, installing |
- // a new policy requires making system calls, that might already be |
- // disallowed. |
- // Finally, stacking does add more kernel overhead than having a single |
- // combined policy. So, it should only be used if there are no alternatives. |
- bool StartSandbox(SandboxThreadState thread_state) WARN_UNUSED_RESULT; |
- |
// Assembles a BPF filter program from the current policy. After calling this |
// function, you must not call any other sandboxing function. |
// Typically, AssembleFilter() is only used by unit tests and by sandbox |
@@ -121,34 +102,11 @@ class SANDBOX_EXPORT SandboxBPF { |
scoped_ptr<CodeGen::Program> AssembleFilter(bool force_verification); |
private: |
- // Get a file descriptor pointing to "/proc", if currently available. |
- int proc_fd() { return proc_fd_; } |
- |
- // Creates a subprocess and runs "code_in_sandbox" inside of the specified |
- // policy. The caller has to make sure that "this" has not yet been |
- // initialized with any other policies. |
- bool RunFunctionInPolicy(void (*code_in_sandbox)(), |
- scoped_ptr<bpf_dsl::Policy> policy); |
- |
- // Performs a couple of sanity checks to verify that the kernel supports the |
- // features that we need for successful sandboxing. |
- // The caller has to make sure that "this" has not yet been initialized with |
- // any other policies. |
- bool KernelSupportSeccompBPF(); |
- |
// Assembles and installs a filter based on the policy that has previously |
// been configured with SetSandboxPolicy(). |
void InstallFilter(bool must_sync_threads); |
- // Verify the correctness of a compiled program by comparing it against the |
- // current policy. This function should only ever be called by unit tests and |
- // by the sandbox internals. It should not be used by production code. |
- void VerifyProgram(const CodeGen::Program& program); |
- |
- static SandboxStatus status_; |
- |
- bool quiet_; |
- int proc_fd_; |
+ base::ScopedFD proc_task_fd_; |
bool sandbox_has_started_; |
scoped_ptr<bpf_dsl::Policy> policy_; |
@@ -157,4 +115,4 @@ class SANDBOX_EXPORT SandboxBPF { |
} // namespace sandbox |
-#endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
+#endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_ |