summaryrefslogtreecommitdiff
path: root/chromium/sandbox
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/sandbox
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-c30a6232df03e1efbd9f3b226777b07e087a1122.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/sandbox')
-rw-r--r--chromium/sandbox/BUILD.gn5
-rw-r--r--chromium/sandbox/features.gni5
-rw-r--r--chromium/sandbox/linux/BUILD.gn1
-rw-r--r--chromium/sandbox/linux/bpf_dsl/policy_compiler.cc1
-rw-r--r--chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc36
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/bpf_tests.h2
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc88
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h7
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/trap.cc6
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/trap.h2
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_permission_list.cc14
-rw-r--r--chromium/sandbox/linux/system_headers/linux_seccomp.h16
-rw-r--r--chromium/sandbox/mac/seatbelt_sandbox_design.md80
-rw-r--r--chromium/sandbox/win/src/ipc_leak_test.cc3
-rw-r--r--chromium/sandbox/win/src/policy_engine_opcodes.h2
-rw-r--r--chromium/sandbox/win/src/policy_low_level.cc10
-rw-r--r--chromium/sandbox/win/src/policy_low_level.h5
-rw-r--r--chromium/sandbox/win/src/sandbox_policy.h5
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_base.cc15
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_base.h3
-rw-r--r--chromium/sandbox/win/src/target_services.cc1
21 files changed, 202 insertions, 105 deletions
diff --git a/chromium/sandbox/BUILD.gn b/chromium/sandbox/BUILD.gn
index 9de38b4acd5..27dea2c2727 100644
--- a/chromium/sandbox/BUILD.gn
+++ b/chromium/sandbox/BUILD.gn
@@ -34,7 +34,10 @@ group("sandbox") {
buildflag_header("sandbox_buildflags") {
header = "sandbox_buildflags.h"
- flags = [ "USE_SECCOMP_BPF=$use_seccomp_bpf" ]
+ flags = [
+ "USE_SECCOMP_BPF=$use_seccomp_bpf",
+ "DISABLE_SECCOMP_SSBD=$disable_seccomp_ssbd",
+ ]
}
# This target must be here and not in win/ otherwise it would require a full
diff --git a/chromium/sandbox/features.gni b/chromium/sandbox/features.gni
index 09280d35f6a..46c8a03f45e 100644
--- a/chromium/sandbox/features.gni
+++ b/chromium/sandbox/features.gni
@@ -14,3 +14,8 @@ use_seccomp_bpf = (is_linux || is_android) &&
current_cpu == "mipsel" || current_cpu == "mips64el")
use_seccomp_bpf = use_seccomp_bpf || is_nacl_nonsfi
+
+# SSBD (Speculative Store Bypass Disable) is a mitigation of Spectre Variant 4.
+# As Spectre Variant 4 can be mitigated by site isolation, opt-out SSBD on site
+# isolation fully applied platform.
+disable_seccomp_ssbd = use_seccomp_bpf && !is_android
diff --git a/chromium/sandbox/linux/BUILD.gn b/chromium/sandbox/linux/BUILD.gn
index c27351f9a6a..7d4d600c5ae 100644
--- a/chromium/sandbox/linux/BUILD.gn
+++ b/chromium/sandbox/linux/BUILD.gn
@@ -248,6 +248,7 @@ component("seccomp_bpf") {
":sandbox_services",
"//base",
"//base/third_party/dynamic_annotations",
+ "//sandbox:sandbox_buildflags",
]
if (is_nacl_nonsfi) {
diff --git a/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc b/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
index a894e2ad397..2ba3bc9908f 100644
--- a/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -10,6 +10,7 @@
#include <sys/syscall.h>
#include <limits>
+#include <ostream>
#include "base/check_op.h"
#include "base/stl_util.h"
diff --git a/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc b/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
index 28604a82797..938b51ae623 100644
--- a/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
+++ b/chromium/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
@@ -177,7 +177,9 @@ bool IsSyscallForTestHarness(int sysno) {
// UBSan_vptr checker needs mmap, munmap, pipe, write.
// ASan and MSan don't need any of these for normal operation, but they
// require at least mmap & munmap to print a report if an error is detected.
- if (sysno == kMMapNr || sysno == __NR_munmap || sysno == __NR_pipe) {
+ // ASan requires sigaltstack.
+ if (sysno == kMMapNr || sysno == __NR_munmap || sysno == __NR_pipe ||
+ sysno == __NR_sigaltstack) {
return true;
}
#endif
@@ -599,7 +601,7 @@ class PrctlPolicy : public Policy {
if (sysno == __NR_prctl) {
// Handle prctl() inside an UnsafeTrap()
- return UnsafeTrap(PrctlHandler, NULL);
+ return UnsafeTrap(PrctlHandler, nullptr);
}
// Allow all other system calls.
@@ -661,7 +663,7 @@ ResultExpr RedirectAllSyscallsPolicy::EvaluateSyscall(int sysno) const {
// use of UnsafeTrap()
if (SandboxBPF::IsRequiredForUnsafeTrap(sysno))
return Allow();
- return UnsafeTrap(AllowRedirectedSyscall, NULL);
+ return UnsafeTrap(AllowRedirectedSyscall, nullptr);
}
#if !defined(ADDRESS_SANITIZER)
@@ -688,7 +690,7 @@ BPF_TEST_C(SandboxBPF, SigBus, RedirectAllSyscallsPolicy) {
struct sigaction sa = {};
sa.sa_sigaction = SigBusHandler;
sa.sa_flags = SA_SIGINFO;
- BPF_ASSERT(sigaction(SIGBUS, &sa, NULL) == 0);
+ BPF_ASSERT(sigaction(SIGBUS, &sa, nullptr) == 0);
kill(getpid(), SIGBUS);
char c = '\000';
BPF_ASSERT(read(fds[0], &c, 1) == 1);
@@ -720,8 +722,8 @@ BPF_TEST_C(SandboxBPF, SigMask, RedirectAllSyscallsPolicy) {
// Try again, and this time we verify that we can block it. This
// requires a second call to sigprocmask().
sigaddset(&mask0, SIGUSR2);
- BPF_ASSERT(!sigprocmask(SIG_BLOCK, &mask0, NULL));
- BPF_ASSERT(!sigprocmask(SIG_BLOCK, NULL, &mask2));
+ BPF_ASSERT(!sigprocmask(SIG_BLOCK, &mask0, nullptr));
+ BPF_ASSERT(!sigprocmask(SIG_BLOCK, nullptr, &mask2));
BPF_ASSERT(sigismember(&mask2, SIGUSR2));
}
@@ -837,7 +839,7 @@ class EqualityStressTest {
// work isn't impacted by the fact that we are overriding
// a lot of different system calls.
++end;
- arg_values_.push_back(NULL);
+ arg_values_.push_back(nullptr);
} else {
arg_values_.push_back(
RandomArgValue(rand() % kMaxArgs, 0, rand() % kMaxArgs));
@@ -955,7 +957,7 @@ class EqualityStressTest {
arg_value->tests[n].k_value = k_value;
if (!remaining_args || (rand() & 1)) {
arg_value->tests[n].err = (rand() % 1000) + 1;
- arg_value->tests[n].arg_value = NULL;
+ arg_value->tests[n].arg_value = nullptr;
} else {
arg_value->tests[n].err = 0;
arg_value->tests[n].arg_value =
@@ -967,7 +969,7 @@ class EqualityStressTest {
// node, or we can randomly add another couple of tests.
if (!remaining_args || (rand() & 1)) {
arg_value->err = (rand() % 1000) + 1;
- arg_value->arg_value = NULL;
+ arg_value->arg_value = nullptr;
} else {
arg_value->err = 0;
arg_value->arg_value =
@@ -1820,15 +1822,15 @@ ResultExpr PthreadPolicyBitMask::EvaluateSyscall(int sysno) const {
static void* ThreadFnc(void* arg) {
++*reinterpret_cast<int*>(arg);
Syscall::Call(__NR_futex, arg, FUTEX_WAKE, 1, 0, 0, 0);
- return NULL;
+ return nullptr;
}
static void PthreadTest() {
// Attempt to start a joinable thread. This should succeed.
pthread_t thread;
int thread_ran = 0;
- BPF_ASSERT(!pthread_create(&thread, NULL, ThreadFnc, &thread_ran));
- BPF_ASSERT(!pthread_join(thread, NULL));
+ BPF_ASSERT(!pthread_create(&thread, nullptr, ThreadFnc, &thread_ran));
+ BPF_ASSERT(!pthread_join(thread, nullptr));
BPF_ASSERT(thread_ran);
// Attempt to start a detached thread. This should succeed.
@@ -2084,7 +2086,7 @@ class TrapPread64Policy : public Policy {
}
if (system_call_number == __NR_pread64) {
- return UnsafeTrap(ForwardPreadHandler, NULL);
+ return UnsafeTrap(ForwardPreadHandler, nullptr);
}
return Allow();
}
@@ -2134,7 +2136,7 @@ void* TsyncApplyToTwoThreadsFunc(void* cond_ptr) {
BlacklistNanosleepPolicy::AssertNanosleepFails();
- return NULL;
+ return nullptr;
}
SANDBOX_TEST(SandboxBPF, Tsync) {
@@ -2158,7 +2160,7 @@ SANDBOX_TEST(SandboxBPF, Tsync) {
// Create a thread on which to invoke the blocked syscall.
pthread_t thread;
BPF_ASSERT_EQ(
- 0, pthread_create(&thread, NULL, &TsyncApplyToTwoThreadsFunc, &event));
+ 0, pthread_create(&thread, nullptr, &TsyncApplyToTwoThreadsFunc, &event));
// Test that nanoseelp success.
const struct timespec ts = {0, 0};
@@ -2175,7 +2177,7 @@ SANDBOX_TEST(SandboxBPF, Tsync) {
event.Signal();
// Wait for the thread to finish.
- BPF_ASSERT_EQ(0, pthread_join(thread, NULL));
+ BPF_ASSERT_EQ(0, pthread_join(thread, nullptr));
}
class AllowAllPolicy : public Policy {
@@ -2237,7 +2239,7 @@ class UnsafeTrapWithCondPolicy : public Policy {
case __NR_close:
return Allow();
case __NR_getppid:
- return UnsafeTrap(NoOpHandler, NULL);
+ return UnsafeTrap(NoOpHandler, nullptr);
default:
return Error(EPERM);
}
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;
diff --git a/chromium/sandbox/linux/syscall_broker/broker_permission_list.cc b/chromium/sandbox/linux/syscall_broker/broker_permission_list.cc
index 8032b3a9e56..397cfff7630 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_permission_list.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_permission_list.cc
@@ -25,7 +25,7 @@ bool CheckCallerArgs(const char** file_to_access) {
// Make sure that callers never pass a non-empty string. In case callers
// wrongly forget to check the return value and look at the string
// instead, this could catch bugs.
- RAW_LOG(FATAL, "*file_to_access should be NULL");
+ RAW_LOG(FATAL, "*file_to_access should be nullptr");
return false;
}
return true;
@@ -45,7 +45,7 @@ BrokerPermissionList::BrokerPermissionList(
if (num_of_permissions_ > 0) {
permissions_array_ = &permissions_[0];
} else {
- permissions_array_ = NULL;
+ permissions_array_ = nullptr;
}
}
@@ -56,12 +56,12 @@ BrokerPermissionList::~BrokerPermissionList() {}
// Note: access() being a system call to check permissions, this can get a bit
// confusing. We're checking if calling access() should even be allowed with
// the same policy we would use for open().
-// If |file_to_access| is not NULL, we will return the matching pointer from
+// If |file_to_access| is not nullptr, we will return the matching pointer from
// the whitelist. For paranoia a caller should then use |file_to_access|. See
// GetFileNameIfAllowedToOpen() for more explanation.
// return true if calling access() on this file should be allowed, false
// otherwise.
-// Async signal safe if and only if |file_to_access| is NULL.
+// Async signal safe if and only if |file_to_access| is nullptr.
bool BrokerPermissionList::GetFileNameIfAllowedToAccess(
const char* requested_filename,
int requested_mode,
@@ -79,13 +79,13 @@ bool BrokerPermissionList::GetFileNameIfAllowedToAccess(
}
// Check if |requested_filename| can be opened with flags |requested_flags|.
-// If |file_to_open| is not NULL, we will return the matching pointer from the
-// whitelist. For paranoia, a caller should then use |file_to_open| rather
+// If |file_to_open| is not nullptr, we will return the matching pointer from
+// the whitelist. For paranoia, a caller should then use |file_to_open| rather
// than |requested_filename|, so that it never attempts to open an
// attacker-controlled file name, even if an attacker managed to fool the
// string comparison mechanism.
// Return true if opening should be allowed, false otherwise.
-// Async signal safe if and only if |file_to_open| is NULL.
+// Async signal safe if and only if |file_to_open| is nullptr.
bool BrokerPermissionList::GetFileNameIfAllowedToOpen(
const char* requested_filename,
int requested_flags,
diff --git a/chromium/sandbox/linux/system_headers/linux_seccomp.h b/chromium/sandbox/linux/system_headers/linux_seccomp.h
index a60fe2ad3dc..ab1d1fc2b5d 100644
--- a/chromium/sandbox/linux/system_headers/linux_seccomp.h
+++ b/chromium/sandbox/linux/system_headers/linux_seccomp.h
@@ -67,6 +67,19 @@
#ifndef IPC_64
#define IPC_64 0x0100
#endif
+#ifndef PR_SET_SPECULATION_CTRL
+#define PR_SET_SPECULATION_CTRL 53
+#define PR_GET_SPECULATION_CTRL 52
+#endif
+#ifndef PR_SPEC_INDIRECT_BRANCH
+#define PR_SPEC_INDIRECT_BRANCH 1
+#endif
+#ifndef PR_SPEC_PRCTL
+#define PR_SPEC_PRCTL (1UL << 0)
+#endif
+#ifndef PR_SPEC_FORCE_DISABLE
+#define PR_SPEC_FORCE_DISABLE (1UL << 3)
+#endif
// In order to build will older tool chains, we currently have to avoid
// including <linux/seccomp.h>. Until that can be fixed (if ever). Rely on
@@ -86,6 +99,9 @@
#ifndef SECCOMP_FILTER_FLAG_TSYNC
#define SECCOMP_FILTER_FLAG_TSYNC 1
#endif
+#ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW
+#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
+#endif
#ifndef SECCOMP_RET_KILL
// Return values supported for BPF filter programs. Please note that the
diff --git a/chromium/sandbox/mac/seatbelt_sandbox_design.md b/chromium/sandbox/mac/seatbelt_sandbox_design.md
index d103747906d..53b6566cba3 100644
--- a/chromium/sandbox/mac/seatbelt_sandbox_design.md
+++ b/chromium/sandbox/mac/seatbelt_sandbox_design.md
@@ -1,5 +1,5 @@
# **Mac Sandbox V2 Design Doc**
-*Status: Final, Authors: kerrnel@chromium.org,rsesek@chromium.org, Last Updated: 2017-07-10*
+*Status: Final, Authors: kerrnel@chromium.org, rsesek@chromium.org, Last Updated: 2020-05-14*
# **Objective**
@@ -10,14 +10,14 @@ profile features.
# **Background**
-Chromium currently runs an unsandboxed warm up routine to acquire
-system resources, before entering the sandbox. The design doc
+Chromium historically ran an unsandboxed warm up routine to acquire
+system resources, before entering the sandbox. This design doc
provides a full implementation design and deployment strategy to
sandbox the warmup phase. This document also provides a high level
overview of the macOS provided sandbox.
-In the current warm up phase, Chromium calls system frameworks which
-acquires an unspecified number of resources before being sandboxed,
+In the warm up phase, Chromium called system frameworks which
+acquired an unspecified number of resources before being sandboxed,
and those resources change with every new OS update from Apple.
This [2009 Chromium blog
post](https://blog.chromium.org/2009/06/google-chrome-sandboxing-and-mac-os-x.html&sa=D&ust=1492473048358000&usg=AFQjCNGEbmCLUqoH9-BeudDcNf5NmW-UcQ)
@@ -32,11 +32,11 @@ should read the [Apple Sandbox
Guide](http://reverse.put.as/wp-content/uploads/2011/09/Apple-Sandbox-Guide-v1.0.pdf)
from reverse.put.as, or see the Appendix of this doc.
-# **Current versus New Implementation**
+# **The V2 Sandbox Implementation**
-The new sandbox will continue to use the OS provided sandboxing
+The V2 sandbox continues to use the OS provided sandboxing
framework and the "deny resource access by default" policy that the
-sandbox currently uses. The change introduced by the new implementation
+V1 sandbox used. The major difference under the V2 sandbox architecture
is the removal of the unsandboxed warmup phase.
# **Compatibility and Security Risk**
@@ -51,12 +51,12 @@ sandbox allowed access to dangerous resources.
A more permissive sandbox profile reduces compatibility risk but
increases security risk and vice versa. See
[crbug.com/619981](https://bugs.chromium.org/p/chromium/issues/detail?id=619981)
-for an example of how the current sandbox implementation already
-incurs compatibility risk in favor of security risk.
+for an example of how even given the V1 unsandboxed warmup phase, the
+implementation already dealt with compatibility risk.
-The current sandbox also incurs a large security risk at the warmup
+The V1 sandbox also has greater security risk at the warmup
time, since that phase is unsandboxed. Rather than incurring both
-compatibility and security risk during execution, the new sandbox
+compatibility and security risk during execution, the V2 sandbox
shifts the risk profile to take on more compatibility risk, since
the warmup phase is eliminated, but it eliminates security risk.
@@ -76,25 +76,43 @@ continue its execution into the ChromeMain function.
# **Detailed Design**
+## Executable Structure
+
+Both the main Chromium executable and all of the bundled Chromium Helper
+executables contain [a minimal amount of
+code](https://source.chromium.org/chromium/chromium/src/+/master:chrome/app/chrome_exe_main_mac.cc;drc=05219ddeb8130389da9ad634ba3e021a70bff393).
+The bulk of the code lives in the Chromium Framework library, which is
+`dlopen()`ed at runtime to call `ChromeMain()`, after applying the sandbox.
+
+This design choice has beneficial security properties: many system frameworks
+run static initializers, and some of these static initializers acquire and
+maintain access to files or Mach service ports. If the executables directly
+linked the Chromium Framework or the system frameworks, then those initializers
+would be able to run outside the sandbox, since static initializers run before
+`main()`. The Chromium and Helper executables instead only link
+`/usr/lib/libSystem.dylib` and the very small `//sandbox/mac` target, to bring
+in `/usr/lib/libsandbox.dylib`. After the executable applies the sandbox, the
+program then loads the Framework, which causes all the dependent system
+frameworks to load.
+
## Sandbox Profile Principles
The sandbox profiles will use the following principles when
implementing the profiles for each process type.
-* The profiles deny resource access to anything not explicitly allowed.
-* Processes may access all system libraries and frameworks.
-* Explicitly list which system resources (files, folders, mach services, sysctls, IPC, IOKit calls) Chromium may access. Analyze each resource access for safety first.
-## Sandbox Design
+- The profiles deny resource access to anything not explicitly allowed.
+- Processes may access all system libraries and frameworks.
+- Explicitly list which system resources (files, folders, mach services,
+ sysctls, IPC, IOKit calls) Chromium may access. Analyze each resource access
+ for safety first.
-The current sandbox code lives in content/common/sandbox_mac.mm.
-This file will continue to exist until the current sandbox is
-officially deprecated and removed for all process types. Chromium
-will use a switch to skip the current sandboxing code for each
-process type as it is ported to the new sandbox.
+## Sandbox Design
-The new sandbox will rewrite the Chromium code and profiles from
-scratch, in order to leverage the most modern OS APIs and constructs,
-which are easier to use and maintain.
+The V1 sandbox code lives in
+[sandbox_mac.mm](https://source.chromium.org/chromium/chromium/src/+/master:services/service_manager/sandbox/mac/sandbox_mac.mm;l=1;drc=efd8e880522dc1df3b8883648513016fab3d3956).
+This file will continue to exist until the V1 sandbox is removed for all process
+types. Chromium now uses the V2 sandbox for all process types except the GPU
+process.
## Code Structure
@@ -106,10 +124,10 @@ using the "Google Chromium Helper" executable. The browser passes
command line flags to the Helper executable indicating what type
of process it should execute as.
-The browser will now create a pipe to the Helper executable, and
-using that pipe, the Helper executable will read a protobuf message
-from the browser process. The profobuf message will contain the
-profile string and a map of the sandbox parameters, and using a
+The browser creates a pipe to the Helper executable, and
+using that pipe, the Helper executable reads a protobuf message
+from the browser process. The profobuf message contains the
+profile string and a map of the sandbox parameters. Using the
lightweight protobuf prevents the error prone parsing code for a
whole parameters list from being re-implemented. This must happen
in the main executable itself, as the process must be sandboxed
@@ -117,7 +135,7 @@ before the framework is loaded.
The Helper executable will immediately initialize the sandbox, using
the profile and parameters, before continuing execution to the
-ChromiumMain function.
+`ChromeMain()` function.
# **Design Alternatives**
@@ -130,9 +148,9 @@ a new OS release, and we would not know. The new explicit profiles
make the attack surface very auditable and easy to understand.
Another alternative would have been the [Bootstrap
-Sandbox](https://docs.google.com/presentation/d/1Npdbl7UF06wgKRsRWakiI3-qIlPDNN_-AT8H5tQjbYc/edit#slide=id.p)
+Sandbox](https://docs.google.com/document/d/108sr6gBxqdrnzVPsb_4_JbDyW1V4-DRQUC4R8YvM40M/view)
plan, which proposed intercepting all mach connections to limit the
-attack surface. However, with the "new" launchd released in OS X
+attack surface. However, with the rewritten launchd released in macOS
10.10 Yosemite, messages could no longer be intercepted and forward.
This design solves the same problem by sandboxing the warmup phase,
and allowing the existing system sandbox to enforce the security.
diff --git a/chromium/sandbox/win/src/ipc_leak_test.cc b/chromium/sandbox/win/src/ipc_leak_test.cc
index a2ab9c40b9b..3dd1c1d67e7 100644
--- a/chromium/sandbox/win/src/ipc_leak_test.cc
+++ b/chromium/sandbox/win/src/ipc_leak_test.cc
@@ -46,7 +46,8 @@ enum TestId {
// Helper function to allocate space (on the heap) for policy.
PolicyGlobal* MakePolicyMemory() {
- const size_t kTotalPolicySz = 4096 * 8;
+ // Should not exceed kPolMemSize from |sandbox_policy_base.cc|.
+ const size_t kTotalPolicySz = 4096 * 6;
char* mem = new char[kTotalPolicySz];
memset(mem, 0, kTotalPolicySz);
PolicyGlobal* policy = reinterpret_cast<PolicyGlobal*>(mem);
diff --git a/chromium/sandbox/win/src/policy_engine_opcodes.h b/chromium/sandbox/win/src/policy_engine_opcodes.h
index 8e8816df1cb..88a703c1297 100644
--- a/chromium/sandbox/win/src/policy_engine_opcodes.h
+++ b/chromium/sandbox/win/src/policy_engine_opcodes.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "sandbox/win/src/policy_engine_params.h"
diff --git a/chromium/sandbox/win/src/policy_low_level.cc b/chromium/sandbox/win/src/policy_low_level.cc
index b07677ec7da..d987211c8b5 100644
--- a/chromium/sandbox/win/src/policy_low_level.cc
+++ b/chromium/sandbox/win/src/policy_low_level.cc
@@ -59,10 +59,6 @@ LowLevelPolicy::~LowLevelPolicy() {
}
}
-size_t LowLevelPolicy::GetPolicyGlobalSize() {
- return policy_global_size_;
-}
-
// Here is where the heavy byte shuffling is done. We take all the rules and
// 'compile' them into a single memory region. Now, the rules are in random
// order so the first step is to reorganize them into a stl map that is keyed
@@ -76,8 +72,6 @@ bool LowLevelPolicy::Done() {
typedef std::map<IpcTag, RuleList> Mmap;
Mmap mmap;
- policy_global_size_ = 0;
-
for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
mmap[it->service].push_back(it->rule);
}
@@ -125,10 +119,6 @@ bool LowLevelPolicy::Done() {
current_buffer = &current_buffer[policy_buffers_occupied + 1];
}
- // The size used to store policy rules. Must be >=0 if we got here
- // or we would have bailed out for lack of space earlier.
- policy_global_size_ = policy_store_->data_size - avail_size;
-
return true;
}
diff --git a/chromium/sandbox/win/src/policy_low_level.h b/chromium/sandbox/win/src/policy_low_level.h
index da6410a4a6a..1586f96af90 100644
--- a/chromium/sandbox/win/src/policy_low_level.h
+++ b/chromium/sandbox/win/src/policy_low_level.h
@@ -96,10 +96,6 @@ class LowLevelPolicy {
// passed on the constructor. Returns false on error.
bool Done();
- // Returns the size that could hold all rules, valid after Done() has
- // packed them.
- size_t GetPolicyGlobalSize();
-
private:
struct RuleNode {
const PolicyRule* rule;
@@ -107,7 +103,6 @@ class LowLevelPolicy {
};
std::list<RuleNode> rules_;
PolicyGlobal* policy_store_;
- size_t policy_global_size_;
DISALLOW_IMPLICIT_CONSTRUCTORS(LowLevelPolicy);
};
diff --git a/chromium/sandbox/win/src/sandbox_policy.h b/chromium/sandbox/win/src/sandbox_policy.h
index 279e5024124..57a12d77aa2 100644
--- a/chromium/sandbox/win/src/sandbox_policy.h
+++ b/chromium/sandbox/win/src/sandbox_policy.h
@@ -17,6 +17,7 @@
namespace sandbox {
class AppContainerProfile;
+class PolicyInfo;
class TargetPolicy {
public:
@@ -276,8 +277,8 @@ class TargetPolicy {
// lifetime of the policy object.
virtual void SetEffectiveToken(HANDLE token) = 0;
- // Returns the size of policy memory used at process start.
- virtual size_t GetPolicyGlobalSize() const = 0;
+ // Returns a snapshot of the policy configuration.
+ virtual std::unique_ptr<PolicyInfo> GetPolicyInfo() = 0;
protected:
~TargetPolicy() {}
diff --git a/chromium/sandbox/win/src/sandbox_policy_base.cc b/chromium/sandbox/win/src/sandbox_policy_base.cc
index fdf63d9c774..3d055248c01 100644
--- a/chromium/sandbox/win/src/sandbox_policy_base.cc
+++ b/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -29,6 +29,7 @@
#include "sandbox/win/src/registry_policy.h"
#include "sandbox/win/src/restricted_token_utils.h"
#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_policy_diagnostic.h"
#include "sandbox/win/src/sandbox_utils.h"
#include "sandbox/win/src/security_capabilities.h"
#include "sandbox/win/src/signed_policy.h"
@@ -43,7 +44,7 @@ namespace {
constexpr size_t kOneMemPage = 4096;
// The IPC and Policy shared memory sizes.
constexpr size_t kIPCMemSize = kOneMemPage * 2;
-constexpr size_t kPolMemSize = kOneMemPage * 14;
+constexpr size_t kPolMemSize = kOneMemPage * 6;
// Helper function to allocate space (on the heap) for policy.
sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
@@ -507,13 +508,6 @@ PSID PolicyBase::GetLowBoxSid() const {
return lowbox_sid_;
}
-size_t PolicyBase::GetPolicyGlobalSize() const {
- // TODO(1059129) remove when Process.Sandbox.PolicyGlobalSize expires.
- if (policy_maker_)
- return policy_maker_->GetPolicyGlobalSize();
- return 0;
-}
-
ResultCode PolicyBase::AddTarget(TargetProcess* target) {
if (policy_) {
if (!policy_maker_->Done())
@@ -817,4 +811,9 @@ ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
return SBOX_ALL_OK;
}
+std::unique_ptr<PolicyInfo> PolicyBase::GetPolicyInfo() {
+ auto diagnostic = std::make_unique<PolicyDiagnostic>(this);
+ return diagnostic;
+}
+
} // namespace sandbox
diff --git a/chromium/sandbox/win/src/sandbox_policy_base.h b/chromium/sandbox/win/src/sandbox_policy_base.h
index 9763311479c..233e4d83c17 100644
--- a/chromium/sandbox/win/src/sandbox_policy_base.h
+++ b/chromium/sandbox/win/src/sandbox_policy_base.h
@@ -33,6 +33,7 @@ namespace sandbox {
class LowLevelPolicy;
class PolicyDiagnostic;
+class PolicyInfo;
class TargetProcess;
struct PolicyGlobal;
@@ -80,7 +81,7 @@ class PolicyBase final : public TargetPolicy {
bool create_profile) override;
scoped_refptr<AppContainerProfile> GetAppContainerProfile() override;
void SetEffectiveToken(HANDLE token) override;
- size_t GetPolicyGlobalSize() const override;
+ std::unique_ptr<PolicyInfo> GetPolicyInfo() override;
// Get the AppContainer profile as its internal type.
scoped_refptr<AppContainerProfileBase> GetAppContainerProfileBase();
diff --git a/chromium/sandbox/win/src/target_services.cc b/chromium/sandbox/win/src/target_services.cc
index b6b03b34809..52f61d7102a 100644
--- a/chromium/sandbox/win/src/target_services.cc
+++ b/chromium/sandbox/win/src/target_services.cc
@@ -9,6 +9,7 @@
#include <process.h>
#include <stdint.h>
+#include "base/logging.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/crosscall_client.h"
#include "sandbox/win/src/handle_closer_agent.h"