summaryrefslogtreecommitdiff
path: root/chromium/sandbox
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-26 13:57:00 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-11-02 11:31:01 +0000
commit1943b3c2a1dcee36c233724fc4ee7613d71b9cf6 (patch)
tree8c1b5f12357025c197da5427ae02cfdc2f3570d6 /chromium/sandbox
parent21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (diff)
downloadqtwebengine-chromium-1943b3c2a1dcee36c233724fc4ee7613d71b9cf6.tar.gz
BASELINE: Update Chromium to 94.0.4606.111
Change-Id: I924781584def20fc800bedf6ff41fdb96c438193 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/sandbox')
-rw-r--r--chromium/sandbox/linux/BUILD.gn1
-rw-r--r--chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc4
-rw-r--r--chromium/sandbox/linux/bpf_dsl/policy_compiler.cc10
-rw-r--r--chromium/sandbox/linux/bpf_dsl/syscall_set_unittest.cc2
-rw-r--r--chromium/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc2
-rw-r--r--chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc122
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/DEPS1
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc39
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc17
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc27
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h14
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc23
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h4
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc4
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc1
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc2
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc2
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/trap.cc2
-rw-r--r--chromium/sandbox/linux/services/credentials.cc2
-rw-r--r--chromium/sandbox/linux/services/libc_interceptor.cc10
-rw-r--r--chromium/sandbox/linux/services/namespace_sandbox.cc2
-rw-r--r--chromium/sandbox/linux/services/syscall_wrappers.cc50
-rw-r--r--chromium/sandbox/linux/services/syscall_wrappers.h15
-rw-r--r--chromium/sandbox/linux/services/syscall_wrappers_unittest.cc185
-rw-r--r--chromium/sandbox/linux/suid/client/setuid_sandbox_host.cc2
-rw-r--r--chromium/sandbox/linux/suid/sandbox.c2
-rw-r--r--chromium/sandbox/linux/syscall_broker/DEPS3
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_client.cc4
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_client.h4
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_host.cc23
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_process.cc21
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_process_unittest.cc94
-rw-r--r--chromium/sandbox/linux/syscall_broker/broker_simple_message_unittest.cc2
-rw-r--r--chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler.cc2
-rw-r--r--chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc36
-rw-r--r--chromium/sandbox/linux/syscall_broker/syscall_dispatcher.cc67
-rw-r--r--chromium/sandbox/linux/syscall_broker/syscall_dispatcher.h27
-rw-r--r--chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h96
-rw-r--r--chromium/sandbox/linux/system_headers/arm_linux_syscalls.h12
-rw-r--r--chromium/sandbox/linux/system_headers/linux_stat.h196
-rw-r--r--chromium/sandbox/linux/system_headers/linux_time.h26
-rw-r--r--chromium/sandbox/linux/system_headers/mips64_linux_syscalls.h144
-rw-r--r--chromium/sandbox/linux/system_headers/mips_linux_syscalls.h12
-rw-r--r--chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h12
-rw-r--r--chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h88
-rw-r--r--chromium/sandbox/mac/seatbelt_extension_unittest.cc2
-rw-r--r--chromium/sandbox/policy/BUILD.gn4
-rw-r--r--chromium/sandbox/policy/features.cc26
-rw-r--r--chromium/sandbox/policy/features.h5
-rw-r--r--chromium/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc34
-rw-r--r--chromium/sandbox/policy/linux/bpf_broker_policy_linux.cc4
-rw-r--r--chromium/sandbox/policy/linux/bpf_cros_arm_gpu_policy_linux.cc8
-rw-r--r--chromium/sandbox/policy/linux/bpf_libassistant_policy_linux.cc21
-rw-r--r--chromium/sandbox/policy/linux/bpf_service_policy_linux.h2
-rw-r--r--chromium/sandbox/policy/linux/sandbox_linux.cc6
-rw-r--r--chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc19
-rw-r--r--chromium/sandbox/policy/mojom/BUILD.gn10
-rw-r--r--chromium/sandbox/policy/mojom/OWNERS2
-rw-r--r--chromium/sandbox/policy/mojom/sandbox.mojom61
-rw-r--r--chromium/sandbox/policy/sandbox_type.cc31
-rw-r--r--chromium/sandbox/policy/sandbox_type.h41
-rw-r--r--chromium/sandbox/policy/sandbox_type_unittest.cc22
-rw-r--r--chromium/sandbox/policy/switches.cc4
-rw-r--r--chromium/sandbox/policy/switches.h4
-rw-r--r--chromium/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc4
-rw-r--r--chromium/sandbox/policy/win/sandbox_diagnostics.h5
-rw-r--r--chromium/sandbox/policy/win/sandbox_win.cc11
-rw-r--r--chromium/sandbox/win/BUILD.gn105
-rw-r--r--chromium/sandbox/win/sandbox_poc/main_ui_window.cc3
-rw-r--r--chromium/sandbox/win/src/app_container_base.cc2
-rw-r--r--chromium/sandbox/win/src/app_container_test.cc553
-rw-r--r--chromium/sandbox/win/src/app_container_unittest.cc2
-rw-r--r--chromium/sandbox/win/src/broker_services.cc22
-rw-r--r--chromium/sandbox/win/src/crosscall_client.h12
-rw-r--r--chromium/sandbox/win/src/file_policy_test.cc11
-rw-r--r--chromium/sandbox/win/src/filesystem_policy.cc2
-rw-r--r--chromium/sandbox/win/src/interception.cc3
-rw-r--r--chromium/sandbox/win/src/ipc_leak_test.cc2
-rw-r--r--chromium/sandbox/win/src/ipc_tags.h1
-rw-r--r--chromium/sandbox/win/src/policy_engine_opcodes.cc6
-rw-r--r--chromium/sandbox/win/src/policy_engine_opcodes.h6
-rw-r--r--chromium/sandbox/win/src/policy_engine_params.h20
-rw-r--r--chromium/sandbox/win/src/policy_low_level.cc2
-rw-r--r--chromium/sandbox/win/src/sandbox.cc13
-rw-r--r--chromium/sandbox/win/src/sandbox.h9
-rw-r--r--chromium/sandbox/win/src/sandbox_policy.h6
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_base.cc10
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_diagnostic.cc2
-rw-r--r--chromium/sandbox/win/src/sandbox_policy_diagnostic.h2
-rw-r--r--chromium/sandbox/win/src/socket_dispatcher.cc132
-rw-r--r--chromium/sandbox/win/src/socket_dispatcher.h45
-rw-r--r--chromium/sandbox/win/src/target_services.cc32
-rw-r--r--chromium/sandbox/win/src/target_services.h3
-rw-r--r--chromium/sandbox/win/src/threadpool.cc26
-rw-r--r--chromium/sandbox/win/src/top_level_dispatcher.cc5
-rw-r--r--chromium/sandbox/win/src/top_level_dispatcher.h1
-rw-r--r--chromium/sandbox/win/src/win_utils.cc2
-rw-r--r--chromium/sandbox/win/src/win_utils.h2
98 files changed, 2402 insertions, 380 deletions
diff --git a/chromium/sandbox/linux/BUILD.gn b/chromium/sandbox/linux/BUILD.gn
index 2f778dd0bca..ccbbc91716e 100644
--- a/chromium/sandbox/linux/BUILD.gn
+++ b/chromium/sandbox/linux/BUILD.gn
@@ -443,6 +443,7 @@ source_set("sandbox_services_headers") {
"system_headers/linux_ptrace.h",
"system_headers/linux_seccomp.h",
"system_headers/linux_signal.h",
+ "system_headers/linux_stat.h",
"system_headers/linux_syscalls.h",
"system_headers/linux_time.h",
"system_headers/linux_ucontext.h",
diff --git a/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc b/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
index 82a40696b87..846dc7a83d1 100644
--- a/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
+++ b/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
@@ -103,8 +103,8 @@ class IfThenResultExprImpl : public internal::ResultExprImpl {
class ConstBoolExprImpl : public internal::BoolExprImpl {
public:
- ConstBoolExprImpl(bool value) : value_(value) {}
- ~ConstBoolExprImpl() override {}
+ explicit ConstBoolExprImpl(bool value) : value_(value) {}
+ ~ConstBoolExprImpl() override = default;
CodeGen::Node Compile(PolicyCompiler* pc,
CodeGen::Node then_node,
diff --git a/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc b/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
index 2ba3bc9908f..19c0cf631db 100644
--- a/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -12,8 +12,9 @@
#include <limits>
#include <ostream>
+#include "base/bits.h"
#include "base/check_op.h"
-#include "base/stl_util.h"
+#include "base/cxx17_backports.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
#include "sandbox/linux/bpf_dsl/codegen.h"
@@ -51,11 +52,6 @@ const int kSyscallsRequiredForUnsafeTraps[] = {
#endif
};
-bool HasExactlyOneBit(uint64_t x) {
- // Common trick; e.g., see http://stackoverflow.com/a/108329.
- return x != 0 && (x & (x - 1)) == 0;
-}
-
ResultExpr DefaultPanic(const char* error) {
return Kill();
}
@@ -404,7 +400,7 @@ CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno,
// For (arg & x) == x where x is a single-bit value, emit:
// LDW [idx]
// JSET mask, passed, failed
- if (mask == value && HasExactlyOneBit(mask)) {
+ if (mask == value && base::bits::IsPowerOfTwo(mask)) {
return gen_.MakeInstruction(
BPF_LD + BPF_W + BPF_ABS,
idx,
diff --git a/chromium/sandbox/linux/bpf_dsl/syscall_set_unittest.cc b/chromium/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
index 942ac745a3c..00c475ea990 100644
--- a/chromium/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
+++ b/chromium/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/stl_util.h"
+#include "base/cxx17_backports.h"
#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
#include "sandbox/linux/tests/unit_tests.h"
diff --git a/chromium/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc b/chromium/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc
index 6f0f71f5fee..05bca9edee8 100644
--- a/chromium/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc
+++ b/chromium/sandbox/linux/bpf_dsl/test_trap_registry_unittest.cc
@@ -6,7 +6,7 @@
#include <stddef.h>
-#include "base/stl_util.h"
+#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sandbox {
diff --git a/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc b/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
index 9da9c689114..6d6132a542f 100644
--- a/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
+++ b/chromium/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
@@ -34,6 +34,7 @@
#include "sandbox/linux/syscall_broker/broker_file_permission.h"
#include "sandbox/linux/syscall_broker/broker_process.h"
#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/tests/scoped_temporary_file.h"
#include "sandbox/linux/tests/test_utils.h"
@@ -202,6 +203,26 @@ namespace {
// not accept this as a valid error number. E.g. bionic accepts up to 255, glibc
// and musl up to 4096.
const int kFakeErrnoSentinel = 254;
+
+void ConvertKernelStatToLibcStat(default_stat_struct& in_stat,
+ struct stat& out_stat) {
+ out_stat.st_dev = in_stat.st_dev;
+ out_stat.st_ino = in_stat.st_ino;
+ out_stat.st_mode = in_stat.st_mode;
+ out_stat.st_nlink = in_stat.st_nlink;
+ out_stat.st_uid = in_stat.st_uid;
+ out_stat.st_gid = in_stat.st_gid;
+ out_stat.st_rdev = in_stat.st_rdev;
+ out_stat.st_size = in_stat.st_size;
+ out_stat.st_blksize = in_stat.st_blksize;
+ out_stat.st_blocks = in_stat.st_blocks;
+ out_stat.st_atim.tv_sec = in_stat.st_atime_;
+ out_stat.st_atim.tv_nsec = in_stat.st_atime_nsec_;
+ out_stat.st_mtim.tv_sec = in_stat.st_mtime_;
+ out_stat.st_mtim.tv_nsec = in_stat.st_mtime_nsec_;
+ out_stat.st_ctim.tv_sec = in_stat.st_ctime_;
+ out_stat.st_ctim.tv_nsec = in_stat.st_ctime_nsec_;
+}
} // namespace
// There are a variety of ways to make syscalls in a sandboxed process. One is
@@ -217,6 +238,10 @@ class Syscaller {
virtual int Open(const char* filepath, int flags) = 0;
virtual int Access(const char* filepath, int mode) = 0;
+ // NOTE: we use struct stat instead of default_stat_struct, to make the libc
+ // syscaller simpler. Copying from default_stat_struct (the structure returned
+ // from a stat sycall) to struct stat (the structure exposed by a libc to its
+ // users) is simpler than going in the opposite direction.
virtual int Stat(const char* filepath,
bool follow_links,
struct stat* statbuf) = 0;
@@ -243,8 +268,12 @@ class IPCSyscaller : public Syscaller {
int Stat(const char* filepath,
bool follow_links,
struct stat* statbuf) override {
- return broker_->GetBrokerClientSignalBased()->Stat(filepath, follow_links,
- statbuf);
+ default_stat_struct buf;
+ int ret = broker_->GetBrokerClientSignalBased()->DefaultStatForTesting(
+ filepath, follow_links, &buf);
+ if (ret >= 0)
+ ConvertKernelStatToLibcStat(buf, *statbuf);
+ return ret;
}
int Rename(const char* oldpath, const char* newpath) override {
@@ -300,10 +329,13 @@ class DirectSyscaller : public Syscaller {
int Stat(const char* filepath,
bool follow_links,
struct stat* statbuf) override {
- int ret = follow_links ? syscall(__NR_stat, filepath, statbuf)
- : syscall(__NR_lstat, filepath, statbuf);
+ struct kernel_stat buf;
+ int ret = syscall(__NR_newfstatat, AT_FDCWD, filepath, &buf,
+ follow_links ? 0 : AT_SYMLINK_NOFOLLOW);
if (ret < 0)
return -errno;
+
+ ConvertKernelStatToLibcStat(buf, *statbuf);
return ret;
}
@@ -1212,11 +1244,11 @@ class StatFileNoCommandDelegate final : public StatFileDelegate {
};
TEST(BrokerProcessIntegrationTest, StatFileNoCommandFollowLinks) {
- RunAllBrokerTests<StatFileNoCommandDelegate<true>>();
+ RunAllBrokerTests<StatFileNoCommandDelegate</*follow_links=*/true>>();
}
TEST(BrokerProcessIntegrationTest, StatFileNoCommandNoFollowLinks) {
- RunAllBrokerTests<StatFileNoCommandDelegate<false>>();
+ RunAllBrokerTests<StatFileNoCommandDelegate</*follow_links=*/false>>();
}
// Allows the STAT command without any file permissions.
@@ -1242,11 +1274,11 @@ class StatFilesNoPermissionDelegate final : public StatFileDelegate {
};
TEST(BrokerProcessIntegrationTest, StatFilesNoPermissionFollowLinks) {
- RunAllBrokerTests<StatFilesNoPermissionDelegate<true>>();
+ RunAllBrokerTests<StatFilesNoPermissionDelegate</*follow_links=*/true>>();
}
TEST(BrokerProcessIntegrationTest, StatFilesNoPermissionNoFollowLinks) {
- RunAllBrokerTests<StatFilesNoPermissionDelegate<false>>();
+ RunAllBrokerTests<StatFilesNoPermissionDelegate</*follow_links=*/false>>();
}
// Nonexistent file with permissions to see file.
@@ -1291,12 +1323,14 @@ class StatNonexistentFileWithPermissionsDelegate final
TEST(BrokerProcessIntegrationTest,
StatNonexistentFileWithPermissionsFollowLinks) {
- RunAllBrokerTests<StatNonexistentFileWithPermissionsDelegate<true>>();
+ RunAllBrokerTests<
+ StatNonexistentFileWithPermissionsDelegate</*follow_links=*/true>>();
}
TEST(BrokerProcessIntegrationTest,
StatNonexistentFileWithPermissionsNoFollowLinks) {
- RunAllBrokerTests<StatNonexistentFileWithPermissionsDelegate<false>>();
+ RunAllBrokerTests<
+ StatNonexistentFileWithPermissionsDelegate</*follow_links=*/false>>();
}
// Nonexistent file with permissions to create file.
@@ -1340,12 +1374,14 @@ class StatNonexistentFileWithCreatePermissionsDelegate final
TEST(BrokerProcessIntegrationTest,
StatNonexistentFileWithCreatePermissionsFollowLinks) {
- RunAllBrokerTests<StatNonexistentFileWithCreatePermissionsDelegate<true>>();
+ RunAllBrokerTests<StatNonexistentFileWithCreatePermissionsDelegate<
+ /*follow_links=*/true>>();
}
TEST(BrokerProcessIntegrationTest,
StatNonexistentFileWithCreatePermissionsNoFollowLinks) {
- RunAllBrokerTests<StatNonexistentFileWithCreatePermissionsDelegate<false>>();
+ RunAllBrokerTests<StatNonexistentFileWithCreatePermissionsDelegate<
+ /*follow_links=*/false>>();
}
// Actual file with permissions to see file.
@@ -1387,11 +1423,11 @@ class StatFileWithPermissionsDelegate final : public StatFileDelegate {
};
TEST(BrokerProcessIntegrationTest, StatFileWithPermissionsFollowLinks) {
- RunAllBrokerTests<StatFileWithPermissionsDelegate<true>>();
+ RunAllBrokerTests<StatFileWithPermissionsDelegate</*follow_links=*/true>>();
}
TEST(BrokerProcessIntegrationTest, StatFileWithPermissionsNoFollowLinks) {
- RunAllBrokerTests<StatFileWithPermissionsDelegate<false>>();
+ RunAllBrokerTests<StatFileWithPermissionsDelegate</*follow_links=*/false>>();
}
class RenameTestDelegate : public BrokerTestDelegate {
@@ -1421,6 +1457,16 @@ class RenameTestDelegate : public BrokerTestDelegate {
}
protected:
+ void ExpectRenamed() {
+ EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
+ EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
+ }
+
+ void ExpectNotRenamed() {
+ EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
+ EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
+ }
+
std::string oldpath_;
std::string newpath_;
};
@@ -1443,13 +1489,7 @@ class RenameNoCommandDelegate final : public RenameTestDelegate {
}
void ParentTearDown() override {
- if (true) {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
- } else {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
- }
+ ExpectNotRenamed();
RenameTestDelegate::ParentTearDown();
}
};
@@ -1474,13 +1514,7 @@ class RenameNoPermNewDelegate final : public RenameTestDelegate {
}
void ParentTearDown() override {
- if (true) {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
- } else {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
- }
+ ExpectNotRenamed();
RenameTestDelegate::ParentTearDown();
}
};
@@ -1505,13 +1539,7 @@ class RenameNoPermOldDelegate final : public RenameTestDelegate {
}
void ParentTearDown() override {
- if (true) {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
- } else {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
- }
+ ExpectNotRenamed();
RenameTestDelegate::ParentTearDown();
}
};
@@ -1538,13 +1566,7 @@ class RenameReadPermNewDelegate final : public RenameTestDelegate {
}
void ParentTearDown() override {
- if (true) {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
- } else {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
- }
+ ExpectNotRenamed();
RenameTestDelegate::ParentTearDown();
}
};
@@ -1571,13 +1593,7 @@ class RenameReadPermOldDelegate final : public RenameTestDelegate {
}
void ParentTearDown() override {
- if (true) {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
- } else {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
- }
+ ExpectNotRenamed();
RenameTestDelegate::ParentTearDown();
}
};
@@ -1603,13 +1619,7 @@ class RenameWritePermsBothDelegate final : public RenameTestDelegate {
}
void ParentTearDown() override {
- if (false) {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) == 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) < 0);
- } else {
- EXPECT_TRUE(access(oldpath_.c_str(), 0) < 0);
- EXPECT_TRUE(access(newpath_.c_str(), 0) == 0);
- }
+ ExpectRenamed();
RenameTestDelegate::ParentTearDown();
}
};
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/DEPS b/chromium/sandbox/linux/seccomp-bpf-helpers/DEPS
index 4419fd1da34..95d1bb6cbba 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/DEPS
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/DEPS
@@ -3,5 +3,4 @@ include_rules = [
"+sandbox/linux/seccomp-bpf",
"+sandbox/linux/services",
"+sandbox/linux/system_headers",
- "+third_party/lss/linux_syscall_support.h",
]
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index 05c39f0f564..049e921694e 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -20,6 +20,7 @@
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#if !defined(SO_PEEK_OFF)
@@ -170,6 +171,15 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
return Allow();
#endif
+ // V8 uses PKU (a.k.a. MPK / PKEY) for protecting code spaces.
+ if (sysno == __NR_pkey_alloc) {
+ return RestrictPkeyAllocFlags();
+ }
+
+ if (sysno == __NR_pkey_free) {
+ return Allow();
+ }
+
if (SyscallSets::IsClockApi(sysno)) {
return RestrictClockID();
}
@@ -178,6 +188,12 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
return RestrictCloneToThreadsAndEPERMFork();
}
+ // clone3 takes a pointer argument which we cannot examine, so return ENOSYS
+ // to force the libc to use clone. See https://crbug.com/1213452.
+ if (sysno == __NR_clone3) {
+ return Error(ENOSYS);
+ }
+
if (sysno == __NR_fcntl)
return RestrictFcntlCommands();
@@ -253,8 +269,11 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
return RestrictMmapFlags();
#endif
- if (sysno == __NR_mprotect)
+ if (sysno == __NR_mprotect || sysno == __NR_pkey_mprotect) {
+ // pkey_mprotect is identical to mprotect except for the additional (last)
+ // parameter, which can be ignored here.
return RestrictMprotectFlags();
+ }
if (sysno == __NR_prctl)
return RestrictPrctl();
@@ -286,6 +305,24 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
return Allow();
}
+ // The fstatat syscalls are file system syscalls, which will be denied below
+ // with fs_denied_errno. However some allowed fstat syscalls are rewritten by
+ // libc implementations to fstatat syscalls, and we need to rewrite them back.
+ if (sysno == __NR_fstatat_default) {
+ return RewriteFstatatSIGSYS(fs_denied_errno);
+ }
+
+ // The statx syscall is a filesystem syscall, which will be denied below with
+ // fs_denied_errno. However, on some platforms, glibc will default to statx
+ // for normal stat-family calls. Unfortunately there's no way to rewrite statx
+ // to something safe using a signal handler. Returning ENOSYS will cause glibc
+ // to fallback to old stat paths.
+ if (sysno == __NR_statx) {
+ const Arg<int> mask(3);
+ return If(mask == STATX_BASIC_STATS, Error(ENOSYS))
+ .Else(Error(fs_denied_errno));
+ }
+
if (SyscallSets::IsFileSystem(sysno) ||
SyscallSets::IsCurrentDirectory(sysno)) {
return Error(fs_denied_errno);
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index 68c29b564bb..57d307e09d3 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -51,7 +51,8 @@ namespace sandbox {
namespace {
-// This also tests that read(), write() and fstat() are allowed.
+// This also tests that read(), write(), fstat(), and fstatat(.., "", ..,
+// AT_EMPTY_PATH) are allowed.
void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) {
BPF_ASSERT_LE(0, read_end.get());
BPF_ASSERT_LE(0, write_end.get());
@@ -60,6 +61,20 @@ void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) {
BPF_ASSERT_EQ(0, sys_ret);
BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode));
+ sys_ret = fstatat(read_end.get(), "", &stat_buf, AT_EMPTY_PATH);
+ BPF_ASSERT_EQ(0, sys_ret);
+ BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode));
+
+ // Make sure fstatat with anything other than an empty string is denied.
+ sys_ret = fstatat(read_end.get(), "/", &stat_buf, AT_EMPTY_PATH);
+ BPF_ASSERT_EQ(sys_ret, -1);
+ BPF_ASSERT_EQ(EPERM, errno);
+
+ // Make sure fstatat without AT_EMPTY_PATH is denied.
+ sys_ret = fstatat(read_end.get(), "", &stat_buf, 0);
+ BPF_ASSERT_EQ(sys_ret, -1);
+ BPF_ASSERT_EQ(EPERM, errno);
+
const ssize_t kTestTransferSize = 4;
static const char kTestString[kTestTransferSize] = {'T', 'E', 'S', 'T'};
ssize_t transfered = 0;
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index 76eb32493f5..71068a04527 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -6,6 +6,7 @@
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@@ -13,15 +14,16 @@
#include <unistd.h>
#include "base/check.h"
+#include "base/cxx17_backports.h"
#include "base/debug/crash_logging.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/stl_util.h"
#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/seccomp-bpf/syscall.h"
#include "sandbox/linux/services/syscall_wrappers.h"
#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#if defined(__mips__)
@@ -355,6 +357,24 @@ intptr_t SIGSYSSchedHandler(const struct arch_seccomp_data& args,
return -ENOSYS;
}
+intptr_t SIGSYSFstatatHandler(const struct arch_seccomp_data& args,
+ void* fs_denied_errno) {
+ if (args.nr == __NR_fstatat_default) {
+ if (*reinterpret_cast<const char*>(args.args[1]) == '\0' &&
+ args.args[3] == static_cast<uint64_t>(AT_EMPTY_PATH)) {
+ return syscall(__NR_fstat_default, static_cast<int>(args.args[0]),
+ reinterpret_cast<default_stat_struct*>(args.args[2]));
+ }
+ return -reinterpret_cast<intptr_t>(fs_denied_errno);
+ }
+
+ CrashSIGSYS_Handler(args, fs_denied_errno);
+
+ // Should never be reached.
+ RAW_CHECK(false);
+ return -ENOSYS;
+}
+
bpf_dsl::ResultExpr CrashSIGSYS() {
return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL);
}
@@ -387,6 +407,11 @@ bpf_dsl::ResultExpr RewriteSchedSIGSYS() {
return bpf_dsl::Trap(SIGSYSSchedHandler, NULL);
}
+bpf_dsl::ResultExpr RewriteFstatatSIGSYS(int fs_denied_errno) {
+ return bpf_dsl::Trap(SIGSYSFstatatHandler,
+ reinterpret_cast<void*>(fs_denied_errno));
+}
+
void AllocateCrashKeys() {
#if !defined(OS_NACL_NONSFI)
if (seccomp_crash_key)
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
index 7a958b93b27..8cd735ce157 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
@@ -62,6 +62,19 @@ SANDBOX_EXPORT intptr_t SIGSYSPtraceFailure(const arch_seccomp_data& args,
// sched_setparam(), sched_setscheduler()
SANDBOX_EXPORT intptr_t SIGSYSSchedHandler(const arch_seccomp_data& args,
void* aux);
+// If the fstatat() syscall is functionally equivalent to an fstat() syscall,
+// then rewrite the syscall to the equivalent fstat() syscall which can be
+// adequately sandboxed.
+// If the fstatat() is not functionally equivalent to an fstat() syscall, we
+// fail with -fs_denied_errno.
+// If the syscall is not an fstatat() at all, crash in the same way as
+// CrashSIGSYS_Handler.
+// This is necessary because glibc and musl have started rewriting fstat(fd,
+// stat_buf) as fstatat(fd, "", stat_buf, AT_EMPTY_PATH). We rewrite the latter
+// back to the former, which is actually sandboxable.
+SANDBOX_EXPORT intptr_t
+SIGSYSFstatatHandler(const struct arch_seccomp_data& args,
+ void* fs_denied_errno);
// Variants of the above functions for use with bpf_dsl.
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS();
@@ -72,6 +85,7 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPtrace();
SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteSchedSIGSYS();
+SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteFstatatSIGSYS(int fs_denied_errno);
// Allocates a crash key so that Seccomp information can be recorded.
void AllocateCrashKeys();
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index cc0e91b203c..a8f860fcf08 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -64,6 +64,14 @@
#if defined(__mips__) && !defined(MAP_STACK)
#define MAP_STACK 0x40000
#endif
+
+// Temporary definitions for Arm's Memory Tagging Extension (MTE) and Branch
+// Target Identification (BTI).
+#if defined(ARCH_CPU_ARM64)
+#define PROT_MTE 0x20
+#define PROT_BTI 0x10
+#endif
+
namespace {
inline bool IsArchitectureX86_64() {
@@ -229,7 +237,15 @@ ResultExpr RestrictMprotectFlags() {
// "denied" mask because of the negation operator.
// Significantly, we don't permit weird undocumented flags such as
// PROT_GROWSDOWN.
- const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC;
+#if defined(ARCH_CPU_ARM64)
+ // Allows PROT_MTE and PROT_BTI (as explained higher up) on only Arm
+ // platforms.
+ const uint64_t kArchSpecificFlags = PROT_MTE | PROT_BTI;
+#else
+ const uint64_t kArchSpecificFlags = 0;
+#endif
+ const uint64_t kAllowedMask =
+ PROT_READ | PROT_WRITE | PROT_EXEC | kArchSpecificFlags;
const Arg<int> prot(2);
return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
}
@@ -446,4 +462,9 @@ ResultExpr RestrictPtrace() {
}
#endif // defined(OS_NACL_NONSFI)
+ResultExpr RestrictPkeyAllocFlags() {
+ const Arg<int> flags(0);
+ return If(flags == 0, Allow()).Else(CrashSIGSYS());
+}
+
} // namespace sandbox.
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index ba4289f05be..348970b39e7 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -39,6 +39,7 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMmapFlags();
// Restrict the prot argument in mprotect(2).
// Only allow: PROT_READ | PROT_WRITE | PROT_EXEC.
+// PROT_BTI | PROT_MTE is additionally allowed on 64-bit Arm.
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMprotectFlags();
// Restrict fcntl(2) cmd argument to:
@@ -113,6 +114,9 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimitToGetrlimit(pid_t target_pid);
// reporting. See https://crbug.com/933418 for details.
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPtrace();
+// Restrict the flags argument for pkey_alloc. It's specified to always be 0.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPkeyAllocFlags();
+
} // namespace sandbox.
#endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
index 903e702eab1..76c393032c1 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -37,10 +37,6 @@
#include "sandbox/linux/system_headers/linux_time.h"
#include "sandbox/linux/tests/unit_tests.h"
-#if !defined(OS_ANDROID)
-#include "third_party/lss/linux_syscall_support.h" // for MAKE_PROCESS_CPUCLOCK
-#endif
-
namespace sandbox {
namespace {
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index 96c9f490e28..8227dc18546 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -171,6 +171,7 @@ bool SyscallSets::IsFileSystem(int sysno) {
(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
case __NR_statfs64:
#endif
+ case __NR_statx: // EPERM not a valid errno.
case __NR_symlinkat:
case __NR_truncate:
#if defined(__i386__) || defined(__arm__) || \
diff --git a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
index e8fd90cde6c..d8e451d3e65 100644
--- a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/notreached.h"
#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/codegen.h"
#include "sandbox/linux/bpf_dsl/policy.h"
@@ -171,7 +172,6 @@ bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level, bool enable_ibpb) {
if (!supports_tsync) {
SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
"filters for a threadgroup");
- return false;
}
}
diff --git a/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc
index 2bc6619a3e9..39774c46802 100644
--- a/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc
+++ b/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -16,9 +16,9 @@
#include <vector>
+#include "base/cxx17_backports.h"
#include "base/memory/page_size.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/stl_util.h"
#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/policy.h"
diff --git a/chromium/sandbox/linux/seccomp-bpf/trap.cc b/chromium/sandbox/linux/seccomp-bpf/trap.cc
index f5b86a73ac7..cef1cddc0c3 100644
--- a/chromium/sandbox/linux/seccomp-bpf/trap.cc
+++ b/chromium/sandbox/linux/seccomp-bpf/trap.cc
@@ -280,8 +280,6 @@ uint16_t Trap::Add(TrapFnc fnc, const void* aux, bool safe) {
SANDBOX_DIE(
"Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
"is enabled");
-
- return 0;
}
// Each unique pair of TrapFnc and auxiliary data make up a distinct instance
diff --git a/chromium/sandbox/linux/services/credentials.cc b/chromium/sandbox/linux/services/credentials.cc
index d7b5d8c4413..67025a7dde1 100644
--- a/chromium/sandbox/linux/services/credentials.cc
+++ b/chromium/sandbox/linux/services/credentials.cc
@@ -18,12 +18,12 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h"
-#include "base/stl_util.h"
#include "build/build_config.h"
#include "sandbox/linux/services/namespace_utils.h"
#include "sandbox/linux/services/proc_util.h"
diff --git a/chromium/sandbox/linux/services/libc_interceptor.cc b/chromium/sandbox/linux/services/libc_interceptor.cc
index fd4ff9156a5..c08a450f070 100644
--- a/chromium/sandbox/linux/services/libc_interceptor.cc
+++ b/chromium/sandbox/linux/services/libc_interceptor.cc
@@ -23,11 +23,14 @@
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/global_descriptors.h"
#include "base/posix/unix_domain_socket.h"
#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
namespace sandbox {
@@ -119,6 +122,8 @@ void ProxyLocaltimeCallToBrowser(time_t input,
struct tm* output,
char* timezone_out,
size_t timezone_out_len) {
+ base::ElapsedTimer timer;
+
base::Pickle request;
request.WriteInt(METHOD_LOCALTIME);
request.WriteString(
@@ -137,6 +142,11 @@ void ProxyLocaltimeCallToBrowser(time_t input,
if (!ReadTimeStruct(&iter, output, timezone_out, timezone_out_len)) {
memset(output, 0, sizeof(struct tm));
}
+
+ base::UmaHistogramCustomMicrosecondsTimes(
+ "Linux.ProxyLocaltimeCallToBrowserUs", timer.Elapsed(),
+ base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(1),
+ /*buckets=*/50);
}
// The other side of this call is ProxyLocaltimeCallToBrowser().
diff --git a/chromium/sandbox/linux/services/namespace_sandbox.cc b/chromium/sandbox/linux/services/namespace_sandbox.cc
index d5d0f68e274..3ae22651576 100644
--- a/chromium/sandbox/linux/services/namespace_sandbox.cc
+++ b/chromium/sandbox/linux/services/namespace_sandbox.cc
@@ -17,12 +17,12 @@
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/cxx17_backports.h"
#include "base/environment.h"
#include "base/files/scoped_file.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h"
#include "base/process/process.h"
-#include "base/stl_util.h"
#include "build/build_config.h"
#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/namespace_utils.h"
diff --git a/chromium/sandbox/linux/services/syscall_wrappers.cc b/chromium/sandbox/linux/services/syscall_wrappers.cc
index fcfd2aa129d..3bec18a14e9 100644
--- a/chromium/sandbox/linux/services/syscall_wrappers.cc
+++ b/chromium/sandbox/linux/services/syscall_wrappers.cc
@@ -4,6 +4,7 @@
#include "sandbox/linux/services/syscall_wrappers.h"
+#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <setjmp.h>
@@ -14,11 +15,13 @@
#include <unistd.h>
#include <cstring>
+#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "sandbox/linux/system_headers/capability.h"
#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
namespace sandbox {
@@ -217,7 +220,7 @@ asm(
#undef STR
#undef XSTR
-#endif
+#endif // defined(ARCH_CPU_X86_FAMILY)
int sys_sigaction(int signum,
const struct sigaction* act,
@@ -241,7 +244,7 @@ int sys_sigaction(int signum,
#error "Unsupported architecture."
#endif
}
-#endif
+#endif // defined(ARCH_CPU_X86_FAMILY)
}
LinuxSigAction linux_oldact = {};
@@ -259,6 +262,47 @@ int sys_sigaction(int signum,
return result;
}
-#endif // defined(MEMORY_SANITIZER)
+#endif // !defined(OS_NACL_NONSFI)
+
+int sys_stat(const char* path, struct kernel_stat* stat_buf) {
+ int res;
+#if !defined(__NR_stat)
+ res = syscall(__NR_newfstatat, AT_FDCWD, path, stat_buf, 0);
+#else
+ res = syscall(__NR_stat, path, stat_buf);
+#endif
+ if (res == 0)
+ MSAN_UNPOISON(stat_buf, sizeof(*stat_buf));
+ return res;
+}
+
+int sys_lstat(const char* path, struct kernel_stat* stat_buf) {
+ int res;
+#if !defined(__NR_lstat)
+ res = syscall(__NR_newfstatat, AT_FDCWD, path, stat_buf, AT_SYMLINK_NOFOLLOW);
+#else
+ res = syscall(__NR_lstat, path, stat_buf);
+#endif
+ if (res == 0)
+ MSAN_UNPOISON(stat_buf, sizeof(*stat_buf));
+ return res;
+}
+
+int sys_fstatat64(int dirfd,
+ const char* pathname,
+ struct kernel_stat64* stat_buf,
+ int flags) {
+#if defined(__NR_fstatat64)
+ int res = syscall(__NR_fstatat64, dirfd, pathname, stat_buf, flags);
+ if (res == 0)
+ MSAN_UNPOISON(stat_buf, sizeof(*stat_buf));
+ return res;
+#else // defined(__NR_fstatat64)
+ // We should not reach here on 64-bit systems, as the *stat*64() are only
+ // necessary on 32-bit.
+ RAW_CHECK(false);
+ return -ENOSYS;
+#endif
+}
} // namespace sandbox
diff --git a/chromium/sandbox/linux/services/syscall_wrappers.h b/chromium/sandbox/linux/services/syscall_wrappers.h
index 1975bfbd88a..b55340e4a26 100644
--- a/chromium/sandbox/linux/services/syscall_wrappers.h
+++ b/chromium/sandbox/linux/services/syscall_wrappers.h
@@ -17,6 +17,8 @@ struct sock_fprog;
struct rlimit64;
struct cap_hdr;
struct cap_data;
+struct kernel_stat;
+struct kernel_stat64;
namespace sandbox {
@@ -84,6 +86,19 @@ SANDBOX_EXPORT int sys_sigaction(int signum,
const struct sigaction* act,
struct sigaction* oldact);
+// Some architectures do not have stat() and lstat() syscalls. In that case,
+// these wrappers will use newfstatat(), which is available on all other
+// architectures, with the same capabilities as stat() and lstat().
+SANDBOX_EXPORT int sys_stat(const char* path, struct kernel_stat* stat_buf);
+SANDBOX_EXPORT int sys_lstat(const char* path, struct kernel_stat* stat_buf);
+
+// Takes care of unpoisoning |stat_buf| for MSAN. Check-fails if fstatat64() is
+// not a supported syscall on the current platform.
+SANDBOX_EXPORT int sys_fstatat64(int dirfd,
+ const char* pathname,
+ struct kernel_stat64* stat_buf,
+ int flags);
+
} // namespace sandbox
#endif // SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
diff --git a/chromium/sandbox/linux/services/syscall_wrappers_unittest.cc b/chromium/sandbox/linux/services/syscall_wrappers_unittest.cc
index 32820f60a8c..723ff3b672e 100644
--- a/chromium/sandbox/linux/services/syscall_wrappers_unittest.cc
+++ b/chromium/sandbox/linux/services/syscall_wrappers_unittest.cc
@@ -4,16 +4,21 @@
#include "sandbox/linux/services/syscall_wrappers.h"
+#include <fcntl.h>
#include <stdint.h>
+#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <cstring>
+#include "base/logging.h"
+#include "base/memory/page_size.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
+#include "sandbox/linux/tests/scoped_temporary_file.h"
#include "sandbox/linux/tests/test_utils.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -93,6 +98,184 @@ TEST(SyscallWrappers, LinuxSigSet) {
linux_sigset);
}
+TEST(SyscallWrappers, Stat) {
+ // Create a file to stat, with 12 bytes of data.
+ ScopedTemporaryFile tmp_file;
+ EXPECT_EQ(12, write(tmp_file.fd(), "blahblahblah", 12));
+
+ // To test we have the correct stat structures for each kernel/platform, we
+ // will right-align them on a page, with a guard page after.
+ char* two_pages = static_cast<char*>(TestUtils::MapPagesOrDie(2));
+ TestUtils::MprotectLastPageOrDie(two_pages, 2);
+ char* page1_end = two_pages + base::GetPageSize();
+
+ // First, check that calling stat with |stat_buf| pointing to the last byte on
+ // a page causes EFAULT.
+ int res = sys_stat(tmp_file.full_file_name(),
+ reinterpret_cast<struct kernel_stat*>(page1_end - 1));
+ ASSERT_EQ(res, -1);
+ if (res < 0 && errno == EOVERFLOW) {
+ GTEST_SKIP();
+ }
+ ASSERT_EQ(errno, EFAULT);
+
+ // Now, check that we have the correctly sized stat structure.
+ struct kernel_stat* sb = reinterpret_cast<struct kernel_stat*>(
+ page1_end - sizeof(struct kernel_stat));
+ // Memset to c's so we can check the kernel zero'd the padding...
+ memset(sb, 'c', sizeof(struct kernel_stat));
+ res = sys_stat(tmp_file.full_file_name(), sb);
+ ASSERT_EQ(res, 0);
+
+ // Following fields may never be consistent but should be non-zero.
+ // Don't trust the platform to define fields with any particular sign.
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_dev));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_ino));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_mode));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_blksize));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_blocks));
+
+// We are the ones that made the file.
+// Note: normally gid and uid overflow on backwards-compatible 32-bit systems
+// and we end up with dummy uids and gids in place here.
+#if defined(ARCH_CPU_64_BITS)
+ EXPECT_EQ(geteuid(), sb->st_uid);
+ EXPECT_EQ(getegid(), sb->st_gid);
+#endif
+
+ // Wrote 12 bytes above which should fit in one block.
+ EXPECT_EQ(12u, sb->st_size);
+
+ // Can't go backwards in time, 1500000000 was some time ago.
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_atime_));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_mtime_));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_ctime_));
+
+ // Checking the padding for good measure.
+#if defined(__x86_64__)
+ EXPECT_EQ(0u, sb->__pad0);
+ EXPECT_EQ(0u, sb->__unused4[0]);
+ EXPECT_EQ(0u, sb->__unused4[1]);
+ EXPECT_EQ(0u, sb->__unused4[2]);
+#elif defined(__aarch64__)
+ EXPECT_EQ(0u, sb->__pad1);
+ EXPECT_EQ(0, sb->__pad2);
+ EXPECT_EQ(0u, sb->__unused4);
+ EXPECT_EQ(0u, sb->__unused5);
+#endif
+}
+
+#if defined(__NR_fstatat64)
+TEST(SyscallWrappers, Stat64) {
+ static_assert(sizeof(struct kernel_stat64) == sizeof(default_stat_struct),
+ "This test only works on systems where the default_stat_struct "
+ "is kernel_stat64");
+ // Create a file to stat, with 12 bytes of data.
+ ScopedTemporaryFile tmp_file;
+ EXPECT_EQ(12, write(tmp_file.fd(), "blahblahblah", 12));
+
+ // To test we have the correct stat structures for each kernel/platform, we
+ // will right-align them on a page, with a guard page after.
+ char* two_pages = static_cast<char*>(TestUtils::MapPagesOrDie(2));
+ TestUtils::MprotectLastPageOrDie(two_pages, 2);
+ char* page1_end = two_pages + base::GetPageSize();
+
+ // First, check that calling stat with |stat_buf| pointing to the last byte on
+ // a page causes EFAULT.
+ int res =
+ sys_fstatat64(AT_FDCWD, tmp_file.full_file_name(),
+ reinterpret_cast<struct kernel_stat64*>(page1_end - 1), 0);
+ ASSERT_EQ(res, -1);
+ ASSERT_EQ(errno, EFAULT);
+
+ // Now, check that we have the correctly sized stat structure.
+ struct kernel_stat64* sb = reinterpret_cast<struct kernel_stat64*>(
+ page1_end - sizeof(struct kernel_stat64));
+ memset(sb, 0, sizeof(struct kernel_stat64));
+ res = sys_fstatat64(AT_FDCWD, tmp_file.full_file_name(), sb, 0);
+ ASSERT_EQ(res, 0);
+
+ // Following fields may never be consistent but should be non-zero.
+ // Don't trust the platform to define fields with any particular sign.
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_dev));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_ino));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_mode));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_blksize));
+ EXPECT_NE(0u, static_cast<unsigned int>(sb->st_blocks));
+
+ // We are the ones that made the file.
+ EXPECT_EQ(geteuid(), sb->st_uid);
+ EXPECT_EQ(getegid(), sb->st_gid);
+
+ // Wrote 12 bytes above which should fit in one block.
+ EXPECT_EQ(12, sb->st_size);
+
+ // Can't go backwards in time, 1500000000 was some time ago.
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_atime_));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_mtime_));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb->st_ctime_));
+}
+#endif // defined(__NR_fstatat64)
+
+TEST(SyscallWrappers, LStat) {
+ // Create a file to stat, with 12 bytes of data.
+ ScopedTemporaryFile tmp_file;
+ EXPECT_EQ(12, write(tmp_file.fd(), "blahblahblah", 12));
+
+ // Also create a symlink.
+ std::string symlink_name;
+ {
+ ScopedTemporaryFile tmp_file2;
+ symlink_name = tmp_file2.full_file_name();
+ }
+ int rc = symlink(tmp_file.full_file_name(), symlink_name.c_str());
+ if (rc != 0) {
+ PLOG(ERROR) << "Couldn't symlink " << symlink_name << " to target "
+ << tmp_file.full_file_name();
+ GTEST_FAIL();
+ }
+
+ struct kernel_stat lstat_info;
+ rc = sys_lstat(symlink_name.c_str(), &lstat_info);
+ if (rc < 0 && errno == EOVERFLOW) {
+ GTEST_SKIP();
+ }
+ if (rc != 0) {
+ PLOG(ERROR) << "Couldn't sys_lstat " << symlink_name;
+ GTEST_FAIL();
+ }
+
+ struct kernel_stat stat_info;
+ rc = sys_stat(symlink_name.c_str(), &stat_info);
+ if (rc < 0 && errno == EOVERFLOW) {
+ GTEST_SKIP();
+ }
+ if (rc != 0) {
+ PLOG(ERROR) << "Couldn't sys_stat " << symlink_name;
+ GTEST_FAIL();
+ }
+
+ struct kernel_stat tmp_file_stat_info;
+ rc = sys_stat(tmp_file.full_file_name(), &tmp_file_stat_info);
+ if (rc < 0 && errno == EOVERFLOW) {
+ GTEST_SKIP();
+ }
+ if (rc != 0) {
+ PLOG(ERROR) << "Couldn't sys_stat " << tmp_file.full_file_name();
+ GTEST_FAIL();
+ }
+
+ // lstat should produce information about a symlink.
+ ASSERT_TRUE(S_ISLNK(lstat_info.st_mode));
+
+ // stat-ing symlink_name and tmp_file should produce the same inode.
+ ASSERT_EQ(stat_info.st_ino, tmp_file_stat_info.st_ino);
+
+ // lstat-ing symlink_name should give a different inode than stat-ing
+ // symlink_name.
+ ASSERT_NE(stat_info.st_ino, lstat_info.st_ino);
+}
+
} // namespace
} // namespace sandbox
diff --git a/chromium/sandbox/linux/suid/client/setuid_sandbox_host.cc b/chromium/sandbox/linux/suid/client/setuid_sandbox_host.cc
index f88c5077c6d..7022a65e035 100644
--- a/chromium/sandbox/linux/suid/client/setuid_sandbox_host.cc
+++ b/chromium/sandbox/linux/suid/client/setuid_sandbox_host.cc
@@ -15,6 +15,7 @@
#include <utility>
#include "base/command_line.h"
+#include "base/cxx17_backports.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -24,7 +25,6 @@
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h"
#include "base/process/process_metrics.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "sandbox/linux/suid/common/sandbox.h"
#include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
diff --git a/chromium/sandbox/linux/suid/sandbox.c b/chromium/sandbox/linux/suid/sandbox.c
index 5ee1689e234..2bedcb34f2d 100644
--- a/chromium/sandbox/linux/suid/sandbox.c
+++ b/chromium/sandbox/linux/suid/sandbox.c
@@ -480,6 +480,4 @@ int main(int argc, char** argv) {
execv(argv[1], &argv[1]);
FatalError("execv failed");
-
- return 1;
}
diff --git a/chromium/sandbox/linux/syscall_broker/DEPS b/chromium/sandbox/linux/syscall_broker/DEPS
index c477f7d3639..149c463b068 100644
--- a/chromium/sandbox/linux/syscall_broker/DEPS
+++ b/chromium/sandbox/linux/syscall_broker/DEPS
@@ -1,4 +1,5 @@
include_rules = [
- "+sandbox/linux/system_headers",
"+sandbox/linux/bpf_dsl",
+ "+sandbox/linux/services",
+ "+sandbox/linux/system_headers",
]
diff --git a/chromium/sandbox/linux/syscall_broker/broker_client.cc b/chromium/sandbox/linux/syscall_broker/broker_client.cc
index 6b1b5be4338..e24f659fcf8 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_client.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_client.cc
@@ -166,7 +166,7 @@ int BrokerClient::Rmdir(const char* path) const {
int BrokerClient::Stat(const char* pathname,
bool follow_links,
- struct stat* sb) const {
+ struct kernel_stat* sb) const {
if (!pathname || !sb)
return -EFAULT;
@@ -181,7 +181,7 @@ int BrokerClient::Stat(const char* pathname,
int BrokerClient::Stat64(const char* pathname,
bool follow_links,
- struct stat64* sb) const {
+ struct kernel_stat64* sb) const {
if (!pathname || !sb)
return -EFAULT;
diff --git a/chromium/sandbox/linux/syscall_broker/broker_client.h b/chromium/sandbox/linux/syscall_broker/broker_client.h
index 05e14c83f20..26ca78101c7 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_client.h
+++ b/chromium/sandbox/linux/syscall_broker/broker_client.h
@@ -61,10 +61,10 @@ class SANDBOX_EXPORT BrokerClient : public SyscallDispatcher {
int Rmdir(const char* path) const override;
int Stat(const char* pathname,
bool follow_links,
- struct stat* sb) const override;
+ struct kernel_stat* sb) const override;
int Stat64(const char* pathname,
bool follow_links,
- struct stat64* sb) const override;
+ struct kernel_stat64* sb) const override;
int Unlink(const char* unlink) const override;
private:
diff --git a/chromium/sandbox/linux/syscall_broker/broker_host.cc b/chromium/sandbox/linux/syscall_broker/broker_host.cc
index 1cd03a18df8..1cdc01a888f 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_host.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_host.cc
@@ -20,9 +20,11 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
#include "sandbox/linux/syscall_broker/broker_command.h"
#include "sandbox/linux/syscall_broker/broker_permission_list.h"
#include "sandbox/linux/syscall_broker/broker_simple_message.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
namespace sandbox {
@@ -193,10 +195,12 @@ void StatFileForIPC(const BrokerCommandSet& allowed_command_set,
RAW_CHECK(reply->AddIntToMessage(-permission_list.denied_errno()));
return;
}
+
if (command_type == COMMAND_STAT) {
- struct stat sb;
- int sts =
- follow_links ? stat(file_to_access, &sb) : lstat(file_to_access, &sb);
+ struct kernel_stat sb;
+
+ int sts = follow_links ? sandbox::sys_stat(file_to_access, &sb)
+ : sandbox::sys_lstat(file_to_access, &sb);
if (sts < 0) {
RAW_CHECK(reply->AddIntToMessage(-errno));
return;
@@ -205,10 +209,12 @@ void StatFileForIPC(const BrokerCommandSet& allowed_command_set,
RAW_CHECK(
reply->AddDataToMessage(reinterpret_cast<char*>(&sb), sizeof(sb)));
} else {
+#if defined(__NR_fstatat64)
DCHECK(command_type == COMMAND_STAT64);
- struct stat64 sb;
- int sts = follow_links ? stat64(file_to_access, &sb)
- : lstat64(file_to_access, &sb);
+ struct kernel_stat64 sb;
+
+ int sts = sandbox::sys_fstatat64(AT_FDCWD, file_to_access, &sb,
+ follow_links ? 0 : AT_SYMLINK_NOFOLLOW);
if (sts < 0) {
RAW_CHECK(reply->AddIntToMessage(-errno));
return;
@@ -216,6 +222,11 @@ void StatFileForIPC(const BrokerCommandSet& allowed_command_set,
RAW_CHECK(reply->AddIntToMessage(0));
RAW_CHECK(
reply->AddDataToMessage(reinterpret_cast<char*>(&sb), sizeof(sb)));
+#else // defined(__NR_fstatat64)
+ // We should not reach here on 64-bit systems, as the *stat*64() are only
+ // necessary on 32-bit.
+ RAW_CHECK(false);
+#endif
}
}
diff --git a/chromium/sandbox/linux/syscall_broker/broker_process.cc b/chromium/sandbox/linux/syscall_broker/broker_process.cc
index c2176eb785e..e9dad37485a 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_process.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_process.cc
@@ -113,44 +113,49 @@ bool BrokerProcess::IsSyscallAllowed(int sysno) const {
}
bool BrokerProcess::IsSyscallBrokerable(int sysno, bool fast_check) const {
+ // The syscalls unavailable on aarch64 are all blocked by Android's default
+ // seccomp policy, even on non-aarch64 architectures. I.e., the syscalls XX()
+ // with a corresponding XXat() versions are typically unavailable in aarch64
+ // and are default disabled in Android. So, we should refuse to broker them
+ // to be consistent with the platform's restrictions.
switch (sysno) {
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_access:
#endif
case __NR_faccessat:
return !fast_check || allowed_command_set_.test(COMMAND_ACCESS);
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_mkdir:
#endif
case __NR_mkdirat:
return !fast_check || allowed_command_set_.test(COMMAND_MKDIR);
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_open:
#endif
case __NR_openat:
return !fast_check || allowed_command_set_.test(COMMAND_OPEN);
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_readlink:
#endif
case __NR_readlinkat:
return !fast_check || allowed_command_set_.test(COMMAND_READLINK);
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_rename:
#endif
case __NR_renameat:
case __NR_renameat2:
return !fast_check || allowed_command_set_.test(COMMAND_RENAME);
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_rmdir:
return !fast_check || allowed_command_set_.test(COMMAND_RMDIR);
#endif
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_stat:
case __NR_lstat:
#endif
@@ -175,7 +180,7 @@ bool BrokerProcess::IsSyscallBrokerable(int sysno, bool fast_check) const {
return !fast_check || allowed_command_set_.test(COMMAND_STAT);
#endif
-#if !defined(__aarch64__)
+#if !defined(__aarch64__) && !defined(OS_ANDROID)
case __NR_unlink:
return !fast_check || allowed_command_set_.test(COMMAND_UNLINK);
#endif
diff --git a/chromium/sandbox/linux/syscall_broker/broker_process_unittest.cc b/chromium/sandbox/linux/syscall_broker/broker_process_unittest.cc
index 08096b95aa3..f0db08d84e0 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_process_unittest.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -23,12 +23,12 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
+#include "base/cxx17_backports.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "sandbox/linux/syscall_broker/broker_client.h"
@@ -811,7 +811,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
const char* bad_leading_path5 = "/mbogo/fictitioux";
const char* bad_leading_path6 = "/mbogo/fictitiousa";
- struct stat sb;
+ default_stat_struct sb;
{
// Actual file with permissions to see file but command not allowed.
@@ -824,7 +824,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
memset(&sb, 0, sizeof(sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
tempfile_name, follow_links, &sb));
}
@@ -840,7 +840,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
memset(&sb, 0, sizeof(sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
nonesuch_name, follow_links, &sb));
}
{
@@ -852,7 +852,7 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
memset(&sb, 0, sizeof(sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
tempfile_name, follow_links, &sb));
}
{
@@ -864,38 +864,39 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
ASSERT_TRUE(open_broker.Init(base::BindOnce(&NoOpCallback)));
memset(&sb, 0, sizeof(sb));
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
- nonesuch_name, follow_links, &sb));
+ EXPECT_EQ(-ENOENT,
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
+ nonesuch_name, follow_links, &sb));
// Gets denied all the way back to root since no create permission.
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
leading_path1, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
leading_path2, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
leading_path3, follow_links, &sb));
// Not fooled by substrings.
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path1, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path2, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path3, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path4, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path5, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path6, follow_links, &sb));
}
{
@@ -907,37 +908,41 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
ASSERT_TRUE(open_broker.Init(base::BindOnce(&NoOpCallback)));
memset(&sb, 0, sizeof(sb));
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
- nonesuch_name, follow_links, &sb));
+ EXPECT_EQ(-ENOENT,
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
+ nonesuch_name, follow_links, &sb));
// Gets ENOENT all the way back to root since it has create permission.
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
- leading_path1, follow_links, &sb));
- EXPECT_EQ(-ENOENT, open_broker.GetBrokerClientSignalBased()->Stat(
- leading_path2, follow_links, &sb));
+ EXPECT_EQ(-ENOENT,
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
+ leading_path1, follow_links, &sb));
+ EXPECT_EQ(-ENOENT,
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
+ leading_path2, follow_links, &sb));
// But can always get the root.
- EXPECT_EQ(0, open_broker.GetBrokerClientSignalBased()->Stat(
- leading_path3, follow_links, &sb));
+ EXPECT_EQ(0,
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
+ leading_path3, follow_links, &sb));
// Not fooled by substrings.
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path1, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path2, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path3, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path4, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path5, follow_links, &sb));
EXPECT_EQ(-kFakeErrnoSentinel,
- open_broker.GetBrokerClientSignalBased()->Stat(
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
bad_leading_path6, follow_links, &sb));
}
{
@@ -949,8 +954,9 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
ASSERT_TRUE(open_broker.Init(base::BindOnce(&NoOpCallback)));
memset(&sb, 0, sizeof(sb));
- EXPECT_EQ(0, open_broker.GetBrokerClientSignalBased()->Stat(
- tempfile_name, follow_links, &sb));
+ EXPECT_EQ(0,
+ open_broker.GetBrokerClientSignalBased()->DefaultStatForTesting(
+ tempfile_name, follow_links, &sb));
// Following fields may never be consistent but should be non-zero.
// Don't trust the platform to define fields with any particular sign.
@@ -968,9 +974,9 @@ void TestStatHelper(bool fast_check_in_client, bool follow_links) {
EXPECT_EQ(12, sb.st_size);
// Can't go backwards in time, 1500000000 was some time ago.
- EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_atime));
- EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_mtime));
- EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_ctime));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_atime_));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_mtime_));
+ EXPECT_LT(1500000000u, static_cast<unsigned int>(sb.st_ctime_));
}
}
@@ -1590,52 +1596,52 @@ TEST(BrokerProcess, IsSyscallAllowed) {
const base::flat_map<BrokerCommand, base::flat_set<int>> kSysnosForCommand = {
{COMMAND_ACCESS,
{__NR_faccessat,
-#if defined(__NR_access)
+#if defined(__NR_access) && !defined(OS_ANDROID)
__NR_access
#endif
}},
{COMMAND_MKDIR,
{__NR_mkdirat,
-#if defined(__NR_mkdir)
+#if defined(__NR_mkdir) && !defined(OS_ANDROID)
__NR_mkdir
#endif
}},
{COMMAND_OPEN,
{__NR_openat,
-#if defined(__NR_open)
+#if defined(__NR_open) && !defined(OS_ANDROID)
__NR_open
#endif
}},
{COMMAND_READLINK,
{__NR_readlinkat,
-#if defined(__NR_readlink)
+#if defined(__NR_readlink) && !defined(OS_ANDROID)
__NR_readlink
#endif
}},
{COMMAND_RENAME,
{__NR_renameat,
-#if defined(__NR_rename)
+#if defined(__NR_rename) && !defined(OS_ANDROID)
__NR_rename
#endif
}},
{COMMAND_UNLINK,
{__NR_unlinkat,
-#if defined(__NR_unlink)
+#if defined(__NR_unlink) && !defined(OS_ANDROID)
__NR_unlink
#endif
}},
{COMMAND_RMDIR,
{__NR_unlinkat,
-#if defined(__NR_rmdir)
+#if defined(__NR_rmdir) && !defined(OS_ANDROID)
__NR_rmdir
#endif
}},
{COMMAND_STAT,
{
-#if defined(__NR_stat)
+#if defined(__NR_stat) && !defined(OS_ANDROID)
__NR_stat,
#endif
-#if defined(__NR_lstat)
+#if defined(__NR_lstat) && !defined(OS_ANDROID)
__NR_lstat,
#endif
#if defined(__NR_fstatat)
diff --git a/chromium/sandbox/linux/syscall_broker/broker_simple_message_unittest.cc b/chromium/sandbox/linux/syscall_broker/broker_simple_message_unittest.cc
index d64cba22281..c3aca7d522d 100644
--- a/chromium/sandbox/linux/syscall_broker/broker_simple_message_unittest.cc
+++ b/chromium/sandbox/linux/syscall_broker/broker_simple_message_unittest.cc
@@ -61,7 +61,7 @@ class ExpectedResultDataValue : public ExpectedResultValue {
class ExpectedResultIntValue : public ExpectedResultValue {
public:
- ExpectedResultIntValue(int value);
+ explicit ExpectedResultIntValue(int value);
bool NextMessagePieceMatches(BrokerSimpleMessage* message) override;
size_t Size() override;
diff --git a/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler.cc b/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler.cc
index 1ba5890daff..256586e141b 100644
--- a/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler.cc
+++ b/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler.cc
@@ -138,7 +138,7 @@ RemoteProcessIOResult ReadFilePathFromRemoteProcess(pid_t pid,
namespace internal {
uintptr_t NumBytesLeftInPage(uintptr_t addr) {
- const uintptr_t page_end = base::bits::Align(addr + 1, base::GetPageSize());
+ const uintptr_t page_end = base::bits::AlignUp(addr + 1, base::GetPageSize());
return page_end - addr;
}
} // namespace internal
diff --git a/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc b/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc
index fffa9bb7082..f517a9867c5 100644
--- a/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc
+++ b/chromium/sandbox/linux/syscall_broker/remote_syscall_arg_handler_unittest.cc
@@ -16,6 +16,7 @@
#include "base/memory/page_size.h"
#include "base/posix/unix_domain_socket.h"
#include "base/test/bind.h"
+#include "sandbox/linux/tests/test_utils.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,19 +53,6 @@ void VerifyCorrectString(std::string str, size_t size) {
}
}
-void* MapPagesOrDie(size_t num_pages) {
- void* addr = mmap(nullptr, num_pages * base::GetPageSize(),
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- PCHECK(addr);
- return addr;
-}
-
-void MprotectLastPageOrDie(char* addr, size_t num_pages) {
- size_t last_page_offset = (num_pages - 1) * base::GetPageSize();
- PCHECK(mprotect(addr + last_page_offset, base::GetPageSize(), PROT_NONE) >=
- 0);
-}
-
pid_t ForkWaitingChild(base::OnceCallback<void(int)>
after_parent_signals_callback = base::DoNothing(),
base::ScopedFD* parent_sync_fd = nullptr) {
@@ -105,13 +93,13 @@ void ReadTest(const ReadTestConfig& test_config) {
size_t total_pages = (test_config.start_at + test_config.total_size +
base::GetPageSize() - 1) /
base::GetPageSize();
- char* mmap_addr = static_cast<char*>(MapPagesOrDie(total_pages));
+ char* mmap_addr = static_cast<char*>(TestUtils::MapPagesOrDie(total_pages));
char* addr = mmap_addr + test_config.start_at;
FillBufferWithPath(addr, test_config.total_size,
test_config.include_null_byte);
if (test_config.last_page_inaccessible)
- MprotectLastPageOrDie(mmap_addr, total_pages);
+ TestUtils::MprotectLastPageOrDie(mmap_addr, total_pages);
pid_t pid = ForkWaitingChild();
munmap(mmap_addr, base::GetPageSize() * total_pages);
@@ -212,7 +200,7 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, ReadChunkPlus1EndingOnePastPage) {
}
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, ReadChildExited) {
- void* addr = MapPagesOrDie(1);
+ void* addr = TestUtils::MapPagesOrDie(1);
FillBufferWithPath(static_cast<char*>(addr), strlen(kPathPart) + 1, true);
base::ScopedFD parent_sync, child_sync;
@@ -240,10 +228,10 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, ReadChildExited) {
}
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, BasicWrite) {
- void* read_from = MapPagesOrDie(1);
+ void* read_from = TestUtils::MapPagesOrDie(1);
const size_t write_size = base::GetPageSize();
FillBufferWithPath(static_cast<char*>(read_from), write_size, false);
- char* write_to = static_cast<char*>(MapPagesOrDie(1));
+ char* write_to = static_cast<char*>(TestUtils::MapPagesOrDie(1));
base::ScopedFD parent_signal_fd;
const std::vector<int> empty_fd_vec;
@@ -278,8 +266,8 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, BasicWrite) {
}
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WriteToInvalidAddress) {
- char* write_to = static_cast<char*>(MapPagesOrDie(1));
- MprotectLastPageOrDie(write_to, 1);
+ char* write_to = static_cast<char*>(TestUtils::MapPagesOrDie(1));
+ TestUtils::MprotectLastPageOrDie(write_to, 1);
base::ScopedFD parent_signal_fd;
const std::vector<int> empty_fd_vec;
@@ -295,11 +283,11 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WriteToInvalidAddress) {
}
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WritePartiallyToInvalidAddress) {
- char* read_from = static_cast<char*>(MapPagesOrDie(2));
+ char* read_from = static_cast<char*>(TestUtils::MapPagesOrDie(2));
const size_t write_size = base::GetPageSize();
FillBufferWithPath(static_cast<char*>(read_from), write_size, false);
- char* write_to = static_cast<char*>(MapPagesOrDie(2));
- MprotectLastPageOrDie(write_to, 2);
+ char* write_to = static_cast<char*>(TestUtils::MapPagesOrDie(2));
+ TestUtils::MprotectLastPageOrDie(write_to, 2);
write_to += base::GetPageSize() / 2;
base::ScopedFD parent_signal_fd;
const std::vector<int> empty_fd_vec;
@@ -314,7 +302,7 @@ SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WritePartiallyToInvalidAddress) {
}
SANDBOX_TEST(BrokerRemoteSyscallArgHandler, WriteChildExited) {
- char* addr = static_cast<char*>(MapPagesOrDie(1));
+ char* addr = static_cast<char*>(TestUtils::MapPagesOrDie(1));
FillBufferWithPath(static_cast<char*>(addr), strlen(kPathPart) + 1, true);
base::ScopedFD parent_sync, child_sync;
diff --git a/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.cc b/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.cc
index b9ee93c14ac..8a42397ef87 100644
--- a/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.cc
+++ b/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.cc
@@ -19,8 +19,18 @@ namespace syscall_broker {
#define BROKER_UNPOISON_STRING(x)
#endif
+int SyscallDispatcher::DefaultStatForTesting(const char* pathname,
+ bool follow_links,
+ default_stat_struct* sb) {
+#if defined(__NR_fstatat64)
+ return Stat64(pathname, follow_links, sb);
+#elif defined(__NR_newfstatat)
+ return Stat(pathname, follow_links, sb);
+#endif
+}
+
int SyscallDispatcher::PerformStatat(const arch_seccomp_data& args,
- bool arch64) {
+ bool stat64) {
if (static_cast<int>(args.args[0]) != AT_FDCWD)
return -EPERM;
// Only allow the AT_SYMLINK_NOFOLLOW flag which is used by some libc
@@ -30,13 +40,29 @@ int SyscallDispatcher::PerformStatat(const arch_seccomp_data& args,
const bool follow_links =
!(static_cast<int>(args.args[3]) & AT_SYMLINK_NOFOLLOW);
- if (arch64) {
+ if (stat64) {
return Stat64(reinterpret_cast<const char*>(args.args[1]), follow_links,
- reinterpret_cast<struct stat64*>(args.args[2]));
+ reinterpret_cast<struct kernel_stat64*>(args.args[2]));
}
return Stat(reinterpret_cast<const char*>(args.args[1]), follow_links,
- reinterpret_cast<struct stat*>(args.args[2]));
+ reinterpret_cast<struct kernel_stat*>(args.args[2]));
+}
+
+int SyscallDispatcher::PerformUnlinkat(const arch_seccomp_data& args) {
+ if (static_cast<int>(args.args[0]) != AT_FDCWD)
+ return -EPERM;
+
+ int flags = static_cast<int>(args.args[2]);
+
+ if (flags == AT_REMOVEDIR) {
+ return Rmdir(reinterpret_cast<const char*>(args.args[1]));
+ }
+
+ if (flags != 0)
+ return -EPERM;
+
+ return Unlink(reinterpret_cast<const char*>(args.args[1]));
}
int SyscallDispatcher::DispatchSyscall(const arch_seccomp_data& args) {
@@ -127,59 +153,42 @@ int SyscallDispatcher::DispatchSyscall(const arch_seccomp_data& args) {
#if defined(__NR_stat)
case __NR_stat:
return Stat(reinterpret_cast<const char*>(args.args[0]), true,
- reinterpret_cast<struct stat*>(args.args[1]));
+ reinterpret_cast<struct kernel_stat*>(args.args[1]));
#endif
#if defined(__NR_stat64)
case __NR_stat64:
return Stat64(reinterpret_cast<const char*>(args.args[0]), true,
- reinterpret_cast<struct stat64*>(args.args[1]));
+ reinterpret_cast<struct kernel_stat64*>(args.args[1]));
#endif
#if defined(__NR_lstat)
case __NR_lstat:
// See https://crbug.com/847096
BROKER_UNPOISON_STRING(reinterpret_cast<const char*>(args.args[0]));
return Stat(reinterpret_cast<const char*>(args.args[0]), false,
- reinterpret_cast<struct stat*>(args.args[1]));
+ reinterpret_cast<struct kernel_stat*>(args.args[1]));
#endif
#if defined(__NR_lstat64)
case __NR_lstat64:
// See https://crbug.com/847096
BROKER_UNPOISON_STRING(reinterpret_cast<const char*>(args.args[0]));
return Stat64(reinterpret_cast<const char*>(args.args[0]), false,
- reinterpret_cast<struct stat64*>(args.args[1]));
-#endif
-#if defined(__NR_fstatat)
- case __NR_fstatat:
- return PerformStatat(args, /*arch64=*/false);
+ reinterpret_cast<struct kernel_stat64*>(args.args[1]));
#endif
#if defined(__NR_fstatat64)
case __NR_fstatat64:
- return PerformStatat(args, /*arch64=*/true);
+ return PerformStatat(args, /*stat64=*/true);
#endif
#if defined(__NR_newfstatat)
case __NR_newfstatat:
- return PerformStatat(args, /*arch64=*/false);
+ return PerformStatat(args, /*stat64=*/false);
#endif
#if defined(__NR_unlink)
case __NR_unlink:
return Unlink(reinterpret_cast<const char*>(args.args[0]));
#endif
#if defined(__NR_unlinkat)
- case __NR_unlinkat: {
- if (static_cast<int>(args.args[0]) != AT_FDCWD)
- return -EPERM;
-
- int flags = static_cast<int>(args.args[2]);
-
- if (flags == AT_REMOVEDIR) {
- return Rmdir(reinterpret_cast<const char*>(args.args[1]));
- }
-
- if (flags != 0)
- return -EPERM;
-
- return Unlink(reinterpret_cast<const char*>(args.args[1]));
- }
+ case __NR_unlinkat:
+ return PerformUnlinkat(args);
#endif // defined(__NR_unlinkat)
default:
RAW_CHECK(false);
diff --git a/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.h b/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.h
index d8b8874ad9c..1d6653caf3b 100644
--- a/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.h
+++ b/chromium/sandbox/linux/syscall_broker/syscall_dispatcher.h
@@ -9,13 +9,15 @@
#include <cstddef>
#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_stat.h"
+#include "sandbox/sandbox_export.h"
namespace sandbox {
namespace syscall_broker {
// An abstract class that defines all the system calls we perform for the
// sandboxed process.
-class SyscallDispatcher {
+class SANDBOX_EXPORT SyscallDispatcher {
public:
// Emulates access()/faccessat().
// X_OK will always return an error in practice since the broker process
@@ -40,19 +42,34 @@ class SyscallDispatcher {
virtual int Rmdir(const char* path) const = 0;
// Emulates stat()/stat64()/lstat()/lstat64()/fstatat()/newfstatat().
+ // Stat64 is only available on 32-bit systems.
virtual int Stat(const char* pathname,
bool follow_links,
- struct stat* sb) const = 0;
+ struct kernel_stat* sb) const = 0;
virtual int Stat64(const char* pathname,
bool follow_links,
- struct stat64* sb) const = 0;
+ struct kernel_stat64* sb) const = 0;
// Emulates unlink()/unlinkat().
virtual int Unlink(const char* unlink) const = 0;
+ // Different architectures use a different syscall from the stat family by
+ // default in glibc. E.g. 32-bit systems use *stat*64() and fill out struct
+ // kernel_stat64, whereas 64-bit systems use *stat*() and fill out struct
+ // kernel_stat. Some tests want to call the SyscallDispatcher directly, and
+ // should be using the default stat in order to test against glibc.
+ int DefaultStatForTesting(const char* pathname,
+ bool follow_links,
+ default_stat_struct* sb);
+
// Validates the args passed to a *statat*() syscall and performs the syscall
- // using Stat() or Stat64().
- int PerformStatat(const arch_seccomp_data& args, bool arch64);
+ // using Stat(), or on 32-bit systems it uses Stat64() for the *statat64()
+ // syscalls.
+ int PerformStatat(const arch_seccomp_data& args, bool stat64);
+
+ // Validates the args passed to an unlinkat() syscall and performs the syscall
+ // using either Unlink() or Rmdir().
+ int PerformUnlinkat(const arch_seccomp_data& args);
// Reads the syscall number and arguments, imposes some policy (e.g. the *at()
// system calls must only allow AT_FDCWD as the first argument), and
diff --git a/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h b/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h
index a242c18c842..ab86b36353c 100644
--- a/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h
@@ -1119,4 +1119,100 @@
#define __NR_rseq 293
#endif
+#if !defined(__NR_kexec_file_load)
+#define __NR_kexec_file_load 294
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal 424
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup 425
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter 426
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register 427
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree 428
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount 429
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen 430
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig 431
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount 432
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick 433
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open 434
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 435
+#endif
+
+#if !defined(__NR_close_range)
+#define __NR_close_range 436
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 437
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd 438
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 439
+#endif
+
+#if !defined(__NR_process_madvise)
+#define __NR_process_madvise 440
+#endif
+
+#if !defined(__NR_epoll_pwait2)
+#define __NR_epoll_pwait2 441
+#endif
+
+#if !defined(__NR_mount_setattr)
+#define __NR_mount_setattr 442
+#endif
+
+#if !defined(__NR_quotactl_path)
+#define __NR_quotactl_path 443
+#endif
+
+#if !defined(__NR_landlock_create_ruleset)
+#define __NR_landlock_create_ruleset 444
+#endif
+
+#if !defined(__NR_landlock_add_rule)
+#define __NR_landlock_add_rule 445
+#endif
+
+#if !defined(__NR_landlock_restrict_self)
+#define __NR_landlock_restrict_self 446
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
diff --git a/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h b/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h
index 85da6f41c66..9c44368a8ee 100644
--- a/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h
@@ -1605,6 +1605,18 @@
#define __NR_mount_setattr (__NR_SYSCALL_BASE + 442)
#endif
+#if !defined(__NR_landlock_create_ruleset)
+#define __NR_landlock_create_ruleset (__NR_SYSCALL_BASE + 444)
+#endif
+
+#if !defined(__NR_landlock_add_rule)
+#define __NR_landlock_add_rule (__NR_SYSCALL_BASE + 445)
+#endif
+
+#if !defined(__NR_landlock_restrict_self)
+#define __NR_landlock_restrict_self (__NR_SYSCALL_BASE + 446)
+#endif
+
// ARM private syscalls.
#if !defined(__ARM_NR_BASE)
#define __ARM_NR_BASE (__NR_SYSCALL_BASE + 0xF0000)
diff --git a/chromium/sandbox/linux/system_headers/linux_stat.h b/chromium/sandbox/linux/system_headers/linux_stat.h
new file mode 100644
index 00000000000..e697dd6777e
--- /dev/null
+++ b/chromium/sandbox/linux/system_headers/linux_stat.h
@@ -0,0 +1,196 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_STAT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_STAT_H_
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+#if defined(ARCH_CPU_MIPS_FAMILY)
+#if defined(ARCH_CPU_64_BITS)
+struct kernel_stat {
+#else
+struct kernel_stat64 {
+#endif
+ unsigned st_dev;
+ unsigned __pad0[3];
+ unsigned long long st_ino;
+ unsigned st_mode;
+ unsigned st_nlink;
+ unsigned st_uid;
+ unsigned st_gid;
+ unsigned st_rdev;
+ unsigned __pad1[3];
+ long long st_size;
+ unsigned st_atime_;
+ unsigned st_atime_nsec_;
+ unsigned st_mtime_;
+ unsigned st_mtime_nsec_;
+ unsigned st_ctime_;
+ unsigned st_ctime_nsec_;
+ unsigned st_blksize;
+ unsigned __pad2;
+ unsigned long long st_blocks;
+};
+#else
+struct kernel_stat64 {
+ unsigned long long st_dev;
+ unsigned char __pad0[4];
+ unsigned __st_ino;
+ unsigned st_mode;
+ unsigned st_nlink;
+ unsigned st_uid;
+ unsigned st_gid;
+ unsigned long long st_rdev;
+ unsigned char __pad3[4];
+ long long st_size;
+ unsigned st_blksize;
+ unsigned long long st_blocks;
+ unsigned st_atime_;
+ unsigned st_atime_nsec_;
+ unsigned st_mtime_;
+ unsigned st_mtime_nsec_;
+ unsigned st_ctime_;
+ unsigned st_ctime_nsec_;
+ unsigned long long st_ino;
+};
+#endif
+
+#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__)
+struct kernel_stat {
+ /* The kernel headers suggest that st_dev and st_rdev should be 32bit
+ * quantities encoding 12bit major and 20bit minor numbers in an interleaved
+ * format. In reality, we do not see useful data in the top bits. So,
+ * we'll leave the padding in here, until we find a better solution.
+ */
+ unsigned short st_dev;
+ short pad1;
+ unsigned st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ short pad2;
+ unsigned st_size;
+ unsigned st_blksize;
+ unsigned st_blocks;
+ unsigned st_atime_;
+ unsigned st_atime_nsec_;
+ unsigned st_mtime_;
+ unsigned st_mtime_nsec_;
+ unsigned st_ctime_;
+ unsigned st_ctime_nsec_;
+ unsigned __unused4;
+ unsigned __unused5;
+};
+#elif defined(__x86_64__)
+struct kernel_stat {
+ uint64_t st_dev;
+ uint64_t st_ino;
+ uint64_t st_nlink;
+ unsigned st_mode;
+ unsigned st_uid;
+ unsigned st_gid;
+ unsigned __pad0;
+ uint64_t st_rdev;
+ int64_t st_size;
+ int64_t st_blksize;
+ int64_t st_blocks;
+ uint64_t st_atime_;
+ uint64_t st_atime_nsec_;
+ uint64_t st_mtime_;
+ uint64_t st_mtime_nsec_;
+ uint64_t st_ctime_;
+ uint64_t st_ctime_nsec_;
+ int64_t __unused4[3];
+};
+#elif (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
+struct kernel_stat {
+ unsigned st_dev;
+ int st_pad1[3];
+ unsigned st_ino;
+ unsigned st_mode;
+ unsigned st_nlink;
+ unsigned st_uid;
+ unsigned st_gid;
+ unsigned st_rdev;
+ int st_pad2[2];
+ long st_size;
+ int st_pad3;
+ long st_atime_;
+ long st_atime_nsec_;
+ long st_mtime_;
+ long st_mtime_nsec_;
+ long st_ctime_;
+ long st_ctime_nsec_;
+ int st_blksize;
+ int st_blocks;
+ int st_pad4[14];
+};
+#elif defined(__aarch64__)
+struct kernel_stat {
+ unsigned long st_dev;
+ unsigned long st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned long st_rdev;
+ unsigned long __pad1;
+ long st_size;
+ int st_blksize;
+ int __pad2;
+ long st_blocks;
+ long st_atime_;
+ unsigned long st_atime_nsec_;
+ long st_mtime_;
+ unsigned long st_mtime_nsec_;
+ long st_ctime_;
+ unsigned long st_ctime_nsec_;
+ unsigned int __unused4;
+ unsigned int __unused5;
+};
+#endif
+
+#if !defined(AT_EMPTY_PATH)
+#define AT_EMPTY_PATH 0x1000
+#endif
+
+#if !defined(STATX_BASIC_STATS)
+#define STATX_BASIC_STATS 0x000007ffU
+#endif
+
+// On 32-bit systems, we default to the 64-bit stat struct like libc
+// implementations do. Otherwise we default to the normal stat struct which is
+// already 64-bit.
+// These defines make it easy to call the right syscall to fill out a 64-bit
+// stat struct, which is the default in libc implementations but requires
+// different syscall names on 32 and 64-bit platforms.
+#if defined(__NR_fstatat64)
+
+namespace sandbox {
+using default_stat_struct = struct kernel_stat64;
+} // namespace sandbox
+
+#define __NR_fstatat_default __NR_fstatat64
+#define __NR_fstat_default __NR_fstat64
+
+#elif defined(__NR_newfstatat)
+
+namespace sandbox {
+using default_stat_struct = struct kernel_stat;
+} // namespace sandbox
+
+#define __NR_fstatat_default __NR_newfstatat
+#define __NR_fstat_default __NR_fstat
+
+#else
+#error "one of fstatat64 and newfstatat must be defined"
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_STAT_H_
diff --git a/chromium/sandbox/linux/system_headers/linux_time.h b/chromium/sandbox/linux/system_headers/linux_time.h
index 780f24dddd9..f18c806611f 100644
--- a/chromium/sandbox/linux/system_headers/linux_time.h
+++ b/chromium/sandbox/linux/system_headers/linux_time.h
@@ -11,6 +11,32 @@
#define CPUCLOCK_CLOCK_MASK 3
#endif
+#if !defined(CPUCLOCK_PROF)
+#define CPUCLOCK_PROF 0
+#endif
+
+#if !defined(CPUCLOCK_VIRT)
+#define CPUCLOCK_VIRT 1
+#endif
+
+#if !defined(CPUCLOCK_SCHED)
+#define CPUCLOCK_SCHED 2
+#endif
+
+#if !defined(CPUCLOCK_PERTHREAD_MASK)
+#define CPUCLOCK_PERTHREAD_MASK 4
+#endif
+
+#if !defined(MAKE_PROCESS_CPUCLOCK)
+#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
+ ((int)(~(unsigned)(pid) << 3) | (int)(clock))
+#endif
+
+#if !defined(MAKE_THREAD_CPUCLOCK)
+#define MAKE_THREAD_CPUCLOCK(tid, clock) \
+ ((int)(~(unsigned)(tid) << 3) | (int)((clock) | CPUCLOCK_PERTHREAD_MASK))
+#endif
+
#if !defined(CLOCKFD)
#define CLOCKFD 3
#endif
diff --git a/chromium/sandbox/linux/system_headers/mips64_linux_syscalls.h b/chromium/sandbox/linux/system_headers/mips64_linux_syscalls.h
index ec75815a842..ae7cb48f57c 100644
--- a/chromium/sandbox/linux/system_headers/mips64_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/mips64_linux_syscalls.h
@@ -1271,4 +1271,148 @@
#define __NR_memfd_create (__NR_Linux + 314)
#endif
+#if !defined(__NR_bpf)
+#define __NR_bpf (__NR_Linux + 315)
+#endif
+
+#if !defined(__NR_execveat)
+#define __NR_execveat (__NR_Linux + 316)
+#endif
+
+#if !defined(__NR_userfaultfd)
+#define __NR_userfaultfd (__NR_Linux + 317)
+#endif
+
+#if !defined(__NR_membarrier)
+#define __NR_membarrier (__NR_Linux + 318)
+#endif
+
+#if !defined(__NR_mlock2)
+#define __NR_mlock2 (__NR_Linux + 319)
+#endif
+
+#if !defined(__NR_copy_file_range)
+#define __NR_copy_file_range (__NR_Linux + 320)
+#endif
+
+#if !defined(__NR_preadv2)
+#define __NR_preadv2 (__NR_Linux + 321)
+#endif
+
+#if !defined(__NR_pwritev2)
+#define __NR_pwritev2 (__NR_Linux + 322)
+#endif
+
+#if !defined(__NR_pkey_mprotect)
+#define __NR_pkey_mprotect (__NR_Linux + 323)
+#endif
+
+#if !defined(__NR_pkey_alloc)
+#define __NR_pkey_alloc (__NR_Linux + 324)
+#endif
+
+#if !defined(__NR_pkey_free)
+#define __NR_pkey_free (__NR_Linux + 325)
+#endif
+
+#if !defined(__NR_statx)
+#define __NR_statx (__NR_Linux + 326)
+#endif
+
+#if !defined(__NR_rseq)
+#define __NR_rseq (__NR_Linux + 327)
+#endif
+
+#if !defined(__NR_io_pgetevents)
+#define __NR_io_pgetevents (__NR_Linux + 328)
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal (__NR_Linux + 424)
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup (__NR_Linux + 425)
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter (__NR_Linux + 426)
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register (__NR_Linux + 427)
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree (__NR_Linux + 428)
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount (__NR_Linux + 429)
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen (__NR_Linux + 430)
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig (__NR_Linux + 431)
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount (__NR_Linux + 432)
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick (__NR_Linux + 433)
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open (__NR_Linux + 434)
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 (__NR_Linux + 435)
+#endif
+
+#if !defined(__NR_close_range)
+#define __NR_close_range (__NR_Linux + 436)
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 (__NR_Linux + 437)
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd (__NR_Linux + 438)
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 (__NR_Linux + 439)
+#endif
+
+#if !defined(__NR_process_madvise)
+#define __NR_process_madvise (__NR_Linux + 440)
+#endif
+
+#if !defined(__NR_epoll_pwait2)
+#define __NR_epoll_pwait2 (__NR_Linux + 441)
+#endif
+
+#if !defined(__NR_mount_setattr)
+#define __NR_mount_setattr (__NR_Linux + 442)
+#endif
+
+#if !defined(__NR_landlock_create_ruleset)
+#define __NR_landlock_create_ruleset (__NR_Linux + 444)
+#endif
+
+#if !defined(__NR_landlock_add_rule)
+#define __NR_landlock_add_rule (__NR_Linux + 445)
+#endif
+
+#if !defined(__NR_landlock_restrict_self)
+#define __NR_landlock_restrict_self (__NR_Linux + 446)
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
diff --git a/chromium/sandbox/linux/system_headers/mips_linux_syscalls.h b/chromium/sandbox/linux/system_headers/mips_linux_syscalls.h
index 50d9ea11bfa..093778288bb 100644
--- a/chromium/sandbox/linux/system_headers/mips_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/mips_linux_syscalls.h
@@ -1685,4 +1685,16 @@
#define __NR_mount_setattr (__NR_Linux + 442)
#endif
+#if !defined(__NR_landlock_create_ruleset)
+#define __NR_landlock_create_ruleset (__NR_Linux + 444)
+#endif
+
+#if !defined(__NR_landlock_add_rule)
+#define __NR_landlock_add_rule (__NR_Linux + 445)
+#endif
+
+#if !defined(__NR_landlock_restrict_self)
+#define __NR_landlock_restrict_self (__NR_Linux + 446)
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
diff --git a/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
index 1720edb1810..2c81a930138 100644
--- a/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
@@ -1738,5 +1738,17 @@
#define __NR_mount_setattr 442
#endif
+#if !defined(__NR_landlock_create_ruleset)
+#define __NR_landlock_create_ruleset 444
+#endif
+
+#if !defined(__NR_landlock_add_rule)
+#define __NR_landlock_add_rule 445
+#endif
+
+#if !defined(__NR_landlock_restrict_self)
+#define __NR_landlock_restrict_self 446
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
diff --git a/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h b/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h
index b0ae0a2edf6..e618c6237b0 100644
--- a/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h
+++ b/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h
@@ -1350,5 +1350,93 @@
#define __NR_rseq 334
#endif
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal 424
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup 425
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter 426
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register 427
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree 428
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount 429
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen 430
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig 431
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount 432
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick 433
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open 434
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 435
+#endif
+
+#if !defined(__NR_close_range)
+#define __NR_close_range 436
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 437
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd 438
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 439
+#endif
+
+#if !defined(__NR_process_madvise)
+#define __NR_process_madvise 440
+#endif
+
+#if !defined(__NR_epoll_pwait2)
+#define __NR_epoll_pwait2 441
+#endif
+
+#if !defined(__NR_mount_setattr)
+#define __NR_mount_setattr 442
+#endif
+
+#if !defined(__NR_landlock_create_ruleset)
+#define __NR_landlock_create_ruleset 444
+#endif
+
+#if !defined(__NR_landlock_add_rule)
+#define __NR_landlock_add_rule 445
+#endif
+
+#if !defined(__NR_landlock_restrict_self)
+#define __NR_landlock_restrict_self 446
+#endif
+
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
diff --git a/chromium/sandbox/mac/seatbelt_extension_unittest.cc b/chromium/sandbox/mac/seatbelt_extension_unittest.cc
index 2a746886742..ef1d7ceecb1 100644
--- a/chromium/sandbox/mac/seatbelt_extension_unittest.cc
+++ b/chromium/sandbox/mac/seatbelt_extension_unittest.cc
@@ -7,11 +7,11 @@
#include <unistd.h>
#include "base/command_line.h"
+#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/stl_util.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "sandbox/mac/sandbox_compiler.h"
diff --git a/chromium/sandbox/policy/BUILD.gn b/chromium/sandbox/policy/BUILD.gn
index 7dfa7764de3..69828e5bb9f 100644
--- a/chromium/sandbox/policy/BUILD.gn
+++ b/chromium/sandbox/policy/BUILD.gn
@@ -10,6 +10,7 @@ import("//chromeos/assistant/assistant.gni")
import("//printing/buildflags/buildflags.gni")
import("//testing/test.gni")
+# Most consumers of sandbox::policy should depend on this target.
component("policy") {
sources = [
"export.h",
@@ -30,6 +31,7 @@ component("policy") {
"//build:chromeos_buildflags",
"//printing/buildflags",
"//sandbox:common",
+ "//sandbox/policy/mojom",
]
public_deps = []
if (is_linux || is_chromeos) {
@@ -92,7 +94,7 @@ component("policy") {
]
deps += [ "//chromeos/assistant:buildflags" ]
- if (enable_libassistant_sandbox) {
+ if (enable_cros_libassistant) {
sources += [
"linux/bpf_libassistant_policy_linux.cc",
"linux/bpf_libassistant_policy_linux.h",
diff --git a/chromium/sandbox/policy/features.cc b/chromium/sandbox/policy/features.cc
index 8ba5f501bda..4922dad3810 100644
--- a/chromium/sandbox/policy/features.cc
+++ b/chromium/sandbox/policy/features.cc
@@ -4,6 +4,7 @@
#include "sandbox/policy/features.h"
+#include "base/win/windows_version.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -24,10 +25,10 @@ const base::Feature kNetworkServiceSandbox{"NetworkServiceSandbox",
const base::Feature kWinSboxDisableKtmComponent{
"WinSboxDisableKtmComponent", base::FEATURE_ENABLED_BY_DEFAULT};
-// Emergency "off switch" for new Windows sandbox security mitigation,
+// Experiment for Windows sandbox security mitigation,
// sandbox::MITIGATION_EXTENSION_POINT_DISABLE.
const base::Feature kWinSboxDisableExtensionPoints{
- "WinSboxDisableExtensionPoint", base::FEATURE_ENABLED_BY_DEFAULT};
+ "WinSboxDisableExtensionPoint", base::FEATURE_DISABLED_BY_DEFAULT};
// Enables GPU AppContainer sandbox on Windows.
const base::Feature kGpuAppContainer{"GpuAppContainer",
@@ -36,10 +37,6 @@ const base::Feature kGpuAppContainer{"GpuAppContainer",
// Enables GPU Low Privilege AppContainer when combined with kGpuAppContainer.
const base::Feature kGpuLPAC{"GpuLPAC", base::FEATURE_ENABLED_BY_DEFAULT};
-// Use LPAC for network sandbox instead of restricted token. Relies on
-// NetworkServiceSandbox being also enabled.
-const base::Feature kNetworkServiceSandboxLPAC{
- "NetworkServiceSandboxLPAC", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_WIN)
#if !defined(OS_ANDROID)
@@ -61,6 +58,23 @@ const base::Feature kForceSpectreVariant2Mitigation{
"ForceSpectreVariant2Mitigation", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_WIN)
+bool IsNetworkServiceSandboxLPACEnabled() {
+ // Use LPAC for network sandbox instead of restricted token. Relies on
+ // NetworkServiceSandbox being also enabled.
+ const base::Feature kNetworkServiceSandboxLPAC{
+ "NetworkServiceSandboxLPAC", base::FEATURE_DISABLED_BY_DEFAULT};
+
+ // Since some APIs used for LPAC are unsupported below Windows 10, place a
+ // check here in a central place.
+ if (base::win::GetVersion() < base::win::Version::WIN10)
+ return false;
+
+ return base::FeatureList::IsEnabled(kNetworkServiceSandbox) &&
+ base::FeatureList::IsEnabled(kNetworkServiceSandboxLPAC);
+}
+#endif // defined(OS_WIN)
+
} // namespace features
} // namespace policy
} // namespace sandbox
diff --git a/chromium/sandbox/policy/features.h b/chromium/sandbox/policy/features.h
index 6de7bbd6742..86b7d433e92 100644
--- a/chromium/sandbox/policy/features.h
+++ b/chromium/sandbox/policy/features.h
@@ -26,7 +26,6 @@ SANDBOX_POLICY_EXPORT extern const base::Feature kWinSboxDisableKtmComponent;
SANDBOX_POLICY_EXPORT extern const base::Feature kWinSboxDisableExtensionPoints;
SANDBOX_POLICY_EXPORT extern const base::Feature kGpuAppContainer;
SANDBOX_POLICY_EXPORT extern const base::Feature kGpuLPAC;
-SANDBOX_POLICY_EXPORT extern const base::Feature kNetworkServiceSandboxLPAC;
#endif // defined(OS_WIN)
#if !defined(OS_ANDROID)
@@ -39,6 +38,10 @@ SANDBOX_POLICY_EXPORT extern const base::Feature
kForceSpectreVariant2Mitigation;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#if defined(OS_WIN)
+// Returns whether Network Service Sandbox is enabled in LPAC mode.
+SANDBOX_POLICY_EXPORT bool IsNetworkServiceSandboxLPACEnabled();
+#endif
} // namespace features
} // namespace policy
} // namespace sandbox
diff --git a/chromium/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc b/chromium/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
index e105eee8c06..c08356d7830 100644
--- a/chromium/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
+++ b/chromium/sandbox/policy/fuchsia/sandbox_policy_fuchsia.cc
@@ -13,6 +13,7 @@
#include <fuchsia/fonts/cpp/fidl.h>
#include <fuchsia/intl/cpp/fidl.h>
#include <fuchsia/logger/cpp/fidl.h>
+#include <fuchsia/media/cpp/fidl.h>
#include <fuchsia/mediacodec/cpp/fidl.h>
#include <fuchsia/memorypressure/cpp/fidl.h>
#include <fuchsia/net/cpp/fidl.h>
@@ -66,6 +67,8 @@ struct SandboxConfig {
constexpr SandboxConfig kGpuConfig = {
base::make_span((const char* const[]){
+ // TODO(crbug.com/1224707): Use the fuchsia.scheduler API instead.
+ fuchsia::media::ProfileProvider::Name_,
fuchsia::sysmem::Allocator::Name_,
"fuchsia.vulkan.loader.Loader",
fuchsia::ui::scenic::Scenic::Name_,
@@ -76,6 +79,7 @@ constexpr SandboxConfig kGpuConfig = {
constexpr SandboxConfig kNetworkConfig = {
base::make_span((const char* const[]){
fuchsia::net::NameLookup::Name_,
+ "fuchsia.net.name.Lookup",
fuchsia::net::interfaces::State::Name_,
"fuchsia.posix.socket.Provider",
}),
@@ -85,6 +89,8 @@ constexpr SandboxConfig kNetworkConfig = {
constexpr SandboxConfig kRendererConfig = {
base::make_span((const char* const[]){
fuchsia::fonts::Provider::Name_,
+ // TODO(crbug.com/1224707): Use the fuchsia.scheduler API instead.
+ fuchsia::media::ProfileProvider::Name_,
fuchsia::mediacodec::CodecFactory::Name_,
fuchsia::memorypressure::Provider::Name_,
fuchsia::sysmem::Allocator::Name_,
@@ -227,20 +233,20 @@ void SandboxPolicyFuchsia::UpdateLaunchOptionsForSandbox(
options->paths_to_clone.push_back(base::FilePath("/config/ssl"));
if (config->features & kProvideVulkanResources) {
- // /dev/class/gpu and /config/vulkan/icd.d are to used configure and
- // access the GPU.
- options->paths_to_clone.push_back(base::FilePath("/dev/class/gpu"));
- const auto vulkan_icd_path = base::FilePath("/config/vulkan/icd.d");
- if (base::PathExists(vulkan_icd_path))
- options->paths_to_clone.push_back(vulkan_icd_path);
-
- // The following devices are used for Fuchsia Emulator.
- options->paths_to_clone.insert(
- options->paths_to_clone.end(),
- {base::FilePath("/dev/class/goldfish-address-space"),
- base::FilePath("/dev/class/goldfish-control"),
- base::FilePath("/dev/class/goldfish-pipe"),
- base::FilePath("/dev/class/goldfish-sync")});
+ static const char* const kPathsToCloneForVulkan[] = {
+ // Used configure and access the GPU.
+ "/dev/class/gpu", "/config/vulkan/icd.d",
+ // Used for Fuchsia Emulator.
+ "/dev/class/goldfish-address-space", "/dev/class/goldfish-control",
+ "/dev/class/goldfish-pipe", "/dev/class/goldfish-sync"};
+ for (const char* path_str : kPathsToCloneForVulkan) {
+ base::FilePath path(path_str);
+ // Vulkan paths aren't needed with newer Fuchsia versions, so they may not
+ // be available.
+ if (base::PathExists(path)) {
+ options->paths_to_clone.push_back(path);
+ }
+ }
}
// If the process needs access to any services then transfer the
diff --git a/chromium/sandbox/policy/linux/bpf_broker_policy_linux.cc b/chromium/sandbox/policy/linux/bpf_broker_policy_linux.cc
index 2963bb9ca86..6dc8c0581b4 100644
--- a/chromium/sandbox/policy/linux/bpf_broker_policy_linux.cc
+++ b/chromium/sandbox/policy/linux/bpf_broker_policy_linux.cc
@@ -93,8 +93,8 @@ ResultExpr BrokerProcessPolicy::EvaluateSyscall(int sysno) const {
return Allow();
break;
#endif
-#if defined(__NR_fstatat)
- case __NR_fstatat:
+#if defined(__NR_fstatat64)
+ case __NR_fstatat64:
if (allowed_command_set_.test(syscall_broker::COMMAND_STAT))
return Allow();
break;
diff --git a/chromium/sandbox/policy/linux/bpf_cros_arm_gpu_policy_linux.cc b/chromium/sandbox/policy/linux/bpf_cros_arm_gpu_policy_linux.cc
index 76e310533b6..124b4c32fab 100644
--- a/chromium/sandbox/policy/linux/bpf_cros_arm_gpu_policy_linux.cc
+++ b/chromium/sandbox/policy/linux/bpf_cros_arm_gpu_policy_linux.cc
@@ -53,6 +53,14 @@ ResultExpr CrosArmGpuProcessPolicy::EvaluateSyscall(int sysno) const {
case __NR_sched_setscheduler:
case __NR_sysinfo:
case __NR_uname:
+ // We need fstatfs for supporting a local glibc patch
+ // which hooks into dlopen(), LD_PRELOAD, and --preload.
+ // https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/2910526
+ case __NR_fstatfs:
+#if defined(__arm__)
+ // Only available on ARM 32bit devices
+ case __NR_fstatfs64:
+#endif
return Allow();
// Allow only AF_UNIX for |domain|.
case __NR_socket:
diff --git a/chromium/sandbox/policy/linux/bpf_libassistant_policy_linux.cc b/chromium/sandbox/policy/linux/bpf_libassistant_policy_linux.cc
index a00dd4fdc04..f235efa9f57 100644
--- a/chromium/sandbox/policy/linux/bpf_libassistant_policy_linux.cc
+++ b/chromium/sandbox/policy/linux/bpf_libassistant_policy_linux.cc
@@ -24,16 +24,23 @@ LibassistantProcessPolicy::LibassistantProcessPolicy() = default;
LibassistantProcessPolicy::~LibassistantProcessPolicy() = default;
ResultExpr LibassistantProcessPolicy::EvaluateSyscall(int sysno) const {
+ switch (sysno) {
+#if defined(__NR_getcpu)
+ // Needed by arm devices.
+ case __NR_getcpu:
+ return Allow();
+#endif
#if defined(__NR_sched_setscheduler)
- if (sysno == __NR_sched_setscheduler)
- return Allow();
+ case __NR_sched_setscheduler:
+ return Allow();
#endif
+ default:
+ auto* sandbox_linux = SandboxLinux::GetInstance();
+ if (sandbox_linux->ShouldBrokerHandleSyscall(sysno))
+ return sandbox_linux->HandleViaBroker();
- auto* sandbox_linux = SandboxLinux::GetInstance();
- if (sandbox_linux->ShouldBrokerHandleSyscall(sysno))
- return sandbox_linux->HandleViaBroker();
-
- return BPFBasePolicy::EvaluateSyscall(sysno);
+ return BPFBasePolicy::EvaluateSyscall(sysno);
+ }
}
} // namespace policy
diff --git a/chromium/sandbox/policy/linux/bpf_service_policy_linux.h b/chromium/sandbox/policy/linux/bpf_service_policy_linux.h
index 2c7a33595b0..7dad88cf61c 100644
--- a/chromium/sandbox/policy/linux/bpf_service_policy_linux.h
+++ b/chromium/sandbox/policy/linux/bpf_service_policy_linux.h
@@ -29,4 +29,4 @@ class ServiceProcessPolicy : public BPFBasePolicy {
} // namespace policy
} // namespace sandbox
-#endif // SERVICES_SERVICE_MANAGER_SANDBOX_LINUX_BPF_SERVICE_POLICY_LINUX_H_
+#endif // SANDBOX_POLICY_LINUX_BPF_SERVICE_POLICY_LINUX_H_
diff --git a/chromium/sandbox/policy/linux/sandbox_linux.cc b/chromium/sandbox/policy/linux/sandbox_linux.cc
index ba21e015b5a..e7f2fecb4f7 100644
--- a/chromium/sandbox/policy/linux/sandbox_linux.cc
+++ b/chromium/sandbox/policy/linux/sandbox_linux.cc
@@ -490,8 +490,12 @@ void SandboxLinux::StartBrokerProcess(
PreSandboxHook broker_side_hook,
const Options& options) {
// Leaked at shutdown, so use bare |new|.
+ // Use EACCES as the policy's default error number to remain consistent with
+ // other LSMs like AppArmor and Landlock. Some userspace code, such as
+ // glibc's |dlopen|, expect to see EACCES rather than EPERM. See
+ // crbug.com/1233028 for an example.
broker_process_ = new syscall_broker::BrokerProcess(
- BPFBasePolicy::GetFSDeniedErrno(), allowed_command_set, permissions,
+ EACCES, allowed_command_set, permissions,
syscall_broker::BrokerProcess::BrokerType::SIGNAL_BASED);
// The initialization callback will perform generic initialization and then
diff --git a/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc b/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
index 5d572af56b4..185eef17ced 100644
--- a/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
+++ b/chromium/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
@@ -61,9 +61,9 @@
#include "sandbox/policy/linux/bpf_tts_policy_linux.h"
#include "chromeos/assistant/buildflags.h"
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#include "sandbox/policy/linux/bpf_libassistant_policy_linux.h"
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
using sandbox::bpf_dsl::Allow;
@@ -199,10 +199,10 @@ std::unique_ptr<BPFBasePolicy> SandboxSeccompBPF::PolicyForSandboxType(
return std::make_unique<ImeProcessPolicy>();
case SandboxType::kTts:
return std::make_unique<TtsProcessPolicy>();
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
case SandboxType::kLibassistant:
return std::make_unique<LibassistantProcessPolicy>();
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
case SandboxType::kZygoteIntermediateSandbox:
case SandboxType::kNoSandbox:
@@ -236,7 +236,12 @@ void SandboxSeccompBPF::RunSandboxSanityChecks(
// open() must be restricted.
syscall_ret = open("/etc/passwd", O_RDONLY);
CHECK_EQ(-1, syscall_ret);
- CHECK_EQ(BPFBasePolicy::GetFSDeniedErrno(), errno);
+ // The broker used with the GPU process sandbox uses EACCES for
+ // invalid filesystem access. See crbug.com/1233028 for more info.
+ CHECK_EQ(sandbox_type == SandboxType::kGpu
+ ? EACCES
+ : BPFBasePolicy::GetFSDeniedErrno(),
+ errno);
// We should never allow the creation of netlink sockets.
syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0);
@@ -247,9 +252,9 @@ void SandboxSeccompBPF::RunSandboxSanityChecks(
#if BUILDFLAG(IS_CHROMEOS_ASH)
case SandboxType::kIme:
case SandboxType::kTts:
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
case SandboxType::kLibassistant:
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
case SandboxType::kAudio:
case SandboxType::kService:
diff --git a/chromium/sandbox/policy/mojom/BUILD.gn b/chromium/sandbox/policy/mojom/BUILD.gn
new file mode 100644
index 00000000000..0c35f3d5877
--- /dev/null
+++ b/chromium/sandbox/policy/mojom/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+ generate_java = true
+ sources = [ "sandbox.mojom" ]
+}
diff --git a/chromium/sandbox/policy/mojom/OWNERS b/chromium/sandbox/policy/mojom/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/sandbox/policy/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/sandbox/policy/mojom/sandbox.mojom b/chromium/sandbox/policy/mojom/sandbox.mojom
new file mode 100644
index 00000000000..403504483ca
--- /dev/null
+++ b/chromium/sandbox/policy/mojom/sandbox.mojom
@@ -0,0 +1,61 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module sandbox.mojom;
+
+// Sandbox type that can be specified as an attribute of mojo interfaces.
+// To specify the sandbox a service should be launched in, use the
+// [ServiceSandbox=type] attribute.
+// If your service does not need access to OS resources it should be
+// possible to host it in |kService|. These values are mapped to
+// //sandbox/policy/sandbox_type.h values.
+enum Sandbox {
+ // |kService| hosts 'computation only' services such as decoders that
+ // use limited operating system services. Prefer to use this sandbox
+ // if possible.
+ kService,
+
+ // Hosts generic utilities with limited access to system services.
+ // On some platforms, may be slightly less locked down than |kService|.
+ // For instance, it allows dynamic code and wider access to APIs on Windows.
+ kUtility,
+
+ // Hosts the content decryption module. Allows pre-loading of CDM libraries.
+ // - On Windows, when `CdmServiceBroker` is connected the CDM was not
+ // sandboxed to allow CDM preloading.
+ // - On Mac, the process is fully sandboxed when launched.
+ // - On Linux/ChromeOS, the CDM is preloaded in the zygote sandbox.
+ kCdm,
+
+ // Composits PDF and XPS documents.
+ kPrintCompositor,
+
+ // Equivalent to no sandbox on all non-Fuchsia platforms.
+ // Minimally privileged sandbox on Fuchsia.
+ // TODO(crbug.com/1236898) Fix this mapping.
+ kVideoCapture,
+
+ // Allows LPAC capabilities for the Windws Media Foundation CDM, including
+ // internet and private network access, COM, Identity & others. Allows access
+ // to files in the `mediaFoundationCdmFiles` Chromium lpac.
+ [EnableIf=is_win]
+ kMediaFoundationCdm,
+
+ // |kXrCompositing| hosts XR Device Service on Windows.
+ [EnableIf=is_win]
+ kXrCompositing,
+
+ // Hosts Input Method Editors.
+ [EnableIf=is_chromeos_ash]
+ kIme,
+
+ // Text-to-speech.
+ [EnableIf=is_chromeos_ash]
+ kTts,
+
+ // Hosts the Libassistant service on ChromeOS Ash, only used for
+ // Chrome branded builds.
+ [EnableIf=is_chromeos_ash]
+ kLibassistant,
+};
diff --git a/chromium/sandbox/policy/sandbox_type.cc b/chromium/sandbox/policy/sandbox_type.cc
index 21b207ca323..a0bdc152f9f 100644
--- a/chromium/sandbox/policy/sandbox_type.cc
+++ b/chromium/sandbox/policy/sandbox_type.cc
@@ -59,10 +59,10 @@ bool IsUnsandboxedSandboxType(SandboxType sandbox_type) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
case SandboxType::kIme:
case SandboxType::kTts:
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
case SandboxType::kLibassistant:
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
-#endif
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+#endif // // BUILDFLAG(IS_CHROMEOS_ASH)
#if !defined(OS_MAC)
case SandboxType::kService:
#endif
@@ -130,9 +130,9 @@ void SetCommandLineFlagsForSandboxType(base::CommandLine* command_line,
#if BUILDFLAG(IS_CHROMEOS_ASH)
case SandboxType::kIme:
case SandboxType::kTts:
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
case SandboxType::kLibassistant:
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if defined(OS_MAC)
case SandboxType::kMirroring:
@@ -271,10 +271,10 @@ std::string StringFromUtilitySandboxType(SandboxType sandbox_type) {
return switches::kImeSandbox;
case SandboxType::kTts:
return switches::kTtsSandbox;
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
case SandboxType::kLibassistant:
return switches::kLibassistantSandbox;
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// The following are not utility processes so should not occur.
case SandboxType::kRenderer:
@@ -294,6 +294,15 @@ std::string StringFromUtilitySandboxType(SandboxType sandbox_type) {
}
SandboxType UtilitySandboxTypeFromString(const std::string& sandbox_string) {
+ // This function should cover all sandbox types used for utilities, the
+ // CHECK at the end should catch any attempts to forget to add a new type.
+
+ // Most utilities are kUtility or kService so put those first.
+ if (sandbox_string == switches::kUtilitySandbox)
+ return SandboxType::kUtility;
+ if (sandbox_string == switches::kServiceSandbox)
+ return SandboxType::kService;
+
if (sandbox_string == switches::kNoneSandbox)
return SandboxType::kNoSandbox;
if (sandbox_string == switches::kNoneSandboxAndElevatedPrivileges) {
@@ -342,11 +351,15 @@ SandboxType UtilitySandboxTypeFromString(const std::string& sandbox_string) {
return SandboxType::kIme;
if (sandbox_string == switches::kTtsSandbox)
return SandboxType::kTts;
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
if (sandbox_string == switches::kLibassistantSandbox)
return SandboxType::kLibassistant;
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+ CHECK(false)
+ << "Command line does not provide a valid sandbox configuration: "
+ << sandbox_string;
+ NOTREACHED();
return SandboxType::kUtility;
}
diff --git a/chromium/sandbox/policy/sandbox_type.h b/chromium/sandbox/policy/sandbox_type.h
index 88903f72a3b..8b841e48e62 100644
--- a/chromium/sandbox/policy/sandbox_type.h
+++ b/chromium/sandbox/policy/sandbox_type.h
@@ -12,6 +12,7 @@
#include "build/chromeos_buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "sandbox/policy/export.h"
+#include "sandbox/policy/mojom/sandbox.mojom.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/assistant/buildflags.h"
@@ -98,9 +99,9 @@ enum class SandboxType {
// Text-to-speech.
kTts,
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
kLibassistant,
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -119,6 +120,42 @@ enum class SandboxType {
kMaxValue = kVideoCapture
};
+inline constexpr sandbox::policy::SandboxType MapToSandboxType(
+ sandbox::mojom::Sandbox mojo_sandbox) {
+ switch (mojo_sandbox) {
+ case sandbox::mojom::Sandbox::kCdm:
+ return sandbox::policy::SandboxType::kCdm;
+ case sandbox::mojom::Sandbox::kPrintCompositor:
+ return sandbox::policy::SandboxType::kPrintCompositor;
+ case sandbox::mojom::Sandbox::kService:
+ return sandbox::policy::SandboxType::kService;
+ case sandbox::mojom::Sandbox::kUtility:
+ return sandbox::policy::SandboxType::kUtility;
+ case sandbox::mojom::Sandbox::kVideoCapture:
+ return sandbox::policy::SandboxType::kVideoCapture;
+#if defined(OS_WIN)
+ case sandbox::mojom::Sandbox::kMediaFoundationCdm:
+ return sandbox::policy::SandboxType::kMediaFoundationCdm;
+ case sandbox::mojom::Sandbox::kXrCompositing:
+ return sandbox::policy::SandboxType::kXrCompositing;
+#endif // OS_WIN
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ case sandbox::mojom::Sandbox::kIme:
+ return sandbox::policy::SandboxType::kIme;
+ case sandbox::mojom::Sandbox::kTts:
+ return sandbox::policy::SandboxType::kTts;
+ case sandbox::mojom::Sandbox::kLibassistant:
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+ return sandbox::policy::SandboxType::kLibassistant;
+#else
+ CHECK(false) << "Libassistant sandbox not supported";
+ NOTREACHED();
+ return sandbox::policy::SandboxType::kService;
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+ }
+}
+
SANDBOX_POLICY_EXPORT bool IsUnsandboxedSandboxType(SandboxType sandbox_type);
SANDBOX_POLICY_EXPORT void SetCommandLineFlagsForSandboxType(
diff --git a/chromium/sandbox/policy/sandbox_type_unittest.cc b/chromium/sandbox/policy/sandbox_type_unittest.cc
index e909a684c79..85b3131a19b 100644
--- a/chromium/sandbox/policy/sandbox_type_unittest.cc
+++ b/chromium/sandbox/policy/sandbox_type_unittest.cc
@@ -54,7 +54,6 @@ TEST(SandboxTypeTest, Utility) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitchASCII(switches::kProcessType,
switches::kUtilityProcess);
- EXPECT_EQ(SandboxType::kUtility, SandboxTypeFromCommandLine(command_line));
base::CommandLine command_line2(command_line);
SetCommandLineFlagsForSandboxType(&command_line2, SandboxType::kNetwork);
@@ -73,8 +72,8 @@ TEST(SandboxTypeTest, Utility) {
EXPECT_EQ(SandboxType::kPpapi, SandboxTypeFromCommandLine(command_line5));
base::CommandLine command_line6(command_line);
- command_line6.AppendSwitchASCII(switches::kServiceSandboxType, "bogus");
- EXPECT_EQ(SandboxType::kUtility, SandboxTypeFromCommandLine(command_line6));
+ SetCommandLineFlagsForSandboxType(&command_line6, SandboxType::kService);
+ EXPECT_EQ(SandboxType::kService, SandboxTypeFromCommandLine(command_line6));
base::CommandLine command_line7(command_line);
SetCommandLineFlagsForSandboxType(&command_line7,
@@ -130,6 +129,23 @@ TEST(SandboxTypeTest, Utility) {
EXPECT_EQ(SandboxType::kNoSandbox, SandboxTypeFromCommandLine(command_line));
}
+TEST(SandboxTypeTest, UtilityDeath) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitchASCII(switches::kProcessType,
+ switches::kUtilityProcess);
+
+ EXPECT_DEATH_IF_SUPPORTED(SandboxTypeFromCommandLine(command_line), "");
+
+ // kGPU not valid for utility processes.
+ base::CommandLine command_line1(command_line);
+ command_line1.AppendSwitchASCII(switches::kServiceSandboxType, "gpu");
+ EXPECT_DEATH_IF_SUPPORTED(SandboxTypeFromCommandLine(command_line1), "");
+
+ base::CommandLine command_line2(command_line);
+ command_line2.AppendSwitchASCII(switches::kServiceSandboxType, "bogus");
+ EXPECT_DEATH_IF_SUPPORTED(SandboxTypeFromCommandLine(command_line2), "");
+}
+
TEST(SandboxTypeTest, GPU) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
diff --git a/chromium/sandbox/policy/switches.cc b/chromium/sandbox/policy/switches.cc
index c0438f62d61..9ab64bce09c 100644
--- a/chromium/sandbox/policy/switches.cc
+++ b/chromium/sandbox/policy/switches.cc
@@ -53,9 +53,9 @@ const char kMirroringSandbox[] = "mirroring";
#if BUILDFLAG(IS_CHROMEOS_ASH)
const char kImeSandbox[] = "ime";
const char kTtsSandbox[] = "tts";
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
const char kLibassistantSandbox[] = "libassistant";
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Flags owned by the service manager sandbox.
diff --git a/chromium/sandbox/policy/switches.h b/chromium/sandbox/policy/switches.h
index a0315cd1ace..1f7dc94681b 100644
--- a/chromium/sandbox/policy/switches.h
+++ b/chromium/sandbox/policy/switches.h
@@ -54,9 +54,9 @@ SANDBOX_POLICY_EXPORT extern const char kMirroringSandbox[];
#if BUILDFLAG(IS_CHROMEOS_ASH)
SANDBOX_POLICY_EXPORT extern const char kImeSandbox[];
SANDBOX_POLICY_EXPORT extern const char kTtsSandbox[];
-#if BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
SANDBOX_POLICY_EXPORT extern const char kLibassistantSandbox[];
-#endif // BUILDFLAG(ENABLE_LIBASSISTANT_SANDBOX)
+#endif // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Flags owned by the service manager sandbox.
diff --git a/chromium/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc b/chromium/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc
index b2988859fbb..7f257c7c90a 100644
--- a/chromium/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc
+++ b/chromium/sandbox/policy/win/mf_cdm_sandbox_type_unittest.cc
@@ -11,12 +11,10 @@
namespace media {
TEST(SandboxTypeTest, Utility) {
- // Setup to have '--type=utility' first.
+ // Setup to have '--type=utility' first (but no valid sandbox).
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitchASCII(sandbox::policy::switches::kProcessType,
sandbox::policy::switches::kUtilityProcess);
- EXPECT_EQ(sandbox::policy::SandboxType::kUtility,
- sandbox::policy::SandboxTypeFromCommandLine(command_line));
base::CommandLine command_line2(command_line);
SetCommandLineFlagsForSandboxType(
diff --git a/chromium/sandbox/policy/win/sandbox_diagnostics.h b/chromium/sandbox/policy/win/sandbox_diagnostics.h
index 68b01a91699..5e74030f4b5 100644
--- a/chromium/sandbox/policy/win/sandbox_diagnostics.h
+++ b/chromium/sandbox/policy/win/sandbox_diagnostics.h
@@ -23,9 +23,10 @@ namespace sandbox {
namespace policy {
// Mediates response from BrokerServices->GetPolicyDiagnostics.
-class ServiceManagerDiagnosticsReceiver : public PolicyDiagnosticsReceiver {
+class ServiceManagerDiagnosticsReceiver final
+ : public PolicyDiagnosticsReceiver {
public:
- ~ServiceManagerDiagnosticsReceiver() final;
+ ~ServiceManagerDiagnosticsReceiver() override;
ServiceManagerDiagnosticsReceiver(
scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
base::OnceCallback<void(base::Value)> response);
diff --git a/chromium/sandbox/policy/win/sandbox_win.cc b/chromium/sandbox/policy/win/sandbox_win.cc
index 3b6543c4d49..f9981846a1d 100644
--- a/chromium/sandbox/policy/win/sandbox_win.cc
+++ b/chromium/sandbox/policy/win/sandbox_win.cc
@@ -11,6 +11,7 @@
#include <vector>
#include "base/command_line.h"
+#include "base/cxx17_backports.h"
#include "base/debug/activity_tracker.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
@@ -24,7 +25,6 @@
#include "base/no_destructor.h"
#include "base/path_service.h"
#include "base/process/launch.h"
-#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -155,7 +155,7 @@ const base::Feature kEnableCsrssLockdownFeature{
// chrome.exe and chrome.dll.
class PolicyTraceHelper : public base::trace_event::ConvertableToTraceFormat {
public:
- PolicyTraceHelper(TargetPolicy* policy) {
+ explicit PolicyTraceHelper(TargetPolicy* policy) {
// |info| must live until JsonString() output is copied.
std::unique_ptr<PolicyInfo> info = policy->GetPolicyInfo();
json_string_ = std::string(info->JsonString());
@@ -660,7 +660,7 @@ ResultCode SetupAppContainerProfile(AppContainer* container,
return SBOX_ERROR_UNSUPPORTED;
DCHECK(sandbox_type != SandboxType::kNetwork ||
- base::FeatureList::IsEnabled(features::kNetworkServiceSandboxLPAC));
+ sandbox::policy::features::IsNetworkServiceSandboxLPACEnabled());
if (sandbox_type == SandboxType::kGpu &&
!container->AddImpersonationCapability(L"chromeInstallFiles")) {
@@ -704,7 +704,8 @@ ResultCode SetupAppContainerProfile(AppContainer* container,
!container->AddCapability(L"lpacAppExperience") ||
!container->AddCapability(L"lpacInstrumentation") ||
!container->AddCapability(L"lpacCryptoServices") ||
- !container->AddCapability(L"lpacEnterprisePolicyChangeNotifications")) {
+ !container->AddCapability(L"lpacEnterprisePolicyChangeNotifications") ||
+ !container->AddCapability(L"mediaFoundationCdmFiles")) {
DLOG(ERROR)
<< "AppContainer::AddCapability() - "
<< "SandboxType::kMediaFoundationCdm lpac capabilities failed";
@@ -923,7 +924,7 @@ bool SandboxWin::IsAppContainerEnabledForSandbox(
return base::FeatureList::IsEnabled(features::kGpuAppContainer);
if (sandbox_type == SandboxType::kNetwork)
- return base::FeatureList::IsEnabled(features::kNetworkServiceSandboxLPAC);
+ return sandbox::policy::features::IsNetworkServiceSandboxLPACEnabled();
return false;
}
diff --git a/chromium/sandbox/win/BUILD.gn b/chromium/sandbox/win/BUILD.gn
index 2dd5ef90d4b..8fb6c13c8de 100644
--- a/chromium/sandbox/win/BUILD.gn
+++ b/chromium/sandbox/win/BUILD.gn
@@ -94,25 +94,21 @@ static_library("sandbox") {
"src/restricted_token_utils.cc",
"src/restricted_token_utils.h",
"src/sandbox.cc",
- "src/sandbox.h",
"src/sandbox_factory.h",
"src/sandbox_globals.cc",
"src/sandbox_nt_types.h",
"src/sandbox_nt_util.cc",
"src/sandbox_nt_util.h",
- "src/sandbox_policy.h",
"src/sandbox_policy_base.cc",
"src/sandbox_policy_base.h",
"src/sandbox_policy_diagnostic.cc",
"src/sandbox_policy_diagnostic.h",
"src/sandbox_rand.cc",
"src/sandbox_rand.h",
- "src/sandbox_types.h",
"src/sandbox_utils.cc",
"src/sandbox_utils.h",
"src/security_capabilities.cc",
"src/security_capabilities.h",
- "src/security_level.h",
"src/service_resolver.cc",
"src/service_resolver.h",
"src/sharedmem_ipc_client.cc",
@@ -127,6 +123,8 @@ static_library("sandbox") {
"src/signed_interception.h",
"src/signed_policy.cc",
"src/signed_policy.h",
+ "src/socket_dispatcher.cc",
+ "src/socket_dispatcher.h",
"src/startup_information_helper.cc",
"src/startup_information_helper.h",
"src/sync_dispatcher.cc",
@@ -182,18 +180,16 @@ static_library("sandbox") {
configs += [ "//build/config:precompiled_headers" ]
- public_deps = [ "//base" ]
+ public_deps = [
+ ":common",
+ "//base",
+ ]
deps = [
+ ":maybe_set_appcontainer_acls",
"//base:base_static",
"//sandbox:common",
]
-
- # NACL on 32-bit builds this target twice, once for 64-bit and once for 32-bit
- # so avoid this dep from running twice with the same output in that case.
- if (current_cpu == target_cpu) {
- deps += [ ":set_appcontainer_acls" ]
- }
}
test("sbox_integration_tests") {
@@ -221,7 +217,6 @@ test("sbox_integration_tests") {
"src/sync_policy_test.h",
"src/unload_dll_test.cc",
"tests/common/controller.cc",
- "tests/common/controller.h",
"tests/common/test_utils.cc",
"tests/common/test_utils.h",
"tests/integration_tests/cfi_unittest.cc",
@@ -244,7 +239,10 @@ test("sbox_integration_tests") {
":sbox_integration_test_win_proc",
]
- libs = [ "ktmw32.lib" ]
+ libs = [
+ "ktmw32.lib",
+ "iphlpapi.lib",
+ ]
}
shared_library("sbox_integration_test_hijack_dll") {
@@ -253,56 +251,64 @@ shared_library("sbox_integration_test_hijack_dll") {
"tests/integration_tests/hijack_dll.def",
]
- deps = [ ":set_appcontainer_acls" ]
+ deps = [ ":maybe_set_appcontainer_acls" ]
+}
+
+group("maybe_set_appcontainer_acls") {
+ # NACL on 32-bit builds this target twice, once for 64-bit and once for 32-bit
+ # so avoid this dep from running twice with the same output in that case.
+ # Additionally, exclude setting ACLs when build is not happening on Windows.
+ if (current_cpu == target_cpu && host_os == "win") {
+ deps = [ ":set_appcontainer_acls" ]
+ }
}
-action("set_appcontainer_acls") {
- script = "//build/win/set_appcontainer_acls.py"
- stamp_file = "$target_out_dir/acls.stamp"
- inputs = [ script ]
- outputs = [ stamp_file ]
+if (current_cpu == target_cpu && host_os == "win") {
+ action("set_appcontainer_acls") {
+ script = "//build/win/set_appcontainer_acls.py"
+ stamp_file = "$target_out_dir/acls.stamp"
+ inputs = [ script ]
+ outputs = [ stamp_file ]
- args = [
- "--stamp=" + rebase_path(stamp_file, root_out_dir),
- "--dir=" + rebase_path(root_out_dir, root_out_dir),
- ]
+ args = [
+ "--stamp=" + rebase_path(stamp_file, root_out_dir),
+ "--dir=" + rebase_path(root_out_dir, root_out_dir),
+ ]
+ }
}
-loadable_module("sbox_integration_test_hijack_shim_dll") {
+shared_library("sbox_integration_test_hijack_shim_dll") {
sources = [
"tests/integration_tests/hijack_shim_dll.cc",
"tests/integration_tests/hijack_shim_dll.def",
- "tests/integration_tests/hijack_shim_dll.h",
]
# Implicitly linking hijack_dll as loader import resolution required.
deps = [
+ ":common",
":sbox_integration_test_hijack_dll",
"//base",
]
}
-loadable_module("sbox_integration_test_hooking_dll") {
- sources = [
- "tests/integration_tests/hooking_dll.cc",
- "tests/integration_tests/hooking_dll.h",
- ]
+shared_library("sbox_integration_test_hooking_dll") {
+ sources = [ "tests/integration_tests/hooking_dll.cc" ]
+
+ deps = [ ":common_test" ]
}
executable("sbox_integration_test_win_proc") {
- sources = [
- "tests/integration_tests/hooking_win_proc.cc",
- "tests/integration_tests/hooking_win_proc.h",
- ]
+ sources = [ "tests/integration_tests/hooking_win_proc.cc" ]
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
+
+ deps = [ ":common_test" ]
}
test("sbox_validation_tests") {
sources = [
"tests/common/controller.cc",
- "tests/common/controller.h",
"tests/validation_tests/commands.cc",
"tests/validation_tests/commands.h",
"tests/validation_tests/suite.cc",
@@ -382,18 +388,39 @@ shared_library("pocdll") {
]
defines = [ "POCDLL_EXPORTS" ]
+
+ deps = [ "//base" ]
}
# This fuzzer will only work on Windows, add fuzz targets which could run on
# Linux to //sandbox/ directly.
fuzzer_test("sandbox_policy_rule_fuzzer") {
- sources = [
- "fuzzer/fuzzer_types.h",
- "fuzzer/sandbox_policy_rule_fuzzer.cc",
- ]
+ sources = [ "fuzzer/sandbox_policy_rule_fuzzer.cc" ]
dict = "fuzzer/sandbox_policy_rule.dict"
deps = [
"//base",
"//sandbox",
]
}
+
+source_set("common") {
+ sources = [
+ "fuzzer/fuzzer_types.h",
+ "src/sandbox.h",
+ "src/sandbox_policy.h",
+ "src/sandbox_types.h",
+ "src/security_level.h",
+ "tests/common/controller.h",
+ "tests/integration_tests/hijack_shim_dll.h",
+ ]
+
+ deps = [ "//base" ]
+ public_deps = [ ":common_test" ]
+}
+
+source_set("common_test") {
+ sources = [
+ "tests/integration_tests/hooking_dll.h",
+ "tests/integration_tests/hooking_win_proc.h",
+ ]
+}
diff --git a/chromium/sandbox/win/sandbox_poc/main_ui_window.cc b/chromium/sandbox/win/sandbox_poc/main_ui_window.cc
index b5ebe760057..2b168ed249d 100644
--- a/chromium/sandbox/win/sandbox_poc/main_ui_window.cc
+++ b/chromium/sandbox/win/sandbox_poc/main_ui_window.cc
@@ -645,8 +645,7 @@ void MainUIWindow::InsertLineInListView(wchar_t* debug_message) {
struct tm time = {0};
localtime_s(&time, &time_temp);
- size_t return_code;
- return_code = wcsftime(message_time, kSizeTime, L"[%H:%M:%S] ", &time);
+ wcsftime(message_time, kSizeTime, L"[%H:%M:%S] ", &time);
wcscat_s(message_time, size_message_with_time, debug_message);
diff --git a/chromium/sandbox/win/src/app_container_base.cc b/chromium/sandbox/win/src/app_container_base.cc
index ca99779109b..9cb27f06385 100644
--- a/chromium/sandbox/win/src/app_container_base.cc
+++ b/chromium/sandbox/win/src/app_container_base.cc
@@ -67,7 +67,7 @@ bool GetGenericMappingForType(SE_OBJECT_TYPE object_type,
class ScopedImpersonation {
public:
- ScopedImpersonation(const base::win::ScopedHandle& token) {
+ explicit ScopedImpersonation(const base::win::ScopedHandle& token) {
BOOL result = ::ImpersonateLoggedOnUser(token.Get());
DCHECK(result);
}
diff --git a/chromium/sandbox/win/src/app_container_test.cc b/chromium/sandbox/win/src/app_container_test.cc
index 3e231971cd3..29d83ed42a9 100644
--- a/chromium/sandbox/win/src/app_container_test.cc
+++ b/chromium/sandbox/win/src/app_container_test.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include <windows.h>
+#include <winsock2.h>
+
+#include <iphlpapi.h>
#include <sddl.h>
@@ -14,15 +17,20 @@
#include "base/files/file_path.h"
#include "base/hash/sha1.h"
#include "base/logging.h"
+#include "base/process/process_info.h"
#include "base/rand_util.h"
#include "base/scoped_native_library.h"
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/thread_pool.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/app_container_base.h"
+#include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/sync_policy_test.h"
#include "sandbox/win/src/win_utils.h"
#include "sandbox/win/tests/common/controller.h"
@@ -37,6 +45,17 @@ const wchar_t kAppContainerSid[] =
L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
L"924012148-2839372144";
+// Some tests depend on a timeout happening (e.g. to detect if firewall blocks a
+// TCP/UDP connection from App Container). However, if process startup time is
+// too slow (which can happen on slower bots with a high degree of test
+// concurrency) then tiny_timeout is not long enough, so a slightly longer
+// timeout is used here to avoid having to retry flaky tests.
+DWORD test_timeout() {
+ const static DWORD kMillisTimeout =
+ TestTimeouts::tiny_timeout().InMilliseconds() * 2;
+ return kMillisTimeout;
+}
+
std::wstring GenerateRandomPackageName() {
return base::StringPrintf(L"%016lX%016lX", base::RandUint64(),
base::RandUint64());
@@ -200,6 +219,69 @@ ResultCode AddNetworkAppContainerPolicy(TargetPolicy* policy) {
return SBOX_ALL_OK;
}
+void InitWinsock() {
+ WORD winsock_ver = MAKEWORD(2, 2);
+ WSAData wsa_data;
+ WSAStartup(winsock_ver, &wsa_data);
+}
+
+class WSAEventHandleTraits {
+ public:
+ typedef HANDLE Handle;
+
+ WSAEventHandleTraits() = delete;
+ WSAEventHandleTraits(const WSAEventHandleTraits&) = delete;
+ WSAEventHandleTraits& operator=(const WSAEventHandleTraits&) = delete;
+
+ static bool CloseHandle(HANDLE handle) {
+ return ::WSACloseEvent(handle) == TRUE;
+ }
+ static bool IsHandleValid(HANDLE handle) {
+ return handle != INVALID_HANDLE_VALUE;
+ }
+ static HANDLE NullHandle() { return INVALID_HANDLE_VALUE; }
+};
+
+typedef base::win::GenericScopedHandle<WSAEventHandleTraits,
+ base::win::DummyVerifierTraits>
+ ScopedWSAEventHandle;
+
+class SocketHandleTraits {
+ public:
+ typedef SOCKET Handle;
+
+ SocketHandleTraits() = delete;
+ SocketHandleTraits(const SocketHandleTraits&) = delete;
+ SocketHandleTraits& operator=(const SocketHandleTraits&) = delete;
+
+ static bool CloseHandle(SOCKET handle) { return ::closesocket(handle) == 0; }
+ static bool IsHandleValid(SOCKET handle) { return handle != INVALID_SOCKET; }
+ static SOCKET NullHandle() { return INVALID_SOCKET; }
+};
+
+class DummySocketVerifierTraits {
+ public:
+ using Handle = SOCKET;
+
+ DummySocketVerifierTraits() = delete;
+ DummySocketVerifierTraits(const DummySocketVerifierTraits&) = delete;
+ DummySocketVerifierTraits& operator=(const DummySocketVerifierTraits&) =
+ delete;
+
+ static void StartTracking(SOCKET handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {}
+ static void StopTracking(SOCKET handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {}
+};
+
+typedef base::win::GenericScopedHandle<SocketHandleTraits,
+ DummySocketVerifierTraits>
+ ScopedSocketHandle;
+
class AppContainerTest : public ::testing::Test {
public:
void SetUp() override {
@@ -247,6 +329,124 @@ class AppContainerTest : public ::testing::Test {
base::win::ScopedProcessInformation scoped_process_info_;
};
+// A Very Simple UDP test server.
+// Binds to all interfaces on a random port, and then waits to receive some
+// data, then sends it back to the peer.
+class UDPEchoServer {
+ public:
+ UDPEchoServer() = default;
+ ~UDPEchoServer();
+
+ // Start server.
+ bool Start();
+ // Get the listening port. Must be called after Start().
+ int GetPort();
+
+ private:
+ void RecvTask();
+ ScopedSocketHandle socket_;
+ int port_;
+ base::test::TaskEnvironment environment_;
+};
+
+UDPEchoServer::~UDPEchoServer() {
+ // Make sure to drain threads before destructing.
+ environment_.RunUntilIdle();
+}
+
+bool UDPEchoServer::Start() {
+ SOCKET s = ::WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, nullptr, 0,
+ WSA_FLAG_OVERLAPPED);
+ if (s == INVALID_SOCKET)
+ return false;
+ socket_ = ScopedSocketHandle(s);
+
+ struct sockaddr_in server;
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ // Pick a random port.
+ server.sin_port = 0;
+
+ int ret =
+ bind(socket_.Get(), reinterpret_cast<sockaddr*>(&server), sizeof(server));
+ if (ret == SOCKET_ERROR)
+ return false;
+
+ struct sockaddr_in bound_server;
+ int bound_server_len = sizeof(bound_server);
+ ret = getsockname(socket_.Get(), reinterpret_cast<sockaddr*>(&bound_server),
+ &bound_server_len);
+ if (ret == SOCKET_ERROR)
+ return false;
+ port_ = ntohs(bound_server.sin_port);
+ return base::ThreadPool::PostTask(
+ FROM_HERE,
+ base::BindOnce(&UDPEchoServer::RecvTask, base::Unretained(this)));
+}
+
+void UDPEchoServer::RecvTask() {
+ char buf[1024];
+ WSABUF wsa_buf;
+ wsa_buf.buf = buf;
+ wsa_buf.len = sizeof(buf);
+ struct sockaddr_in other;
+ int other_len = sizeof(other);
+
+ HANDLE recv_event_handle = WSACreateEvent();
+ ASSERT_NE(WSA_INVALID_EVENT, recv_event_handle);
+ ScopedWSAEventHandle recv_event(recv_event_handle);
+
+ OVERLAPPED read_overlapped = {};
+ read_overlapped.hEvent = recv_event.Get();
+ DWORD flags = 0;
+ int ret = WSARecvFrom(socket_.Get(), &wsa_buf, 1, nullptr, &flags,
+ reinterpret_cast<sockaddr*>(&other), &other_len,
+ &read_overlapped, nullptr);
+ // Return value of 0 means operation completed immediately which should never
+ // happen. SOCKET_ERROR returned means operation is pending.
+ ASSERT_EQ(SOCKET_ERROR, ret);
+ // Operation should be pending.
+ ASSERT_EQ(WSA_IO_PENDING, ::WSAGetLastError());
+
+ // Wait to receive data from the child process. Only wait 1 second.
+ DWORD wait = WaitForSingleObject(recv_event.Get(), test_timeout());
+
+ if (wait != WAIT_OBJECT_0)
+ return; // No connections. Expected for certain types of tests.
+
+ DWORD num_bytes_recv = 0;
+ flags = 0;
+ BOOL overlapped_result = WSAGetOverlappedResult(
+ socket_.Get(), &read_overlapped, &num_bytes_recv, FALSE, &flags);
+ ASSERT_TRUE(overlapped_result);
+
+ // Now reply.
+ HANDLE send_event_handle = WSACreateEvent();
+ ASSERT_NE(WSA_INVALID_EVENT, send_event_handle);
+ ScopedWSAEventHandle send_event(send_event_handle);
+
+ OVERLAPPED send_overlapped = {};
+ read_overlapped.hEvent = send_event.Get();
+
+ ret = WSASendTo(socket_.Get(), &wsa_buf, 1, nullptr, 0,
+ reinterpret_cast<sockaddr*>(&other), other_len,
+ &send_overlapped, nullptr);
+ // Return value of 0 means operation completed immediately, which means data
+ // was successfully sent to the peer.
+ if (ret == 0)
+ return;
+ // If not, the operation should be pending.
+ ASSERT_EQ(WSA_IO_PENDING, ::WSAGetLastError());
+ // Wait for send. Only wait 1 second.
+ wait = WaitForSingleObject(send_event.Get(), test_timeout());
+ // Send should always succeed in a timely manner.
+ EXPECT_EQ(wait, WAIT_OBJECT_0);
+}
+
+int UDPEchoServer::GetPort() {
+ return port_;
+}
+
} // namespace
TEST_F(AppContainerTest, DenyOpenEventForLowBox) {
@@ -411,6 +611,192 @@ SBOX_TESTS_COMMAND int LoadDLL(int argc, wchar_t** argv) {
return SBOX_TEST_FAILED;
}
+SBOX_TESTS_COMMAND int CheckIsAppContainer(int argc, wchar_t** argv) {
+ if (base::IsCurrentProcessInAppContainer())
+ return SBOX_TEST_SUCCEEDED;
+ return SBOX_TEST_FAILED;
+}
+
+// Attempts to create a TCP socket, connect to specified address on a specified
+// port.
+//
+// First parameter should contain the host. Second parameter should contain the
+// port to connect to. Third parameter indicates whether the socket should be
+// brokered (1) or created in-process (0).
+//
+// SBOX_TEST_FAILED_TO_RUN_TEST - Test failed to run e.g. invalid parameters.
+//
+// SBOX_TEST_FIRST_ERROR - Could not create socket from call to WSASocket or
+// socket broker operation.
+//
+// SBOX_TEST_SECOND_ERROR - Could not call successfully perform a non-blocking
+// TCP connect().
+//
+// SBOX_TEST_TIMED_OUT - The connect timed out. This might be the correct result
+// for certain types of tests e.g. when App Container is blocking either a TCP
+// connect.
+SBOX_TESTS_COMMAND int Socket_CreateTCP(int argc, wchar_t** argv) {
+ InitWinsock();
+ SOCKET socket_handle = INVALID_SOCKET;
+
+ if (argc < 3)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+ if (::_wtoi(argv[2]) == 1) {
+ TargetServices* target_services = SandboxFactory::GetTargetServices();
+ if (!target_services)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ socket_handle = target_services->CreateBrokeredSocket(AF_INET, SOCK_STREAM,
+ IPPROTO_TCP);
+ } else {
+ socket_handle = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0,
+ WSA_FLAG_OVERLAPPED);
+ }
+
+ if (socket_handle == INVALID_SOCKET)
+ return SBOX_TEST_FIRST_ERROR;
+
+ ScopedSocketHandle socket(socket_handle);
+
+ sockaddr_in local_service = {};
+ local_service.sin_family = AF_INET;
+ std::string hostname = base::WideToUTF8(argv[0]);
+ local_service.sin_addr.s_addr = inet_addr(hostname.c_str());
+ local_service.sin_port = htons(::_wtoi(argv[1]));
+
+ HANDLE connect_event_handle = WSACreateEvent();
+ if (connect_event_handle == WSA_INVALID_EVENT)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ ScopedWSAEventHandle connect_event(connect_event_handle);
+ // For TCP sockets, wait on the connect.
+ int event_select =
+ WSAEventSelect(socket.Get(), connect_event.Get(), FD_CONNECT);
+
+ if (event_select)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ int ret = ::connect(socket.Get(), reinterpret_cast<sockaddr*>(&local_service),
+ sizeof(local_service));
+ if (ret != SOCKET_ERROR || WSAGetLastError() != WSAEWOULDBLOCK) {
+ return SBOX_TEST_SECOND_ERROR;
+ }
+ // Non-blocking socket, always returns SOCKET_ERROR and sets WSAlastError to
+ // WSAEWOULDBLOCK.
+ // Wait for the connect to succeed.
+ DWORD wait = WaitForSingleObject(connect_event.Get(), test_timeout());
+
+ if (wait != WAIT_OBJECT_0)
+ return SBOX_TEST_TIMED_OUT;
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Attempts to create a UDP socket, connect to specified address on a specified
+// port, and transmit/receive data.
+//
+// First parameter should contain the host. Second parameter should contain the
+// port to connect to. Third parameter indicates whether the socket should be
+// brokered (1) or created in-process (0).
+//
+// Returns:
+//
+// SBOX_TEST_FAILED_TO_RUN_TEST - Test failed to run e.g. invalid parameters.
+//
+// SBOX_TEST_FIRST_ERROR - Could not create socket from call to WSASocket or
+// socket broker operation.
+//
+// SBOX_TEST_THIRD_ERROR - Could not successfully perform a non-blocking UDP
+// sendto().
+//
+// SBOX_TEST_FOURTH_ERROR - Could not successfully perform a non-blocking UDP
+// recv().
+//
+// SBOX_TEST_TIMED_OUT - One of the above operations (connect, sendto, recv)
+// timed out. This might be the correct result for certain types of tests e.g.
+// when App Container is blocking either a TCP connect or UDP recv.
+SBOX_TESTS_COMMAND int Socket_CreateUDP(int argc, wchar_t** argv) {
+ InitWinsock();
+ SOCKET socket_handle = INVALID_SOCKET;
+
+ if (argc < 3)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+ if (::_wtoi(argv[2]) == 1) {
+ TargetServices* target_services = SandboxFactory::GetTargetServices();
+ if (!target_services)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ socket_handle =
+ target_services->CreateBrokeredSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ } else {
+ socket_handle = ::WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, nullptr, 0,
+ WSA_FLAG_OVERLAPPED);
+ }
+
+ if (socket_handle == INVALID_SOCKET)
+ return SBOX_TEST_FIRST_ERROR;
+
+ ScopedSocketHandle socket(socket_handle);
+ sockaddr_in local_service = {};
+ local_service.sin_family = AF_INET;
+ std::string hostname = base::WideToUTF8(argv[0]);
+ local_service.sin_addr.s_addr = inet_addr(hostname.c_str());
+ local_service.sin_port = htons(::_wtoi(argv[1]));
+
+ char data[] = "hello";
+
+ WSABUF write_buffer = {};
+ write_buffer.buf = data;
+ write_buffer.len = sizeof(data);
+ HANDLE send_event_handle = WSACreateEvent();
+ if (send_event_handle == WSA_INVALID_EVENT)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ ScopedWSAEventHandle send_event(send_event_handle);
+ OVERLAPPED write_overlapped = {};
+ write_overlapped.hEvent = send_event.Get();
+ int ret = ::WSASendTo(socket.Get(), &write_buffer, 1, nullptr, 0,
+ reinterpret_cast<sockaddr*>(&local_service),
+ sizeof(local_service), &write_overlapped, nullptr);
+ if (ret == 0) {
+ // Operation completed immediately!
+ } else {
+ // Winsock should return WSA_IO_PENDING and we wait on the event.
+ if (WSAGetLastError() != WSA_IO_PENDING)
+ return SBOX_TEST_THIRD_ERROR;
+ DWORD wait = WaitForSingleObject(send_event.Get(), test_timeout());
+
+ if (wait != WAIT_OBJECT_0)
+ return SBOX_TEST_TIMED_OUT;
+ }
+
+ // Now try to read the response.
+ WSABUF read_buffer = {};
+ char recv_buf[10] = {};
+ read_buffer.buf = recv_buf;
+ read_buffer.len = sizeof(recv_buf);
+ HANDLE read_event_handle = WSACreateEvent();
+ if (read_event_handle == WSA_INVALID_EVENT)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ ScopedWSAEventHandle read_event(read_event_handle);
+ OVERLAPPED read_overlapped = {};
+ read_overlapped.hEvent = read_event.Get();
+ DWORD flags = MSG_PARTIAL;
+ ret = ::WSARecv(socket.Get(), &read_buffer, 1, nullptr, &flags,
+ &read_overlapped, nullptr);
+ if (ret == 0) {
+ // Operation completed immediately!
+ } else {
+ // Winsock should return WSA_IO_PENDING and we wait on the event.
+ if (WSAGetLastError() != WSA_IO_PENDING) {
+ return SBOX_TEST_FOURTH_ERROR;
+ }
+ DWORD wait = WaitForSingleObject(read_event.Get(), test_timeout());
+
+ if (wait != WAIT_OBJECT_0)
+ return SBOX_TEST_TIMED_OUT;
+ }
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
TEST(AppContainerLaunchTest, CheckLPACACE) {
if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
return;
@@ -422,4 +808,171 @@ TEST(AppContainerLaunchTest, CheckLPACACE) {
AppContainerBase::Delete(GetAppContainerProfileName().c_str());
}
+TEST(AppContainerLaunchTest, IsAppContainer) {
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
+ return;
+ TestRunner runner;
+ AddNetworkAppContainerPolicy(runner.GetPolicy());
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIsAppContainer"));
+
+ AppContainerBase::Delete(GetAppContainerProfileName().c_str());
+}
+
+TEST(AppContainerLaunchTest, IsNotAppContainer) {
+ TestRunner runner;
+
+ EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"CheckIsAppContainer"));
+}
+
+class SocketBrokerTest
+ : public ::testing::Test,
+ public ::testing::WithParamInterface<
+ ::testing::tuple</* using app container */ bool,
+ /* using socket brokering */ bool,
+ /* connect to real adapter */ bool,
+ /* add brokering rule */ bool>> {
+ public:
+ void SetUp() override {
+ InitWinsock();
+ SetUpSandboxPolicy();
+ }
+
+ void TearDown() override {
+ if (IsTestInAppContainer())
+ AppContainerBase::Delete(GetAppContainerProfileName().c_str());
+ }
+
+ protected:
+ bool IsTestInAppContainer() { return ::testing::get<0>(GetParam()); }
+ bool IsTestUsingBrokeredSockets() { return ::testing::get<1>(GetParam()); }
+ bool IsTestConnectingToRealAdapter() { return ::testing::get<2>(GetParam()); }
+ bool ShouldBrokerRuleBeAdded() { return ::testing::get<3>(GetParam()); }
+ SboxTestResult GetExpectedTestResult() {
+ if (!IsTestInAppContainer())
+ return SBOX_TEST_SUCCEEDED;
+
+ if (IsTestUsingBrokeredSockets()) {
+ if (ShouldBrokerRuleBeAdded())
+ return SBOX_TEST_SUCCEEDED;
+ return SBOX_TEST_FIRST_ERROR;
+ }
+
+ return SBOX_TEST_TIMED_OUT;
+ }
+
+ std::wstring GetTestHostName() {
+ if (!IsTestConnectingToRealAdapter())
+ return L"127.0.0.1";
+ // Try and obtain a local network address.
+ // MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
+ size_t buffer_size = 16384;
+ std::unique_ptr<char[]> adapter_info(new char[buffer_size]);
+ PIP_ADAPTER_ADDRESSES adapter_addrs =
+ reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
+ ULONG flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
+ GAA_FLAG_SKIP_MULTICAST);
+ ULONG ret = 0;
+ do {
+ adapter_info.reset(new char[buffer_size]);
+ adapter_addrs =
+ reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
+ ret = GetAdaptersAddresses(AF_INET, flags, 0, adapter_addrs,
+ reinterpret_cast<PULONG>(&buffer_size));
+ } while (ret == ERROR_BUFFER_OVERFLOW);
+ if (ret != ERROR_SUCCESS)
+ return std::wstring();
+ while (adapter_addrs) {
+ if (adapter_addrs->OperStatus == IfOperStatusUp) {
+ PIP_ADAPTER_UNICAST_ADDRESS address =
+ adapter_addrs->FirstUnicastAddress;
+ for (; address; address = address->Next) {
+ if (address->Address.lpSockaddr->sa_family != AF_INET)
+ continue;
+ sockaddr_in* ipv4_addr =
+ reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr);
+ return base::UTF8ToWide(inet_ntoa(ipv4_addr->sin_addr));
+ }
+ }
+ adapter_addrs = adapter_addrs->Next;
+ }
+ return std::wstring();
+ }
+
+ void SetUpSandboxPolicy() {
+ if (IsTestInAppContainer()) {
+ AddNetworkAppContainerPolicy(runner_.GetPolicy());
+ } else {
+ TargetPolicy* policy = runner_.GetPolicy();
+ policy->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS, USER_LIMITED);
+ }
+ if (ShouldBrokerRuleBeAdded()) {
+ TargetPolicy* policy = runner_.GetPolicy();
+ policy->AddRule(TargetPolicy::SUBSYS_SOCKET,
+ TargetPolicy::SOCKET_ALLOW_BROKER, nullptr);
+ }
+ }
+
+ protected:
+ TestRunner runner_;
+};
+
+TEST_P(SocketBrokerTest, SocketBrokerTestUDP) {
+ // App Container socket brokering only supported on Win10 RS1 and above.
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
+ return;
+
+ UDPEchoServer server;
+ ASSERT_TRUE(server.Start());
+
+ std::wstring hostname = GetTestHostName();
+ ASSERT_TRUE(!hostname.empty());
+ EXPECT_EQ(
+ GetExpectedTestResult(),
+ runner_.RunTest(base::StringPrintf(L"Socket_CreateUDP %ls %d %d",
+ hostname.c_str(), server.GetPort(),
+ IsTestUsingBrokeredSockets() ? 1 : 0)
+ .c_str()));
+}
+
+TEST_P(SocketBrokerTest, SocketBrokerTestTCP) {
+ // App Container socket brokering only supported on Win10 RS1 and above.
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
+ return;
+
+ std::wstring hostname = GetTestHostName();
+ ASSERT_TRUE(!hostname.empty());
+ EXPECT_EQ(
+ GetExpectedTestResult(),
+ runner_.RunTest(base::StringPrintf(L"Socket_CreateTCP %ls 445 %d",
+ hostname.c_str(),
+ IsTestUsingBrokeredSockets() ? 1 : 0)
+ .c_str()));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AppContainerBrokered,
+ SocketBrokerTest,
+ ::testing::Combine(
+ /* using app container */ ::testing::Values(true),
+ /* using socket brokering */ ::testing::Values(true),
+ /* connect to real adapter */ ::testing::Values(true, false),
+ /* add brokering rule */ ::testing::Values(true, false)));
+INSTANTIATE_TEST_CASE_P(
+ AppContainerNonBrokered,
+ SocketBrokerTest,
+ ::testing::Combine(
+ /* using app container */ ::testing::Values(true),
+ /* using socket brokering */ ::testing::Values(false),
+ /* connect to real adapter */ ::testing::Values(true, false),
+ /* add brokering rule */ ::testing::Values(true, false)));
+INSTANTIATE_TEST_CASE_P(
+ NoAppContainerNonBrokered,
+ SocketBrokerTest,
+ ::testing::Combine(
+ /* using app container */ ::testing::Values(false),
+ /* using socket brokering */ ::testing::Values(false),
+ /* connect to real adapter */ ::testing::Values(true, false),
+ /* add brokering rule */ ::testing::Values(true, false)));
+
} // namespace sandbox
diff --git a/chromium/sandbox/win/src/app_container_unittest.cc b/chromium/sandbox/win/src/app_container_unittest.cc
index 3f22a49b187..a57bd443c4d 100644
--- a/chromium/sandbox/win/src/app_container_unittest.cc
+++ b/chromium/sandbox/win/src/app_container_unittest.cc
@@ -103,7 +103,7 @@ std::wstring GenerateRandomPackageName() {
class SECURITY_ATTRIBUTES_SDDL : public SECURITY_ATTRIBUTES {
public:
- SECURITY_ATTRIBUTES_SDDL(LPCWSTR sddl) : SECURITY_ATTRIBUTES() {
+ explicit SECURITY_ATTRIBUTES_SDDL(LPCWSTR sddl) : SECURITY_ATTRIBUTES() {
nLength = sizeof(SECURITY_ATTRIBUTES);
if (!::ConvertStringSecurityDescriptorToSecurityDescriptor(
sddl, SDDL_REVISION_1, &lpSecurityDescriptor, nullptr)) {
diff --git a/chromium/sandbox/win/src/broker_services.cc b/chromium/sandbox/win/src/broker_services.cc
index c61ad9410ed..68b40b5707c 100644
--- a/chromium/sandbox/win/src/broker_services.cc
+++ b/chromium/sandbox/win/src/broker_services.cc
@@ -10,7 +10,7 @@
#include <utility>
-#include "base/check.h"
+#include "base/check_op.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
@@ -168,11 +168,11 @@ DWORD WINAPI TargetEventsThread(PVOID param) {
::ResetEvent(params->no_targets);
while (true) {
- DWORD events = 0;
+ DWORD event = 0;
ULONG_PTR key = 0;
LPOVERLAPPED ovl = nullptr;
- if (!::GetQueuedCompletionStatus(params->iocp, &events, &key, &ovl,
+ if (!::GetQueuedCompletionStatus(params->iocp, &event, &key, &ovl,
INFINITE)) {
// This call fails if the port has been closed before we have a
// chance to service the last packet which is 'exit' anyway so
@@ -185,17 +185,21 @@ DWORD WINAPI TargetEventsThread(PVOID param) {
// that jobs can send and some of them depend on the job attributes set.
JobTracker* tracker = reinterpret_cast<JobTracker*>(key);
- // Processes may be added to a job after the process count has
- // reached zero, leading us to manipulate a freed JobTracker
- // object or job handle (as the key is no longer valid). We
- // therefore check if the tracker has already been deleted.
+ // Processes may be added to a job after the process count has reached
+ // zero, leading us to manipulate a freed JobTracker object or job handle
+ // (as the key is no longer valid). We therefore check if the tracker has
+ // already been deleted. Note that Windows may emit notifications after
+ // 'job finished' (active process zero), so not every case is unexpected.
if (std::find_if(jobs.begin(), jobs.end(), [&](auto&& p) -> bool {
return p.get() == tracker;
}) == jobs.end()) {
- CHECK(false);
+ // CHECK if job already deleted.
+ CHECK_NE(static_cast<int>(event), JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO);
+ // Continue to next notification otherwise.
+ continue;
}
- switch (events) {
+ switch (event) {
case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: {
// The job object has signaled that the last process associated
// with it has terminated. It is safe to free the tracker
diff --git a/chromium/sandbox/win/src/crosscall_client.h b/chromium/sandbox/win/src/crosscall_client.h
index af13651ddce..dd2974c16aa 100644
--- a/chromium/sandbox/win/src/crosscall_client.h
+++ b/chromium/sandbox/win/src/crosscall_client.h
@@ -58,7 +58,7 @@ const uint32_t kIPCChannelSize = 1024;
template <typename T>
class CopyHelper {
public:
- CopyHelper(const T& t) : t_(t) {}
+ explicit CopyHelper(const T& t) : t_(t) {}
// Returns the pointer to the start of the input.
const void* GetStart() const { return &t_; }
@@ -91,7 +91,7 @@ class CopyHelper {
template <>
class CopyHelper<void*> {
public:
- CopyHelper(void* t) : t_(t) {}
+ explicit CopyHelper(void* t) : t_(t) {}
// Returns the pointer to the start of the input.
const void* GetStart() const { return &t_; }
@@ -121,7 +121,7 @@ class CopyHelper<void*> {
template <>
class CopyHelper<const wchar_t*> {
public:
- CopyHelper(const wchar_t* t) : t_(t) {}
+ explicit CopyHelper(const wchar_t* t) : t_(t) {}
// Returns the pointer to the start of the string.
const void* GetStart() const { return t_; }
@@ -169,7 +169,7 @@ template <>
class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
public:
typedef CopyHelper<const wchar_t*> Base;
- CopyHelper(wchar_t* t) : Base(t) {}
+ explicit CopyHelper(wchar_t* t) : Base(t) {}
const void* GetStart() const { return Base::GetStart(); }
@@ -189,7 +189,7 @@ class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
public:
typedef const wchar_t array[n];
typedef CopyHelper<const wchar_t*> Base;
- CopyHelper(array t) : Base(t) {}
+ explicit CopyHelper(array t) : Base(t) {}
const void* GetStart() const { return Base::GetStart(); }
@@ -216,7 +216,7 @@ class InOutCountedBuffer : public CountedBuffer {
template <>
class CopyHelper<InOutCountedBuffer> {
public:
- CopyHelper(const InOutCountedBuffer t) : t_(t) {}
+ explicit CopyHelper(const InOutCountedBuffer t) : t_(t) {}
// Returns the pointer to the start of the string.
const void* GetStart() const { return t_.Buffer(); }
diff --git a/chromium/sandbox/win/src/file_policy_test.cc b/chromium/sandbox/win/src/file_policy_test.cc
index 4989ab308fc..b061c049c89 100644
--- a/chromium/sandbox/win/src/file_policy_test.cc
+++ b/chromium/sandbox/win/src/file_policy_test.cc
@@ -89,14 +89,11 @@ SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t** argv) {
if (INVALID_HANDLE_VALUE != file) {
::CloseHandle(file);
return SBOX_TEST_SUCCEEDED;
- } else {
- if (ERROR_ACCESS_DENIED == ::GetLastError()) {
- return SBOX_TEST_DENIED;
- } else {
- return SBOX_TEST_FAILED;
- }
}
- return SBOX_TEST_SUCCEEDED;
+ if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+ return SBOX_TEST_DENIED;
+ }
+ return SBOX_TEST_FAILED;
}
// Creates the file in parameter using the NtCreateFile api and returns if the
diff --git a/chromium/sandbox/win/src/filesystem_policy.cc b/chromium/sandbox/win/src/filesystem_policy.cc
index f8cd1647584..fe995b7be70 100644
--- a/chromium/sandbox/win/src/filesystem_policy.cc
+++ b/chromium/sandbox/win/src/filesystem_policy.cc
@@ -8,8 +8,8 @@
#include <string>
+#include "base/cxx17_backports.h"
#include "base/notreached.h"
-#include "base/stl_util.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/ipc_tags.h"
diff --git a/chromium/sandbox/win/src/interception.cc b/chromium/sandbox/win/src/interception.cc
index 369beebac9f..b164a83dda9 100644
--- a/chromium/sandbox/win/src/interception.cc
+++ b/chromium/sandbox/win/src/interception.cc
@@ -13,6 +13,7 @@
#include <set>
#include <string>
+#include "base/bits.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/scoped_native_library.h"
@@ -378,7 +379,7 @@ ResultCode InterceptionManager::PatchNtdll(bool hot_patch_needed) {
thunk_offset &= kPageSize - 1;
// Make an aligned, padded allocation, and move the pointer to our chunk.
- size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & ~(kPageSize - 1);
+ size_t thunk_bytes_padded = base::bits::AlignUp(thunk_bytes, kPageSize);
thunk_base = reinterpret_cast<BYTE*>(
::VirtualAllocEx(child, thunk_base, thunk_bytes_padded, MEM_COMMIT,
PAGE_EXECUTE_READWRITE));
diff --git a/chromium/sandbox/win/src/ipc_leak_test.cc b/chromium/sandbox/win/src/ipc_leak_test.cc
index 7abcc4cd3c4..e77cd94126b 100644
--- a/chromium/sandbox/win/src/ipc_leak_test.cc
+++ b/chromium/sandbox/win/src/ipc_leak_test.cc
@@ -8,8 +8,8 @@
#include <stdlib.h>
+#include "base/cxx17_backports.h"
#include "base/memory/page_size.h"
-#include "base/stl_util.h"
#include "base/win/win_util.h"
#include "sandbox/win/src/crosscall_client.h"
#include "sandbox/win/src/filesystem_interception.h"
diff --git a/chromium/sandbox/win/src/ipc_tags.h b/chromium/sandbox/win/src/ipc_tags.h
index 91e06dbc36e..8603a2488c4 100644
--- a/chromium/sandbox/win/src/ipc_tags.h
+++ b/chromium/sandbox/win/src/ipc_tags.h
@@ -33,6 +33,7 @@ enum class IpcTag {
USER_REGISTERCLASSW,
CREATETHREAD,
NTCREATESECTION,
+ WS2SOCKET,
LAST
};
diff --git a/chromium/sandbox/win/src/policy_engine_opcodes.cc b/chromium/sandbox/win/src/policy_engine_opcodes.cc
index 4bac801f9bc..223b848c3f5 100644
--- a/chromium/sandbox/win/src/policy_engine_opcodes.cc
+++ b/chromium/sandbox/win/src/policy_engine_opcodes.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/check_op.h"
#include "sandbox/win/src/sandbox_nt_types.h"
#include "sandbox/win/src/sandbox_types.h"
@@ -42,6 +43,11 @@ SANDBOX_INTERCEPT NtExports g_nt;
// only the factory method and the evaluation function know the stored argument
// order and meaning.
+size_t OpcodeFactory::memory_size() const {
+ DCHECK_GE(memory_bottom_, memory_top_);
+ return memory_bottom_ - memory_top_;
+}
+
template <int>
EvalResult OpcodeEval(PolicyOpcode* opcode,
const ParameterSet* pp,
diff --git a/chromium/sandbox/win/src/policy_engine_opcodes.h b/chromium/sandbox/win/src/policy_engine_opcodes.h
index 88a703c1297..fe53376b8c4 100644
--- a/chromium/sandbox/win/src/policy_engine_opcodes.h
+++ b/chromium/sandbox/win/src/policy_engine_opcodes.h
@@ -8,7 +8,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/check_op.h"
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "sandbox/win/src/policy_engine_params.h"
@@ -283,10 +282,7 @@ class OpcodeFactory {
}
// Returns the available memory to make opcodes.
- size_t memory_size() const {
- DCHECK_GE(memory_bottom_, memory_top_);
- return memory_bottom_ - memory_top_;
- }
+ size_t memory_size() const;
// Creates an OpAlwaysFalse opcode.
PolicyOpcode* MakeOpAlwaysFalse(uint32_t options);
diff --git a/chromium/sandbox/win/src/policy_engine_params.h b/chromium/sandbox/win/src/policy_engine_params.h
index d7ffdc47df6..d7d4d5c6fe7 100644
--- a/chromium/sandbox/win/src/policy_engine_params.h
+++ b/chromium/sandbox/win/src/policy_engine_params.h
@@ -118,43 +118,49 @@ class ParameterSet {
template <typename T>
class ParameterSetEx : public ParameterSet {
public:
- ParameterSetEx(const void* address);
+ explicit ParameterSetEx(const void* address);
};
template <>
class ParameterSetEx<void const*> : public ParameterSet {
public:
- ParameterSetEx(const void* address) : ParameterSet(VOIDPTR_TYPE, address) {}
+ explicit ParameterSetEx(const void* address)
+ : ParameterSet(VOIDPTR_TYPE, address) {}
};
template <>
class ParameterSetEx<void*> : public ParameterSet {
public:
- ParameterSetEx(const void* address) : ParameterSet(VOIDPTR_TYPE, address) {}
+ explicit ParameterSetEx(const void* address)
+ : ParameterSet(VOIDPTR_TYPE, address) {}
};
template <>
class ParameterSetEx<wchar_t*> : public ParameterSet {
public:
- ParameterSetEx(const void* address) : ParameterSet(WCHAR_TYPE, address) {}
+ explicit ParameterSetEx(const void* address)
+ : ParameterSet(WCHAR_TYPE, address) {}
};
template <>
class ParameterSetEx<wchar_t const*> : public ParameterSet {
public:
- ParameterSetEx(const void* address) : ParameterSet(WCHAR_TYPE, address) {}
+ explicit ParameterSetEx(const void* address)
+ : ParameterSet(WCHAR_TYPE, address) {}
};
template <>
class ParameterSetEx<uint32_t> : public ParameterSet {
public:
- ParameterSetEx(const void* address) : ParameterSet(UINT32_TYPE, address) {}
+ explicit ParameterSetEx(const void* address)
+ : ParameterSet(UINT32_TYPE, address) {}
};
template <>
class ParameterSetEx<UNICODE_STRING> : public ParameterSet {
public:
- ParameterSetEx(const void* address) : ParameterSet(UNISTR_TYPE, address) {}
+ explicit ParameterSetEx(const void* address)
+ : ParameterSet(UNISTR_TYPE, address) {}
};
template <typename T>
diff --git a/chromium/sandbox/win/src/policy_low_level.cc b/chromium/sandbox/win/src/policy_low_level.cc
index d987211c8b5..ea6fcbb0431 100644
--- a/chromium/sandbox/win/src/policy_low_level.cc
+++ b/chromium/sandbox/win/src/policy_low_level.cc
@@ -10,6 +10,8 @@
#include <map>
#include <string>
+#include "base/compiler_specific.h"
+
namespace {
// A single rule can use at most this amount of memory.
diff --git a/chromium/sandbox/win/src/sandbox.cc b/chromium/sandbox/win/src/sandbox.cc
index f65e379683d..4a2d3539525 100644
--- a/chromium/sandbox/win/src/sandbox.cc
+++ b/chromium/sandbox/win/src/sandbox.cc
@@ -41,7 +41,18 @@ TargetServices* SandboxFactory::GetTargetServices() {
} // namespace sandbox
+// Allow calling to SetInterceptionHint from any loaded DLL.
+extern "C" {
+
// Allows querying for whether the current process has been sandboxed.
-extern "C" bool __declspec(dllexport) IsSandboxedProcess() {
+__declspec(dllexport) bool IsSandboxedProcess() {
return !!sandbox::g_shared_section;
}
+
+__declspec(dllexport) sandbox::TargetServicesBase* GetMainTargetServices() {
+ if (!sandbox::g_shared_section)
+ return nullptr;
+ return sandbox::TargetServicesBase::GetInstance();
+}
+
+} // extern "C"
diff --git a/chromium/sandbox/win/src/sandbox.h b/chromium/sandbox/win/src/sandbox.h
index 35996c1726e..3e280ad3004 100644
--- a/chromium/sandbox/win/src/sandbox.h
+++ b/chromium/sandbox/win/src/sandbox.h
@@ -21,6 +21,7 @@
#if !defined(SANDBOX_FUZZ_TARGET)
#include <windows.h>
+#include <winsock2.h>
#else
#include "sandbox/win/fuzzer/fuzzer_types.h"
#endif
@@ -143,7 +144,7 @@ class [[clang::lto_visibility_public]] BrokerServices {
// }
//
// For more information see the BrokerServices API documentation.
-class TargetServices {
+class [[clang::lto_visibility_public]] TargetServices {
public:
// Initializes the target. Must call this function before any other.
// returns ALL_OK if successful. All other return values imply failure.
@@ -161,6 +162,12 @@ class TargetServices {
// LowerToken has been called or not.
virtual ProcessState* GetState() = 0;
+ // Attempts to create a socket in the broker process, and duplicates it back
+ // to the target. The socket will be created with default flags and no group.
+ // Only TCP/UDP and IPV4/IPV6 sockets are supported by the broker.
+ // The socket will be created with WSA_FLAG_OVERLAPPED flags.
+ virtual SOCKET CreateBrokeredSocket(int af, int family, int protocol) = 0;
+
protected:
~TargetServices() {}
};
diff --git a/chromium/sandbox/win/src/sandbox_policy.h b/chromium/sandbox/win/src/sandbox_policy.h
index 89713514f28..d24baf47ee8 100644
--- a/chromium/sandbox/win/src/sandbox_policy.h
+++ b/chromium/sandbox/win/src/sandbox_policy.h
@@ -32,7 +32,8 @@ class TargetPolicy {
SUBSYS_REGISTRY, // Creation and opening of registry keys.
SUBSYS_SYNC, // Creation of named sync objects.
SUBSYS_WIN32K_LOCKDOWN, // Win32K Lockdown related policy.
- SUBSYS_SIGNED_BINARY // Signed binary policy.
+ SUBSYS_SIGNED_BINARY, // Signed binary policy.
+ SUBSYS_SOCKET // Socket brokering policy.
};
// Allowable semantics when a rule is matched.
@@ -59,7 +60,8 @@ class TargetPolicy {
FAKE_USER_GDI_INIT, // Fakes user32 and gdi32 initialization. This can
// be used to allow the DLLs to load and initialize
// even if the process cannot access that subsystem.
- SIGNED_ALLOW_LOAD // Allows loading the module when CIG is enabled.
+ SIGNED_ALLOW_LOAD, // Allows loading the module when CIG is enabled.
+ SOCKET_ALLOW_BROKER // Allows brokering of sockets.
};
// Increments the reference count of this object. The reference count must
diff --git a/chromium/sandbox/win/src/sandbox_policy_base.cc b/chromium/sandbox/win/src/sandbox_policy_base.cc
index 0c8896a78a8..4f585e5e380 100644
--- a/chromium/sandbox/win/src/sandbox_policy_base.cc
+++ b/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -13,7 +13,6 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "sandbox/win/src/acl.h"
@@ -781,6 +780,15 @@ ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
}
break;
}
+ case SUBSYS_SOCKET: {
+ // Only one semantic is supported for this subsystem; to allow socket
+ // brokering.
+ DCHECK_EQ(SOCKET_ALLOW_BROKER, semantics);
+ // A very simple policy that just allows socket brokering if present.
+ PolicyRule socket_policy(ASK_BROKER);
+ policy_maker_->AddRule(IpcTag::WS2SOCKET, &socket_policy);
+ break;
+ }
default: { return SBOX_ERROR_UNSUPPORTED; }
}
diff --git a/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc b/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc
index bc1da58d028..f1f580e5350 100644
--- a/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc
+++ b/chromium/sandbox/win/src/sandbox_policy_diagnostic.cc
@@ -193,6 +193,8 @@ std::string GetIpcTagAsString(IpcTag service) {
return "CreateThread";
case IpcTag::NTCREATESECTION:
return "NtCreateSection";
+ case IpcTag::WS2SOCKET:
+ return "WSA_Socket";
case IpcTag::LAST:
DCHECK(false) << "Unknown IpcTag";
return "Unknown";
diff --git a/chromium/sandbox/win/src/sandbox_policy_diagnostic.h b/chromium/sandbox/win/src/sandbox_policy_diagnostic.h
index 89982a3f115..d5ab4664bee 100644
--- a/chromium/sandbox/win/src/sandbox_policy_diagnostic.h
+++ b/chromium/sandbox/win/src/sandbox_policy_diagnostic.h
@@ -30,7 +30,7 @@ class PolicyBase;
class PolicyDiagnostic final : public PolicyInfo {
public:
// This should quickly copy what it needs from PolicyBase.
- PolicyDiagnostic(PolicyBase* policy);
+ explicit PolicyDiagnostic(PolicyBase* policy);
~PolicyDiagnostic() override;
const char* JsonString() override;
diff --git a/chromium/sandbox/win/src/socket_dispatcher.cc b/chromium/sandbox/win/src/socket_dispatcher.cc
new file mode 100644
index 00000000000..5d042fe91f4
--- /dev/null
+++ b/chromium/sandbox/win/src/socket_dispatcher.cc
@@ -0,0 +1,132 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/socket_dispatcher.h"
+
+#include <stdint.h>
+#include <winsock2.h>
+
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace sandbox {
+
+namespace {
+
+class SocketHandleTraits {
+ public:
+ typedef SOCKET Handle;
+
+ SocketHandleTraits() = delete;
+ SocketHandleTraits(const SocketHandleTraits&) = delete;
+ SocketHandleTraits& operator=(const SocketHandleTraits&) = delete;
+
+ static bool CloseHandle(SOCKET handle) { return ::closesocket(handle) == 0; }
+ static bool IsHandleValid(SOCKET handle) { return handle != INVALID_SOCKET; }
+ static SOCKET NullHandle() { return INVALID_SOCKET; }
+};
+
+class DummySocketVerifierTraits {
+ public:
+ using Handle = SOCKET;
+
+ DummySocketVerifierTraits() = delete;
+ DummySocketVerifierTraits(const DummySocketVerifierTraits&) = delete;
+ DummySocketVerifierTraits& operator=(const DummySocketVerifierTraits&) =
+ delete;
+
+ static void StartTracking(SOCKET handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {}
+ static void StopTracking(SOCKET handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {}
+};
+
+typedef base::win::GenericScopedHandle<SocketHandleTraits,
+ DummySocketVerifierTraits>
+ ScopedSocketHandle;
+
+} // namespace
+
+SocketDispatcher::SocketDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall create_params = {
+ {IpcTag::WS2SOCKET,
+ {UINT32_TYPE, UINT32_TYPE, UINT32_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&SocketDispatcher::WS2Socket)};
+
+ ipc_calls_.push_back(create_params);
+}
+
+bool SocketDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ // This IPC has no interceptions.
+ return true;
+}
+
+bool SocketDispatcher::WS2Socket(IPCInfo* ipc,
+ uint32_t af,
+ uint32_t type,
+ uint32_t protocol,
+ InOutCountedBuffer* protocol_info_buffer) {
+ if (af != AF_INET && af != AF_INET6)
+ return false;
+
+ if (type != SOCK_STREAM && type != SOCK_DGRAM)
+ return false;
+
+ if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
+ return false;
+
+ if (protocol_info_buffer->Size() != sizeof(WSAPROTOCOL_INFOW))
+ return false;
+
+ CountedParameterSet<NameBased> params;
+ // Policy for the IPC just needs to exist, the parameters here do not matter.
+ const wchar_t* dummy_param = L"";
+ params[NameBased::NAME] = ParamPickerMake(dummy_param);
+
+ // Verify that the target process has the permission to broker sockets.
+ if (policy_base_->EvalPolicy(IpcTag::WS2SOCKET, params.GetBase()) !=
+ ASK_BROKER) {
+ return false;
+ }
+
+ ScopedSocketHandle local_socket(
+ ::WSASocketW(af, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED));
+
+ if (!local_socket.IsValid()) {
+ ipc->return_info.extended_count = 1;
+ ipc->return_info.extended[0].unsigned_int =
+ static_cast<uint32_t>(::WSAGetLastError());
+ return true;
+ }
+
+ WSAPROTOCOL_INFOW* protocol_info =
+ reinterpret_cast<WSAPROTOCOL_INFOW*>(protocol_info_buffer->Buffer());
+
+ if (::WSADuplicateSocketW(local_socket.Get(), ipc->client_info->process_id,
+ protocol_info)) {
+ ipc->return_info.extended_count = 1;
+ ipc->return_info.extended[0].unsigned_int =
+ static_cast<uint32_t>(::WSAGetLastError());
+ return true;
+ }
+
+ return true;
+}
+
+} // namespace sandbox
diff --git a/chromium/sandbox/win/src/socket_dispatcher.h b/chromium/sandbox/win/src/socket_dispatcher.h
new file mode 100644
index 00000000000..478ec114bcb
--- /dev/null
+++ b/chromium/sandbox/win/src/socket_dispatcher.h
@@ -0,0 +1,45 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SOCKET_DISPATCHER_H_
+#define SANDBOX_WIN_SRC_SOCKET_DISPATCHER_H_
+
+#include <stdint.h>
+#include <winsock2.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles socket related IPC calls.
+class SocketDispatcher : public Dispatcher {
+ public:
+ explicit SocketDispatcher(PolicyBase* policy_base);
+ ~SocketDispatcher() override = default;
+
+ SocketDispatcher(const SocketDispatcher&) = delete;
+ SocketDispatcher& operator=(const SocketDispatcher&) = delete;
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to WS2_32!WSA_Socket in the
+ // target.
+ bool WS2Socket(IPCInfo* ipc,
+ uint32_t af,
+ uint32_t type,
+ uint32_t protocol,
+ InOutCountedBuffer* buffer);
+ PolicyBase* policy_base_;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SOCKET_DISPATCHER_H_
diff --git a/chromium/sandbox/win/src/target_services.cc b/chromium/sandbox/win/src/target_services.cc
index 52f61d7102a..23a29b6efae 100644
--- a/chromium/sandbox/win/src/target_services.cc
+++ b/chromium/sandbox/win/src/target_services.cc
@@ -165,6 +165,38 @@ TargetServicesBase* TargetServicesBase::GetInstance() {
return g_target_services;
}
+SOCKET TargetServicesBase::CreateBrokeredSocket(int af,
+ int type,
+ int protocol) {
+ if (!GetState()->InitCalled())
+ return INVALID_SOCKET;
+
+ // IPC must be fully started.
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ return INVALID_SOCKET;
+
+ CrossCallReturn answer = {0};
+ SharedMemIPCClient ipc(memory);
+
+ WSAPROTOCOL_INFOW protocol_info = {};
+
+ InOutCountedBuffer protocol_info_buffer(&protocol_info,
+ sizeof(WSAPROTOCOL_INFOW));
+
+ ResultCode code = CrossCall(ipc, IpcTag::WS2SOCKET, af, type, protocol,
+ protocol_info_buffer, &answer);
+
+ if (code != SBOX_ALL_OK)
+ return INVALID_SOCKET;
+
+ if (answer.extended_count == 1)
+ WSASetLastError(static_cast<int>(answer.extended[0].unsigned_int));
+
+ return ::WSASocket(af, type, protocol, &protocol_info, 0,
+ WSA_FLAG_OVERLAPPED);
+}
+
// The broker services a 'test' IPC service with the PING tag.
bool TargetServicesBase::TestIPCPing(int version) {
void* memory = GetGlobalIPCMemory();
diff --git a/chromium/sandbox/win/src/target_services.h b/chromium/sandbox/win/src/target_services.h
index 359ead4c41f..a63072fce87 100644
--- a/chromium/sandbox/win/src/target_services.h
+++ b/chromium/sandbox/win/src/target_services.h
@@ -41,10 +41,11 @@ class TargetServicesBase : public TargetServices {
public:
TargetServicesBase();
- // Public interface of TargetServices.
+ // Public interface of TargetServices. See comments in sandbox.h.
ResultCode Init() override;
void LowerToken() override;
ProcessState* GetState() override;
+ SOCKET CreateBrokeredSocket(int af, int type, int protocol) override;
// Factory method.
static TargetServicesBase* GetInstance();
diff --git a/chromium/sandbox/win/src/threadpool.cc b/chromium/sandbox/win/src/threadpool.cc
index 1d8fa8ac829..d4f9a554870 100644
--- a/chromium/sandbox/win/src/threadpool.cc
+++ b/chromium/sandbox/win/src/threadpool.cc
@@ -37,18 +37,24 @@ bool ThreadPool::UnRegisterWaits(void* cookie) {
if (0 == cookie) {
return false;
}
- AutoLock lock(&lock_);
- bool success = true;
- PoolObjects::iterator it = pool_objects_.begin();
- while (it != pool_objects_.end()) {
- if (it->cookie == cookie) {
- HANDLE wait = it->wait;
- it = pool_objects_.erase(it);
- success &= (::UnregisterWaitEx(wait, INVALID_HANDLE_VALUE) != 0);
- } else {
- ++it;
+ std::vector<HANDLE> finished_waits;
+ {
+ AutoLock lock(&lock_);
+ PoolObjects::iterator it = pool_objects_.begin();
+ while (it != pool_objects_.end()) {
+ if (it->cookie == cookie) {
+ HANDLE wait = it->wait;
+ it = pool_objects_.erase(it);
+ finished_waits.push_back(wait);
+ } else {
+ ++it;
+ }
}
}
+ bool success = true;
+ for (HANDLE wait : finished_waits) {
+ success &= (::UnregisterWaitEx(wait, INVALID_HANDLE_VALUE) != 0);
+ }
return success;
}
diff --git a/chromium/sandbox/win/src/top_level_dispatcher.cc b/chromium/sandbox/win/src/top_level_dispatcher.cc
index da354af9550..522f2f6f7a8 100644
--- a/chromium/sandbox/win/src/top_level_dispatcher.cc
+++ b/chromium/sandbox/win/src/top_level_dispatcher.cc
@@ -20,6 +20,7 @@
#include "sandbox/win/src/registry_dispatcher.h"
#include "sandbox/win/src/sandbox_policy_base.h"
#include "sandbox/win/src/signed_dispatcher.h"
+#include "sandbox/win/src/socket_dispatcher.h"
#include "sandbox/win/src/sync_dispatcher.h"
namespace sandbox {
@@ -70,6 +71,10 @@ TopLevelDispatcher::TopLevelDispatcher(PolicyBase* policy) : policy_(policy) {
dispatcher = new SignedDispatcher(policy_);
ipc_targets_[static_cast<size_t>(IpcTag::NTCREATESECTION)] = dispatcher;
signed_dispatcher_.reset(dispatcher);
+
+ dispatcher = new SocketDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::WS2SOCKET)] = dispatcher;
+ socket_dispatcher_.reset(dispatcher);
}
TopLevelDispatcher::~TopLevelDispatcher() {}
diff --git a/chromium/sandbox/win/src/top_level_dispatcher.h b/chromium/sandbox/win/src/top_level_dispatcher.h
index 94a923cee4c..897d822b5a3 100644
--- a/chromium/sandbox/win/src/top_level_dispatcher.h
+++ b/chromium/sandbox/win/src/top_level_dispatcher.h
@@ -43,6 +43,7 @@ class TopLevelDispatcher : public Dispatcher {
std::unique_ptr<Dispatcher> handle_dispatcher_;
std::unique_ptr<Dispatcher> process_mitigations_win32k_dispatcher_;
std::unique_ptr<Dispatcher> signed_dispatcher_;
+ std::unique_ptr<Dispatcher> socket_dispatcher_;
Dispatcher* ipc_targets_[kMaxIpcTag];
DISALLOW_COPY_AND_ASSIGN(TopLevelDispatcher);
diff --git a/chromium/sandbox/win/src/win_utils.cc b/chromium/sandbox/win/src/win_utils.cc
index 0c97c31bcd0..1db77504ba1 100644
--- a/chromium/sandbox/win/src/win_utils.cc
+++ b/chromium/sandbox/win/src/win_utils.cc
@@ -13,8 +13,8 @@
#include <string>
#include <vector>
+#include "base/cxx17_backports.h"
#include "base/numerics/safe_math.h"
-#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/win/pe_image.h"
#include "sandbox/win/src/internal_types.h"
diff --git a/chromium/sandbox/win/src/win_utils.h b/chromium/sandbox/win/src/win_utils.h
index 5945cd60965..085be2a95e3 100644
--- a/chromium/sandbox/win/src/win_utils.h
+++ b/chromium/sandbox/win/src/win_utils.h
@@ -10,8 +10,8 @@
#include <memory>
#include <string>
+#include "base/cxx17_backports.h"
#include "base/macros.h"
-#include "base/stl_util.h"
#include "sandbox/win/src/nt_internals.h"
namespace sandbox {