diff options
Diffstat (limited to 'chromium/sandbox/linux/seccomp-bpf')
-rw-r--r-- | chromium/sandbox/linux/seccomp-bpf/bpf_tests.h | 2 | ||||
-rw-r--r-- | chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc | 88 | ||||
-rw-r--r-- | chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h | 7 | ||||
-rw-r--r-- | chromium/sandbox/linux/seccomp-bpf/trap.cc | 6 | ||||
-rw-r--r-- | chromium/sandbox/linux/seccomp-bpf/trap.h | 2 |
5 files changed, 84 insertions, 21 deletions
diff --git a/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h b/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h index 8b2b12afd8f..5e35e997d72 100644 --- a/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h +++ b/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h @@ -7,7 +7,7 @@ #include <memory> -#include "base/logging.h" +#include "base/check.h" #include "base/macros.h" #include "build/build_config.h" #include "sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h" diff --git a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc index 639cd15e07f..3d7bc172f79 100644 --- a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc +++ b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc @@ -14,6 +14,7 @@ #include "base/check_op.h" #include "base/compiler_specific.h" #include "base/files/scoped_file.h" +#include "base/logging.h" #include "base/macros.h" #include "base/notreached.h" #include "base/posix/eintr_wrapper.h" @@ -32,6 +33,7 @@ #include "sandbox/linux/system_headers/linux_filter.h" #include "sandbox/linux/system_headers/linux_seccomp.h" #include "sandbox/linux/system_headers/linux_syscalls.h" +#include "sandbox/sandbox_buildflags.h" namespace sandbox { @@ -76,16 +78,13 @@ bool KernelHasLGBug() { return false; } -// Check if the kernel supports seccomp-filter via the seccomp system call -// and the TSYNC feature to enable seccomp on all threads. -bool KernelSupportsSeccompTsync() { +bool KernelSupportsSeccompFlags(unsigned int flags) { if (KernelHasLGBug()) { return false; } errno = 0; - const int rv = - sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr); + const int rv = sys_seccomp(SECCOMP_SET_MODE_FILTER, flags, nullptr); if (rv == -1 && errno == EFAULT) { return true; @@ -96,6 +95,20 @@ bool KernelSupportsSeccompTsync() { return false; } +// Check if the kernel supports seccomp-filter via the seccomp system call +// and the TSYNC feature to enable seccomp on all threads. +bool KernelSupportsSeccompTsync() { + return KernelSupportsSeccompFlags(SECCOMP_FILTER_FLAG_TSYNC); +} + +#if BUILDFLAG(DISABLE_SECCOMP_SSBD) +// Check if the kernel supports seccomp-filter via the seccomp system call and +// without spec flaw mitigation. +bool KernelSupportSeccompSpecAllow() { + return KernelSupportsSeccompFlags(SECCOMP_FILTER_FLAG_SPEC_ALLOW); +} +#endif + uint64_t EscapePC() { intptr_t rv = Syscall::Call(-1); if (rv == -1 && errno == ENOSYS) { @@ -170,8 +183,7 @@ bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) { } // Install the filters. - InstallFilter(supports_tsync || - seccomp_level == SeccompLevel::MULTI_THREADED); + InstallFilter(seccomp_level == SeccompLevel::MULTI_THREADED); return true; } @@ -239,23 +251,67 @@ void SandboxBPF::InstallFilter(bool must_sync_threads) { SANDBOX_DIE("Kernel refuses to enable no-new-privs"); } - // Install BPF filter program. If the thread state indicates multi-threading - // support, then the kernel hass the seccomp system call. Otherwise, fall - // back on prctl, which requires the process to be single-threaded. + // Install BPF filter program. If the thread state indicates that tsync is + // necessary or SECCOMP_FILTER_FLAG_SPEC_ALLOW is supported, then the kernel + // has the seccomp system call. Otherwise, fall back on prctl, which requires + // the process to be single-threaded. + unsigned int seccomp_filter_flags = 0; if (must_sync_threads) { - int rv = - sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog); - if (rv) { - SANDBOX_DIE( - "Kernel refuses to turn on and synchronize threads for BPF filters"); - } + seccomp_filter_flags |= SECCOMP_FILTER_FLAG_TSYNC; +#if BUILDFLAG(DISABLE_SECCOMP_SSBD) + // Seccomp will disable indirect branch speculation and speculative store + // bypass simultaneously. To only opt-out SSBD, following steps are needed + // 1. Disable IBSpec with prctl + // 2. Call seccomp with SECCOMP_FILTER_FLAG_SPEC_ALLOW + // As prctl provide a per thread control of the speculation feature, only + // opt-out SSBD when process is single-threaded and tsync is not necessary. + } else if (KernelSupportSeccompSpecAllow()) { + seccomp_filter_flags |= SECCOMP_FILTER_FLAG_SPEC_ALLOW; + DisableIBSpec(); +#endif } else { if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { SANDBOX_DIE("Kernel refuses to turn on BPF filters"); } + sandbox_has_started_ = true; + return; } + int rv = sys_seccomp(SECCOMP_SET_MODE_FILTER, seccomp_filter_flags, &prog); + if (rv) { + SANDBOX_DIE("Kernel refuses to turn on BPF filters"); + } sandbox_has_started_ = true; } +void SandboxBPF::DisableIBSpec() { + // Test if the per-task control of the mitigation is available. If + // PR_SPEC_PRCTL is set, then the per-task control of the mitigation is + // available. If not set, prctl(PR_SET_SPECULATION_CTRL) for the speculation + // misfeature will fail. + const int rv = + prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, 0, 0, 0); + // Kernel control of the speculation misfeature is not supported. + if (rv < 0) { + return; + } + + if (!(rv & PR_SPEC_PRCTL)) { + DLOG(INFO) << "Indirect branch speculation can not be controled by prctl." + << rv; + return; + } + + if (rv & PR_SPEC_FORCE_DISABLE) { + DLOG(INFO) << "Indirect branch speculation is already force disabled." + << rv; + return; + } + + if (prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, + PR_SPEC_FORCE_DISABLE, 0, 0)) { + DPLOG(INFO) << "Kernel failed to force disable indirect branch speculation"; + } +} + } // namespace sandbox diff --git a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h index 282852992b2..98475061bf2 100644 --- a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h +++ b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h @@ -101,6 +101,13 @@ class SANDBOX_EXPORT SandboxBPF { // been configured with SetSandboxPolicy(). void InstallFilter(bool must_sync_threads); + // Disable indirect branch speculation by prctl. This will be done by + // seccomp if SECCOMP_FILTER_FLAG_SPEC_ALLOW is not set. Seccomp will + // disable indirect branch speculation and speculative store bypass + // simultaneously. We use prctl in supplement to control the speculation + // features separately. + void DisableIBSpec(); + base::ScopedFD proc_fd_; bool sandbox_has_started_; std::unique_ptr<bpf_dsl::Policy> policy_; diff --git a/chromium/sandbox/linux/seccomp-bpf/trap.cc b/chromium/sandbox/linux/seccomp-bpf/trap.cc index 9884be8bb2c..f5b86a73ac7 100644 --- a/chromium/sandbox/linux/seccomp-bpf/trap.cc +++ b/chromium/sandbox/linux/seccomp-bpf/trap.cc @@ -60,7 +60,7 @@ bool GetIsInSigHandler(const ucontext_t* ctx) { void SetIsInSigHandler() { sigset_t mask; if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS) || - sandbox::sys_sigprocmask(LINUX_SIG_BLOCK, &mask, NULL)) { + sandbox::sys_sigprocmask(LINUX_SIG_BLOCK, &mask, nullptr)) { SANDBOX_DIE("Failed to block SIGBUS"); } } @@ -77,7 +77,7 @@ bool IsDefaultSignalAction(const struct sigaction& sa) { namespace sandbox { Trap::Trap() - : trap_array_(NULL), + : trap_array_(nullptr), trap_array_size_(0), trap_array_capacity_(0), has_unsafe_traps_(false) { @@ -104,7 +104,7 @@ Trap::Trap() // Unmask SIGSYS sigset_t mask; if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS) || - sys_sigprocmask(LINUX_SIG_UNBLOCK, &mask, NULL)) { + sys_sigprocmask(LINUX_SIG_UNBLOCK, &mask, nullptr)) { SANDBOX_DIE("Failed to configure SIGSYS handler"); } } diff --git a/chromium/sandbox/linux/seccomp-bpf/trap.h b/chromium/sandbox/linux/seccomp-bpf/trap.h index a73d2064b47..6568a9b7b40 100644 --- a/chromium/sandbox/linux/seccomp-bpf/trap.h +++ b/chromium/sandbox/linux/seccomp-bpf/trap.h @@ -41,7 +41,7 @@ class SANDBOX_EXPORT Trap : public bpf_dsl::TrapRegistry { private: struct TrapKey { - TrapKey() : fnc(NULL), aux(NULL), safe(false) {} + TrapKey() : fnc(nullptr), aux(nullptr), safe(false) {} TrapKey(TrapFnc f, const void* a, bool s) : fnc(f), aux(a), safe(s) {} TrapFnc fnc; const void* aux; |