Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ | 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
| 6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ | 6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
| 7 | 7 |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| 11 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "sandbox/linux/seccomp-bpf/codegen.h" | 13 #include "sandbox/linux/seccomp-bpf/codegen.h" |
| 14 #include "sandbox/sandbox_export.h" | 14 #include "sandbox/sandbox_export.h" |
| 15 | 15 |
| 16 namespace sandbox { | 16 namespace sandbox { |
| 17 struct arch_seccomp_data; | 17 struct arch_seccomp_data; |
| 18 namespace bpf_dsl { | 18 namespace bpf_dsl { |
| 19 class Policy; | 19 class Policy; |
| 20 } | 20 } |
| 21 | 21 |
| 22 class SANDBOX_EXPORT SandboxBPF { | 22 class SANDBOX_EXPORT SandboxBPF { |
| 23 public: | 23 public: |
| 24 enum SandboxStatus { | 24 enum SeccompLevel { |
|
jln (very slow on Chromium)
2014/11/25 01:24:29
I considered making this an enum class, but since
mdempsky
2014/11/25 03:14:06
One solution might be to change "int SupportsSecco
jln (very slow on Chromium)
2014/11/25 03:36:01
I considered that, but in practice in content:: th
| |
| 25 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() | 25 SECCOMP_NONE = 0, |
| 26 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing | 26 SECCOMP_SINGLE_THREADED = 1 << 0, |
| 27 STATUS_UNAVAILABLE, // Currently unavailable but might work again later | 27 SECCOMP_MULTI_THREADED = 1 << 1, |
| 28 STATUS_AVAILABLE, // Sandboxing is available but not currently active | |
| 29 STATUS_ENABLED // The sandbox is now active | |
| 30 }; | |
| 31 | |
| 32 // Depending on the level of kernel support, seccomp-bpf may require the | |
| 33 // process to be single-threaded in order to enable it. When calling | |
| 34 // StartSandbox(), the program should indicate whether or not the sandbox | |
| 35 // should try and engage with multi-thread support. | |
| 36 enum SandboxThreadState { | |
| 37 PROCESS_INVALID, | |
| 38 PROCESS_SINGLE_THREADED, // The program is currently single-threaded. | |
| 39 // Note: PROCESS_MULTI_THREADED requires experimental kernel support that | |
| 40 // has not been contributed to upstream Linux. | |
| 41 PROCESS_MULTI_THREADED, // The program may be multi-threaded. | |
| 42 }; | 28 }; |
| 43 | 29 |
| 44 // Constructors and destructors. | 30 // Constructors and destructors. |
| 45 // NOTE: Setting a policy and starting the sandbox is a one-way operation. | 31 // NOTE: Setting a policy and starting the sandbox is a one-way operation. |
| 46 // The kernel does not provide any option for unloading a loaded | 32 // The kernel does not provide any option for unloading a loaded sandbox. The |
| 47 // sandbox. Strictly speaking, that means we should disallow calling | 33 // sandbox remains engaged even when the object is destructed. |
| 48 // the destructor, if StartSandbox() has ever been called. In practice, | |
| 49 // this makes it needlessly complicated to operate on "Sandbox" | |
| 50 // objects. So, we instead opted to allow object destruction. But it | |
| 51 // should be noted that during its lifetime, the object probably made | |
| 52 // irreversible state changes to the runtime environment. These changes | |
| 53 // stay in effect even after the destructor has been run. | |
| 54 SandboxBPF(); | 34 SandboxBPF(); |
| 55 ~SandboxBPF(); | 35 ~SandboxBPF(); |
| 56 | 36 |
| 57 // Checks whether a particular system call number is valid on the current | 37 // Checks whether a particular system call number is valid on the current |
| 58 // architecture. E.g. on ARM there's a non-contiguous range of private | 38 // architecture. E.g. on ARM there's a non-contiguous range of private |
| 59 // system calls. | 39 // system calls. |
| 60 static bool IsValidSyscallNumber(int sysnum); | 40 static bool IsValidSyscallNumber(int sysnum); |
| 61 | 41 |
| 62 // Detect if the kernel supports the seccomp sandbox. The result of calling | 42 // Detect if the kernel supports the seccomp sandbox. Returns a bitmask |
| 63 // this function will be cached. The first time this function is called, the | 43 // of values in SeccompLevel. |
| 64 // running process must be unsandboxed (able to use /proc) and monothreaded. | 44 static int SupportsSeccompSandbox(); |
| 65 static SandboxStatus SupportsSeccompSandbox(); | |
| 66 | |
| 67 // Determines if the kernel has support for the seccomp() system call to | |
| 68 // synchronize BPF filters across a thread group. | |
| 69 static SandboxStatus SupportsSeccompThreadFilterSynchronization(); | |
| 70 | 45 |
| 71 // The sandbox needs to be able to access files in "/proc/self/tasks/". If | 46 // The sandbox needs to be able to access files in "/proc/self/tasks/". If |
| 72 // this | 47 // this |
| 73 // directory is not accessible when "startSandbox()" gets called, the caller | 48 // directory is not accessible when "startSandbox()" gets called, the caller |
| 74 // must provide an already opened file descriptor by calling | 49 // must provide an already opened file descriptor by calling |
| 75 // "set_proc_task_fd()". The sandbox becomes the new owner of this file | 50 // "set_proc_task_fd()". The sandbox becomes the new owner of this file |
| 76 // descriptor and will eventually close it when "StartSandbox()" executes. | 51 // descriptor and will eventually close it when "StartSandbox()" executes. |
| 77 void set_proc_task_fd(int proc_task_fd); | 52 void set_proc_task_fd(int proc_task_fd); |
| 78 | 53 |
| 79 // Set the BPF policy as |policy|. Ownership of |policy| is transfered here | 54 // Set the BPF policy as |policy|. Ownership of |policy| is transfered here |
| 80 // to the sandbox object. | 55 // to the sandbox object. |
| 81 void SetSandboxPolicy(bpf_dsl::Policy* policy); | 56 void SetSandboxPolicy(bpf_dsl::Policy* policy); |
| 82 | 57 |
| 83 // UnsafeTraps require some syscalls to always be allowed. | 58 // UnsafeTraps require some syscalls to always be allowed. |
| 84 // This helper function returns true for these calls. | 59 // This helper function returns true for these calls. |
| 85 static bool IsRequiredForUnsafeTrap(int sysno); | 60 static bool IsRequiredForUnsafeTrap(int sysno); |
| 86 | 61 |
| 87 // From within an UnsafeTrap() it is often useful to be able to execute | 62 // From within an UnsafeTrap() it is often useful to be able to execute |
| 88 // the system call that triggered the trap. The ForwardSyscall() method | 63 // the system call that triggered the trap. The ForwardSyscall() method |
| 89 // makes this easy. It is more efficient than calling glibc's syscall() | 64 // makes this easy. It is more efficient than calling glibc's syscall() |
| 90 // function, as it avoid the extra round-trip to the signal handler. And | 65 // function, as it avoid the extra round-trip to the signal handler. And |
| 91 // it automatically does the correct thing to report kernel-style error | 66 // it automatically does the correct thing to report kernel-style error |
| 92 // conditions, rather than setting errno. See the comments for TrapFnc for | 67 // conditions, rather than setting errno. See the comments for TrapFnc for |
| 93 // details. In other words, the return value from ForwardSyscall() is | 68 // details. In other words, the return value from ForwardSyscall() is |
| 94 // directly suitable as a return value for a trap handler. | 69 // directly suitable as a return value for a trap handler. |
| 95 static intptr_t ForwardSyscall(const struct arch_seccomp_data& args); | 70 static intptr_t ForwardSyscall(const struct arch_seccomp_data& args); |
| 96 | 71 |
| 97 // This is the main public entry point. It finds all system calls that | 72 // This is the main public entry point. It sets up the resources needed by |
| 98 // need rewriting, sets up the resources needed by the sandbox, and | 73 // the sandbox, and enters Seccomp mode. |
| 99 // enters Seccomp mode. | 74 // The calling process must a |seccomp_level| to tell the sandbox which type |
| 100 // The calling process must specify its current SandboxThreadState, as a way | 75 // of kernel support it should engage. |
| 101 // to tell the sandbox which type of kernel support it should engage. | |
| 102 // It is possible to stack multiple sandboxes by creating separate "Sandbox" | 76 // It is possible to stack multiple sandboxes by creating separate "Sandbox" |
| 103 // objects and calling "StartSandbox()" on each of them. Please note, that | 77 // objects and calling "StartSandbox()" on each of them. Please note, that |
| 104 // this requires special care, though, as newly stacked sandboxes can never | 78 // this requires special care, though, as newly stacked sandboxes can never |
| 105 // relax restrictions imposed by earlier sandboxes. Furthermore, installing | 79 // relax restrictions imposed by earlier sandboxes. Furthermore, installing |
| 106 // a new policy requires making system calls, that might already be | 80 // a new policy requires making system calls, that might already be |
| 107 // disallowed. | 81 // disallowed. |
| 108 // Finally, stacking does add more kernel overhead than having a single | 82 // Finally, stacking does add more kernel overhead than having a single |
| 109 // combined policy. So, it should only be used if there are no alternatives. | 83 // combined policy. So, it should only be used if there are no alternatives. |
| 110 bool StartSandbox(SandboxThreadState thread_state) WARN_UNUSED_RESULT; | 84 bool StartSandbox(SeccompLevel seccomp_level) WARN_UNUSED_RESULT; |
| 111 | 85 |
| 112 // Assembles a BPF filter program from the current policy. After calling this | 86 // Assembles a BPF filter program from the current policy. After calling this |
| 113 // function, you must not call any other sandboxing function. | 87 // function, you must not call any other sandboxing function. |
| 114 // Typically, AssembleFilter() is only used by unit tests and by sandbox | 88 // Typically, AssembleFilter() is only used by unit tests and by sandbox |
| 115 // internals. It should not be used by production code. | 89 // internals. It should not be used by production code. |
| 116 // For performance reasons, we normally only run the assembled BPF program | 90 // For performance reasons, we normally only run the assembled BPF program |
| 117 // through the verifier, iff the program was built in debug mode. | 91 // through the verifier, iff the program was built in debug mode. |
| 118 // But by setting "force_verification", the caller can request that the | 92 // But by setting "force_verification", the caller can request that the |
| 119 // verifier is run unconditionally. This is useful for unittests. | 93 // verifier is run unconditionally. This is useful for unittests. |
| 120 scoped_ptr<CodeGen::Program> AssembleFilter(bool force_verification); | 94 scoped_ptr<CodeGen::Program> AssembleFilter(bool force_verification); |
| 121 | 95 |
| 122 private: | 96 private: |
| 123 // Get a file descriptor pointing to "/proc", if currently available. | 97 // Get a file descriptor pointing to "/proc", if currently available. |
| 124 int proc_task_fd() { return proc_task_fd_; } | 98 int proc_task_fd() { return proc_task_fd_; } |
| 125 | 99 |
| 126 // Creates a subprocess and runs "code_in_sandbox" inside of the specified | 100 // Creates a subprocess and runs "code_in_sandbox" inside of the specified |
| 127 // policy. The caller has to make sure that "this" has not yet been | 101 // policy. The caller has to make sure that "this" has not yet been |
| 128 // initialized with any other policies. | 102 // initialized with any other policies. |
| 129 bool RunFunctionInPolicy(void (*code_in_sandbox)(), | 103 bool RunFunctionInPolicy(void (*code_in_sandbox)(), |
| 130 scoped_ptr<bpf_dsl::Policy> policy); | 104 scoped_ptr<bpf_dsl::Policy> policy); |
| 131 | 105 |
| 132 // Performs a couple of sanity checks to verify that the kernel supports the | |
| 133 // features that we need for successful sandboxing. | |
| 134 // The caller has to make sure that "this" has not yet been initialized with | |
| 135 // any other policies. | |
| 136 bool KernelSupportSeccompBPF(); | |
| 137 | |
| 138 // Assembles and installs a filter based on the policy that has previously | 106 // Assembles and installs a filter based on the policy that has previously |
| 139 // been configured with SetSandboxPolicy(). | 107 // been configured with SetSandboxPolicy(). |
| 140 void InstallFilter(bool must_sync_threads); | 108 void InstallFilter(bool must_sync_threads); |
| 141 | 109 |
| 142 // Verify the correctness of a compiled program by comparing it against the | 110 // Verify the correctness of a compiled program by comparing it against the |
| 143 // current policy. This function should only ever be called by unit tests and | 111 // current policy. This function should only ever be called by unit tests and |
| 144 // by the sandbox internals. It should not be used by production code. | 112 // by the sandbox internals. It should not be used by production code. |
| 145 void VerifyProgram(const CodeGen::Program& program); | 113 void VerifyProgram(const CodeGen::Program& program); |
| 146 | 114 |
| 147 static SandboxStatus status_; | |
| 148 | |
| 149 bool quiet_; | 115 bool quiet_; |
| 150 int proc_task_fd_; | 116 int proc_task_fd_; |
| 151 bool sandbox_has_started_; | 117 bool sandbox_has_started_; |
| 152 scoped_ptr<bpf_dsl::Policy> policy_; | 118 scoped_ptr<bpf_dsl::Policy> policy_; |
| 153 | 119 |
| 154 DISALLOW_COPY_AND_ASSIGN(SandboxBPF); | 120 DISALLOW_COPY_AND_ASSIGN(SandboxBPF); |
| 155 }; | 121 }; |
| 156 | 122 |
| 157 } // namespace sandbox | 123 } // namespace sandbox |
| 158 | 124 |
| 159 #endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ | 125 #endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__ |
| OLD | NEW |