diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-01-20 13:40:20 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-01-22 12:41:23 +0000 |
commit | 7961cea6d1041e3e454dae6a1da660b453efd238 (patch) | |
tree | c0eeb4a9ff9ba32986289c1653d9608e53ccb444 /chromium/sandbox | |
parent | b7034d0803538058e5c9d904ef03cf5eab34f6ef (diff) | |
download | qtwebengine-chromium-7961cea6d1041e3e454dae6a1da660b453efd238.tar.gz |
BASELINE: Update Chromium to 78.0.3904.130
Change-Id: If185e0c0061b3437531c97c9c8c78f239352a68b
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/sandbox')
26 files changed, 232 insertions, 101 deletions
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc index 7dbcc875229..816c0d63dee 100644 --- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc +++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc @@ -313,6 +313,7 @@ bool SyscallSets::IsAllowedSignalHandling(int sysno) { case __NR_rt_sigaction: case __NR_rt_sigprocmask: case __NR_rt_sigreturn: + case __NR_rt_sigtimedwait: #if defined(__i386__) || defined(__arm__) || \ (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)) case __NR_sigaction: @@ -323,7 +324,6 @@ bool SyscallSets::IsAllowedSignalHandling(int sysno) { case __NR_rt_sigpending: case __NR_rt_sigqueueinfo: case __NR_rt_sigsuspend: - case __NR_rt_sigtimedwait: case __NR_rt_tgsigqueueinfo: case __NR_sigaltstack: #if !defined(__aarch64__) diff --git a/chromium/sandbox/linux/syscall_broker/broker_client.cc b/chromium/sandbox/linux/syscall_broker/broker_client.cc index fa7855c2bad..79640d09744 100644 --- a/chromium/sandbox/linux/syscall_broker/broker_client.cc +++ b/chromium/sandbox/linux/syscall_broker/broker_client.cc @@ -9,6 +9,7 @@ #include <stddef.h> #include <stdint.h> #include <sys/socket.h> +#include <sys/stat.h> #include <utility> diff --git a/chromium/sandbox/linux/syscall_broker/broker_client.h b/chromium/sandbox/linux/syscall_broker/broker_client.h index a228afec9fd..842ee16a0c7 100644 --- a/chromium/sandbox/linux/syscall_broker/broker_client.h +++ b/chromium/sandbox/linux/syscall_broker/broker_client.h @@ -71,7 +71,7 @@ class BrokerClient { int Stat(const char* pathname, bool follow_links, struct stat* sb) const; int Stat64(const char* pathname, bool folllow_links, struct stat64* sb) const; - // Can be used in place of rmdir(). + // Can be used in place of unlink(). int Unlink(const char* unlink) const; private: diff --git a/chromium/sandbox/linux/syscall_broker/broker_process.h b/chromium/sandbox/linux/syscall_broker/broker_process.h index e994a01d5c1..849238f48e6 100644 --- a/chromium/sandbox/linux/syscall_broker/broker_process.h +++ b/chromium/sandbox/linux/syscall_broker/broker_process.h @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_ -#define SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_ +#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_PROCESS_H_ +#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_PROCESS_H_ + +#include <sys/stat.h> #include <memory> #include <string> @@ -139,4 +141,4 @@ class SANDBOX_EXPORT BrokerProcess { } // namespace sandbox -#endif // SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_ +#endif // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_PROCESS_H_ diff --git a/chromium/sandbox/mac/BUILD.gn b/chromium/sandbox/mac/BUILD.gn index cbf9488aa9b..1ef9664ea57 100644 --- a/chromium/sandbox/mac/BUILD.gn +++ b/chromium/sandbox/mac/BUILD.gn @@ -67,7 +67,7 @@ component("system_services") { test("sandbox_mac_unittests") { sources = [ - "mojom/struct_traits_unittest.cc", + "mojom/mojom_traits_unittest.cc", "sandbox_mac_compiler_unittest.mm", "sandbox_mac_seatbelt_exec_unittest.cc", "seatbelt_extension_unittest.cc", diff --git a/chromium/sandbox/mac/mojom/OWNERS b/chromium/sandbox/mac/mojom/OWNERS index fc57672d791..3e6cfccf40c 100644 --- a/chromium/sandbox/mac/mojom/OWNERS +++ b/chromium/sandbox/mac/mojom/OWNERS @@ -1,6 +1,6 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS -per-file *_struct_traits*.*=set noparent -per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS +per-file *_mojom_traits*.*=set noparent +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS per-file *.typemap=set noparent per-file *.typemap=file://ipc/SECURITY_OWNERS
\ No newline at end of file diff --git a/chromium/sandbox/mac/mojom/struct_traits_unittest.cc b/chromium/sandbox/mac/mojom/mojom_traits_unittest.cc index ace9c32b3c8..e6f38797d9f 100644 --- a/chromium/sandbox/mac/mojom/struct_traits_unittest.cc +++ b/chromium/sandbox/mac/mojom/mojom_traits_unittest.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/test/scoped_task_environment.h" +#include "base/test/task_environment.h" #include "mojo/public/cpp/bindings/binding.h" -#include "sandbox/mac/mojom/seatbelt_extension_token_struct_traits.h" +#include "sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.h" #include "sandbox/mac/mojom/traits_test_service.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,7 +29,7 @@ class StructTraitsTest : public testing::Test, std::move(callback).Run(std::move(token)); } - base::test::ScopedTaskEnvironment task_environment_; + base::test::TaskEnvironment task_environment_; sandbox::mac::mojom::TraitsTestServicePtr interface_ptr_; mojo::Binding<sandbox::mac::mojom::TraitsTestService> binding_; diff --git a/chromium/sandbox/mac/mojom/seatbelt_extension_token.typemap b/chromium/sandbox/mac/mojom/seatbelt_extension_token.typemap index 430faeb78ce..e22e69ce105 100644 --- a/chromium/sandbox/mac/mojom/seatbelt_extension_token.typemap +++ b/chromium/sandbox/mac/mojom/seatbelt_extension_token.typemap @@ -5,11 +5,11 @@ mojom = "//sandbox/mac/mojom/seatbelt_extension_token.mojom" public_headers = [ "//sandbox/mac/seatbelt_extension_token.h" ] traits_headers = - [ "//sandbox/mac/mojom/seatbelt_extension_token_struct_traits.h" ] + [ "//sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.h" ] sources = [ - "//sandbox/mac/mojom/seatbelt_extension_token_struct_traits.cc", + "//sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.cc", ] deps = [ "//sandbox/mac:seatbelt_extension", ] -type_mappings = [ "sandbox.mac.mojom.SeatbeltExtensionToken=sandbox::SeatbeltExtensionToken[move_only]" ] +type_mappings = [ "sandbox.mac.mojom.SeatbeltExtensionToken=::sandbox::SeatbeltExtensionToken[move_only]" ] diff --git a/chromium/sandbox/mac/mojom/seatbelt_extension_token_struct_traits.cc b/chromium/sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.cc index ae2a1174e8f..fd31c46994c 100644 --- a/chromium/sandbox/mac/mojom/seatbelt_extension_token_struct_traits.cc +++ b/chromium/sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "sandbox/mac/mojom/seatbelt_extension_token_struct_traits.h" +#include "sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.h" namespace mojo { diff --git a/chromium/sandbox/mac/mojom/seatbelt_extension_token_struct_traits.h b/chromium/sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.h index 714802642d7..f9a7bdf1b8a 100644 --- a/chromium/sandbox/mac/mojom/seatbelt_extension_token_struct_traits.h +++ b/chromium/sandbox/mac/mojom/seatbelt_extension_token_mojom_traits.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SANDBOX_MAC_MOJOM_SEATBELT_EXTENSION_TOKEN_STRUCT_TRAITS_H_ -#define SANDBOX_MAC_MOJOM_SEATBELT_EXTENSION_TOKEN_STRUCT_TRAITS_H_ +#ifndef SANDBOX_MAC_MOJOM_SEATBELT_EXTENSION_TOKEN_MOJOM_TRAITS_H_ +#define SANDBOX_MAC_MOJOM_SEATBELT_EXTENSION_TOKEN_MOJOM_TRAITS_H_ #include <string> @@ -24,4 +24,4 @@ struct StructTraits<sandbox::mac::mojom::SeatbeltExtensionTokenDataView, } // namespace mojo -#endif // SANDBOX_MAC_MOJOM_SEATBELT_EXTENSION_TOKEN_STRUCT_TRAITS_H_ +#endif // SANDBOX_MAC_MOJOM_SEATBELT_EXTENSION_TOKEN_MOJOM_TRAITS_H_ diff --git a/chromium/sandbox/win/sandbox_poc/main_ui_window.cc b/chromium/sandbox/win/sandbox_poc/main_ui_window.cc index 89c1be76697..6bdc171823b 100644 --- a/chromium/sandbox/win/sandbox_poc/main_ui_window.cc +++ b/chromium/sandbox/win/sandbox_poc/main_ui_window.cc @@ -626,6 +626,7 @@ void MainUIWindow::AddDebugMessage(const wchar_t* format, ...) { text[kMaxDebugBuffSize] = L'\0'; InsertLineInListView(text); + va_end(arg_list); } diff --git a/chromium/sandbox/win/sandbox_poc/sandbox.cc b/chromium/sandbox/win/sandbox_poc/sandbox.cc index 88757ef6846..6d49a803363 100644 --- a/chromium/sandbox/win/sandbox_poc/sandbox.cc +++ b/chromium/sandbox/win/sandbox_poc/sandbox.cc @@ -154,6 +154,7 @@ int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, wchar_t* command_line, HMODULE dll_module = ::LoadLibraryA(dll_name.c_str()); if (dll_module == NULL) { // TODO(finnur): write the failure to the log file + CloseHandle(pipe); return -5; } diff --git a/chromium/sandbox/win/src/app_container_test.cc b/chromium/sandbox/win/src/app_container_test.cc index d6e3d0e94cb..a6c0948a942 100644 --- a/chromium/sandbox/win/src/app_container_test.cc +++ b/chromium/sandbox/win/src/app_container_test.cc @@ -146,6 +146,8 @@ class AppContainerProfileTest : public ::testing::Test { broker_services_ = GetBroker(); policy_ = broker_services_->CreatePolicy(); ASSERT_EQ(SBOX_ALL_OK, + policy_->SetProcessMitigations(MITIGATION_HEAP_TERMINATE)); + ASSERT_EQ(SBOX_ALL_OK, policy_->AddAppContainerProfile(package_name_.c_str(), true)); // For testing purposes we known the base class so cast directly. profile_ = static_cast<AppContainerProfileBase*>( @@ -212,7 +214,20 @@ TEST_F(AppContainerProfileTest, CheckIncompatibleOptions) { EXPECT_EQ(SBOX_ERROR_BAD_PARAMS, policy_->SetIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED)); EXPECT_EQ(SBOX_ERROR_BAD_PARAMS, policy_->SetLowBox(kAppContainerSid)); - EXPECT_EQ(SBOX_ERROR_BAD_PARAMS, + + MitigationFlags expected_mitigations = 0; + MitigationFlags expected_delayed = MITIGATION_HEAP_TERMINATE; + sandbox::ResultCode expected_result = SBOX_ERROR_BAD_PARAMS; + + if (base::win::GetVersion() >= base::win::Version::WIN10_RS5) { + expected_mitigations = MITIGATION_HEAP_TERMINATE; + expected_delayed = 0; + expected_result = SBOX_ALL_OK; + } + + EXPECT_EQ(expected_mitigations, policy_->GetProcessMitigations()); + EXPECT_EQ(expected_delayed, policy_->GetDelayedProcessMitigations()); + EXPECT_EQ(expected_result, policy_->SetProcessMitigations(MITIGATION_HEAP_TERMINATE)); } diff --git a/chromium/sandbox/win/src/broker_services.cc b/chromium/sandbox/win/src/broker_services.cc index ae7d15de30e..7c7c53397ba 100644 --- a/chromium/sandbox/win/src/broker_services.cc +++ b/chromium/sandbox/win/src/broker_services.cc @@ -282,15 +282,27 @@ ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path, return SBOX_ERROR_BAD_PARAMS; // Even though the resources touched by SpawnTarget can be accessed in - // multiple threads, the method itself cannot be called from more than - // 1 thread. This is to protect the global variables used while setting up - // the child process. + // multiple threads, the method itself cannot be called from more than one + // thread. This is to protect the global variables used while setting up the + // child process, and to make sure launcher thread mitigations are applied + // correctly. static DWORD thread_id = ::GetCurrentThreadId(); DCHECK(thread_id == ::GetCurrentThreadId()); *last_warning = SBOX_ALL_OK; AutoLock lock(&lock_); + // Launcher thread only needs to be opted out of ACG once. Do this on the + // first child process being spawned. + static bool launcher_thread_opted_out = false; + + if (!launcher_thread_opted_out) { + // Soft fail this call. It will fail if ACG is not enabled for this process. + sandbox::ApplyMitigationsToCurrentThread( + sandbox::MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD); + launcher_thread_opted_out = true; + } + // This downcast is safe as long as we control CreatePolicy() scoped_refptr<PolicyBase> policy_base(static_cast<PolicyBase*>(policy.get())); @@ -518,9 +530,4 @@ ResultCode BrokerServicesBase::WaitForAllTargets() { return SBOX_ALL_OK; } -bool BrokerServicesBase::IsActiveTarget(DWORD process_id) { - AutoLock lock(&lock_); - return child_process_ids_.find(process_id) != child_process_ids_.end(); -} - } // namespace sandbox diff --git a/chromium/sandbox/win/src/broker_services.h b/chromium/sandbox/win/src/broker_services.h index 14cfed5f947..701d29a40d1 100644 --- a/chromium/sandbox/win/src/broker_services.h +++ b/chromium/sandbox/win/src/broker_services.h @@ -55,12 +55,6 @@ class BrokerServicesBase final : public BrokerServices, PROCESS_INFORMATION* target) override; ResultCode WaitForAllTargets() override; - // Checks if the supplied process ID matches one of the broker's active - // target processes - // Returns: - // true if there is an active target process for this ID, otherwise false. - bool IsActiveTarget(DWORD process_id); - private: // The routine that the worker thread executes. It is in charge of // notifications and cleanup-related tasks. @@ -88,8 +82,7 @@ class BrokerServicesBase final : public BrokerServices, std::list<std::unique_ptr<JobTracker>> tracker_list_; // Provides a fast lookup to identify sandboxed processes that belong to a - // job. Consult |jobless_process_handles_| for handles of processes without - // jobs. + // job. std::set<DWORD> child_process_ids_; DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase); diff --git a/chromium/sandbox/win/src/process_mitigations.cc b/chromium/sandbox/win/src/process_mitigations.cc index 08a9c894855..e4c6838f96f 100644 --- a/chromium/sandbox/win/src/process_mitigations.cc +++ b/chromium/sandbox/win/src/process_mitigations.cc @@ -20,8 +20,6 @@ #include "sandbox/win/src/win_utils.h" namespace { -// API defined in winbase.h >= Vista. -using SetProcessDEPPolicyFunction = decltype(&SetProcessDEPPolicy); // API defined in libloaderapi.h >= Win8. using SetDefaultDllDirectoriesFunction = decltype(&SetDefaultDllDirectories); @@ -145,16 +143,10 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) { if (flags & MITIGATION_DEP_NO_ATL_THUNK) dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION; - SetProcessDEPPolicyFunction set_process_dep_policy = - reinterpret_cast<SetProcessDEPPolicyFunction>( - ::GetProcAddress(module, "SetProcessDEPPolicy")); - if (set_process_dep_policy) { - if (!set_process_dep_policy(dep_flags) && - ERROR_ACCESS_DENIED != ::GetLastError()) { - return false; - } - } else + if (!::SetProcessDEPPolicy(dep_flags) && + ERROR_ACCESS_DENIED != ::GetLastError()) { return false; + } } #endif @@ -225,17 +217,13 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) { // Enable dynamic code policies. if (!IsRunning32bitEmulatedOnArm64() && - (flags & MITIGATION_DYNAMIC_CODE_DISABLE || - flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT)) { + (flags & MITIGATION_DYNAMIC_CODE_DISABLE)) { + // Verify caller is not accidentally setting both mutually exclusive + // policies. + DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT)); PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {}; policy.ProhibitDynamicCode = true; - // Per-thread opt-out is only supported on >= Anniversary. - if (version >= base::win::Version::WIN10_RS1 && - flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT) { - policy.AllowThreadOptOut = true; - } - if (!set_process_mitigation_policy(ProcessDynamicCodePolicy, &policy, sizeof(policy)) && ERROR_ACCESS_DENIED != ::GetLastError()) { @@ -299,6 +287,27 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) { } } + if (version < base::win::Version::WIN10_RS1) + return true; + + // Enable dynamic code policies. + // Per-thread opt-out is only supported on >= Anniversary (RS1). + if (!IsRunning32bitEmulatedOnArm64() && + (flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT)) { + // Verify caller is not accidentally setting both mutually exclusive + // policies. + DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE)); + PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {}; + policy.ProhibitDynamicCode = true; + policy.AllowThreadOptOut = true; + + if (!set_process_mitigation_policy(ProcessDynamicCodePolicy, &policy, + sizeof(policy)) && + ERROR_ACCESS_DENIED != ::GetLastError()) { + return false; + } + } + return true; } diff --git a/chromium/sandbox/win/src/process_mitigations_unittest.cc b/chromium/sandbox/win/src/process_mitigations_unittest.cc index 2062f39d4ee..81f96451882 100644 --- a/chromium/sandbox/win/src/process_mitigations_unittest.cc +++ b/chromium/sandbox/win/src/process_mitigations_unittest.cc @@ -229,7 +229,11 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { return SBOX_TEST_NOT_FOUND; } if (!policy.DisallowWin32kSystemCalls) - return SBOX_TEST_FAILED; + return SBOX_TEST_FIRST_ERROR; + + // Check if we can call a Win32k API. Fail if it succeeds. + if (::GetDC(nullptr)) + return SBOX_TEST_SECOND_ERROR; break; } @@ -825,9 +829,23 @@ TEST(ProcessMitigationsTest, CheckWin10MsSigned_Failure) { false /* add_directory_permission */); } +// ASAN doesn't initialize early enough for the intercepts in NtCreateSection to +// be able to use std::unique_ptr, so disable pre-launch CIG on ASAN builds. +#if !defined(ADDRESS_SANITIZER) +#define MAYBE_CheckWin10MsSignedWithIntercept_Success \ + CheckWin10MsSignedWithIntercept_Success +#define MAYBE_CheckWin10MsSigned_FailurePreSpawn \ + CheckWin10MsSigned_FailurePreSpawn +#else +#define MAYBE_CheckWin10MsSignedWithIntercept_Success \ + DISABLED_CheckWin10MsSignedWithIntercept_Success +#define MAYBE_CheckWin10MsSigned_FailurePreSpawn \ + DISABLED_CheckWin10MsSigned_FailurePreSpawn +#endif + // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS // mitigation allows the loading of an unsigned DLL if intercept in place. -TEST(ProcessMitigationsTest, CheckWin10MsSignedWithIntercept_Success) { +TEST(ProcessMitigationsTest, MAYBE_CheckWin10MsSignedWithIntercept_Success) { if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; @@ -854,7 +872,7 @@ TEST(ProcessMitigationsTest, CheckWin10MsSignedWithIntercept_Success) { // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS // mitigation pre-load prevents the loading of an unsigned DLL. -TEST(ProcessMitigationsTest, CheckWin10MsSigned_FailurePreSpawn) { +TEST(ProcessMitigationsTest, MAYBE_CheckWin10MsSigned_FailurePreSpawn) { if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; diff --git a/chromium/sandbox/win/src/restricted_token.cc b/chromium/sandbox/win/src/restricted_token.cc index b68ffd81767..eae0a45e2c2 100644 --- a/chromium/sandbox/win/src/restricted_token.cc +++ b/chromium/sandbox/win/src/restricted_token.cc @@ -15,27 +15,14 @@ namespace { -// Calls GetTokenInformation with the desired |info_class| and returns a buffer -// with the result. +// Wrapper for utility version to unwrap ScopedHandle. std::unique_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token, TOKEN_INFORMATION_CLASS info_class, DWORD* error) { - // Get the required buffer size. - DWORD size = 0; - ::GetTokenInformation(token.Get(), info_class, nullptr, 0, &size); - if (!size) { - *error = ::GetLastError(); + std::unique_ptr<BYTE[]> buffer; + *error = sandbox::GetTokenInformation(token.Get(), info_class, &buffer); + if (*error != ERROR_SUCCESS) return nullptr; - } - - std::unique_ptr<BYTE[]> buffer(new BYTE[size]); - if (!::GetTokenInformation(token.Get(), info_class, buffer.get(), size, - &size)) { - *error = ::GetLastError(); - return nullptr; - } - - *error = ERROR_SUCCESS; return buffer; } diff --git a/chromium/sandbox/win/src/restricted_token_test.cc b/chromium/sandbox/win/src/restricted_token_test.cc index a7ba21e47ca..ca7e78f624e 100644 --- a/chromium/sandbox/win/src/restricted_token_test.cc +++ b/chromium/sandbox/win/src/restricted_token_test.cc @@ -12,6 +12,7 @@ #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/sandbox_factory.h" #include "sandbox/win/src/target_services.h" +#include "sandbox/win/src/win_utils.h" #include "sandbox/win/tests/common/controller.h" #include "testing/gtest/include/gtest/gtest.h" @@ -61,6 +62,24 @@ SBOX_TESTS_COMMAND int RestrictedTokenTest_openprocess(int argc, return SBOX_TEST_DENIED; } +// Opens a the process token and checks if it's restricted. +SBOX_TESTS_COMMAND int RestrictedTokenTest_IsRestricted(int argc, + wchar_t** argv) { + HANDLE token_handle; + if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token_handle)) + return SBOX_TEST_FIRST_ERROR; + base::win::ScopedHandle token(token_handle); + + std::unique_ptr<BYTE[]> groups; + if (GetTokenInformation(token_handle, TokenRestrictedSids, &groups) != + ERROR_SUCCESS) { + return SBOX_TEST_SECOND_ERROR; + } + + auto* token_groups = reinterpret_cast<PTOKEN_GROUPS>(groups.get()); + return token_groups->GroupCount > 0 ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED; +} + TEST(RestrictedTokenTest, OpenLowPrivilegedProcess) { // Test limited privilege to renderer open. ASSERT_EQ(SBOX_TEST_SUCCEEDED, @@ -77,4 +96,14 @@ TEST(RestrictedTokenTest, OpenLowPrivilegedProcess) { RunOpenProcessTest(true, true, PROCESS_ALL_ACCESS)); } +TEST(RestrictedTokenTest, CheckNonAdminRestricted) { + TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_NON_ADMIN); + EXPECT_EQ(SBOX_TEST_FAILED, + runner.RunTest(L"RestrictedTokenTest_IsRestricted")); + TestRunner runner_restricted(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, + USER_RESTRICTED_NON_ADMIN); + EXPECT_EQ(SBOX_TEST_SUCCEEDED, + runner_restricted.RunTest(L"RestrictedTokenTest_IsRestricted")); +} + } // namespace sandbox diff --git a/chromium/sandbox/win/src/restricted_token_utils.cc b/chromium/sandbox/win/src/restricted_token_utils.cc index 4717b4ed3d0..53f86e07d87 100644 --- a/chromium/sandbox/win/src/restricted_token_utils.cc +++ b/chromium/sandbox/win/src/restricted_token_utils.cc @@ -92,6 +92,21 @@ DWORD CreateRestrictedToken(HANDLE effective_token, privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME); break; } + case USER_RESTRICTED_NON_ADMIN: { + sid_exceptions.push_back(WinBuiltinUsersSid); + sid_exceptions.push_back(WinWorldSid); + sid_exceptions.push_back(WinInteractiveSid); + sid_exceptions.push_back(WinAuthenticatedUserSid); + privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME); + restricted_token.AddRestrictingSid(WinBuiltinUsersSid); + restricted_token.AddRestrictingSid(WinWorldSid); + restricted_token.AddRestrictingSid(WinInteractiveSid); + restricted_token.AddRestrictingSid(WinAuthenticatedUserSid); + restricted_token.AddRestrictingSid(WinRestrictedCodeSid); + restricted_token.AddRestrictingSidCurrentUser(); + restricted_token.AddRestrictingSidLogonSession(); + break; + } case USER_INTERACTIVE: { sid_exceptions.push_back(WinBuiltinUsersSid); sid_exceptions.push_back(WinWorldSid); diff --git a/chromium/sandbox/win/src/sandbox_policy_base.cc b/chromium/sandbox/win/src/sandbox_policy_base.cc index a47151d6562..dc4375b3f36 100644 --- a/chromium/sandbox/win/src/sandbox_policy_base.cc +++ b/chromium/sandbox/win/src/sandbox_policy_base.cc @@ -305,7 +305,14 @@ ResultCode PolicyBase::SetLowBox(const wchar_t* sid) { } ResultCode PolicyBase::SetProcessMitigations(MitigationFlags flags) { - if (app_container_profile_ || !CanSetProcessMitigationsPreStartup(flags)) + // Prior to Win10 RS5 CreateProcess fails when AppContainer and mitigation + // flags are enabled. Return an error on downlevel platforms if trying to + // set new mitigations. + if (app_container_profile_ && + base::win::GetVersion() < base::win::Version::WIN10_RS5) { + return SBOX_ERROR_BAD_PARAMS; + } + if (!CanSetProcessMitigationsPreStartup(flags)) return SBOX_ERROR_BAD_PARAMS; mitigations_ = flags; return SBOX_ALL_OK; @@ -626,12 +633,19 @@ ResultCode PolicyBase::AddAppContainerProfile(const wchar_t* package_name, } if (!app_container_profile_) return SBOX_ERROR_CREATE_APPCONTAINER_PROFILE; + // A bug exists in CreateProcess where enabling an AppContainer profile and // passing a set of mitigation flags will generate ERROR_INVALID_PARAMETER. // Apply best efforts here and convert set mitigations to delayed mitigations. + // This bug looks to have been fixed in Win10 RS5, so exit early if possible. + if (base::win::GetVersion() >= base::win::Version::WIN10_RS5) + return SBOX_ALL_OK; + delayed_mitigations_ = mitigations_ & GetAllowedPostStartupProcessMitigations(); - DCHECK(delayed_mitigations_ == (mitigations_ & ~MITIGATION_SEHOP)); + DCHECK(delayed_mitigations_ == + (mitigations_ & ~(MITIGATION_SEHOP | + MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION))); mitigations_ = 0; return SBOX_ALL_OK; } diff --git a/chromium/sandbox/win/src/security_level.h b/chromium/sandbox/win/src/security_level.h index 1036b34a669..8aa3ba8cab2 100644 --- a/chromium/sandbox/win/src/security_level.h +++ b/chromium/sandbox/win/src/security_level.h @@ -58,6 +58,14 @@ enum IntegrityLevel { // | | Authent-users | | // | | User | | // ----------------------------|--------------|----------------|----------| +// USER_RESTRICTED_NON_ADMIN | Users | All except: | Traverse | +// | Everyone | Users | | +// | Interactive | Everyone | | +// | Local | Interactive | | +// | Authent-users| Local | | +// | User | Authent-users | | +// | | User | | +// ----------------------------|--------------|----------------|----------| // USER_NON_ADMIN | None | All except: | Traverse | // | | Users | | // | | Everyone | | @@ -86,6 +94,7 @@ enum TokenLevel { USER_RESTRICTED, USER_LIMITED, USER_INTERACTIVE, + USER_RESTRICTED_NON_ADMIN, USER_NON_ADMIN, USER_RESTRICTED_SAME_ACCESS, USER_UNPROTECTED, diff --git a/chromium/sandbox/win/src/sharedmem_ipc_client.cc b/chromium/sandbox/win/src/sharedmem_ipc_client.cc index 2f849be31a9..3ddea76350b 100644 --- a/chromium/sandbox/win/src/sharedmem_ipc_client.cc +++ b/chromium/sandbox/win/src/sharedmem_ipc_client.cc @@ -144,7 +144,7 @@ ResultCode SharedMemIPCClient::DoCall(CrossCallParams* params, } // The server has returned an answer, copy it and free the channel. - memcpy(answer, params->GetCallReturn(), sizeof(CrossCallReturn)); + memcpy_wrapper(answer, params->GetCallReturn(), sizeof(CrossCallReturn)); // Return the IPC state It can indicate that while the IPC has // completed some error in the Broker has caused to not return valid diff --git a/chromium/sandbox/win/src/signed_interception.cc b/chromium/sandbox/win/src/signed_interception.cc index c0715215487..d9b1bc86b1c 100644 --- a/chromium/sandbox/win/src/signed_interception.cc +++ b/chromium/sandbox/win/src/signed_interception.cc @@ -26,45 +26,46 @@ TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection, ULONG section_page_protection, ULONG allocation_attributes, HANDLE file_handle) { - NTSTATUS status = orig_CreateSection( - section_handle, desired_access, object_attributes, maximum_size, - section_page_protection, allocation_attributes, file_handle); - - // Only intercept calls that match a particular signature. - if (status != STATUS_INVALID_IMAGE_HASH) - return status; - if (desired_access != (SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | - SECTION_MAP_EXECUTE)) - return status; - if (object_attributes) - return status; - if (maximum_size) - return status; - if (section_page_protection != PAGE_EXECUTE) - return status; - if (allocation_attributes != SEC_IMAGE) - return status; - do { - if (!ValidParameter(section_handle, sizeof(HANDLE), WRITE)) + // The section only needs to have SECTION_MAP_EXECUTE, but the permissions + // vary depending on the OS. Windows 1903 and higher requests (SECTION_QUERY + // | SECTION_MAP_READ | SECTION_MAP_EXECUTE) while previous OS versions also + // request SECTION_MAP_WRITE. Just check for EXECUTE. + if (!(desired_access & SECTION_MAP_EXECUTE)) + break; + if (object_attributes) + break; + if (maximum_size) + break; + if (section_page_protection != PAGE_EXECUTE) + break; + if (allocation_attributes != SEC_IMAGE) break; + // IPC must be fully started. void* memory = GetGlobalIPCMemory(); if (!memory) break; + std::unique_ptr<wchar_t, NtAllocDeleter> path; + if (!NtGetPathFromHandle(file_handle, &path)) break; + const wchar_t* const_name = path.get(); CountedParameterSet<NameBased> params; params[NameBased::NAME] = ParamPickerMake(const_name); + // Check if this will be sent to the broker. if (!QueryBroker(IPC_NTCREATESECTION_TAG, params.GetBase())) break; + if (!ValidParameter(section_handle, sizeof(HANDLE), WRITE)) + break; + CrossCallReturn answer = {0}; - answer.nt_status = status; + answer.nt_status = STATUS_INVALID_IMAGE_HASH; SharedMemIPCClient ipc(memory); ResultCode code = CrossCall(ipc, IPC_NTCREATESECTION_TAG, file_handle, &answer); @@ -72,19 +73,21 @@ TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection, if (code != SBOX_ALL_OK) break; - status = answer.nt_status; - if (!NT_SUCCESS(answer.nt_status)) break; __try { *section_handle = answer.handle; + return answer.nt_status; } __except (EXCEPTION_EXECUTE_HANDLER) { break; } } while (false); - return status; + // Fall back to the original API in all failure cases. + return orig_CreateSection(section_handle, desired_access, object_attributes, + maximum_size, section_page_protection, + allocation_attributes, file_handle); } } // namespace sandbox diff --git a/chromium/sandbox/win/src/win_utils.cc b/chromium/sandbox/win/src/win_utils.cc index 2225c88f83e..4b80c6eda77 100644 --- a/chromium/sandbox/win/src/win_utils.cc +++ b/chromium/sandbox/win/src/win_utils.cc @@ -545,6 +545,26 @@ void* GetProcessBaseAddress(HANDLE process) { return base_address; } +DWORD GetTokenInformation(HANDLE token, + TOKEN_INFORMATION_CLASS info_class, + std::unique_ptr<BYTE[]>* buffer) { + // Get the required buffer size. + DWORD size = 0; + ::GetTokenInformation(token, info_class, nullptr, 0, &size); + if (!size) { + return ::GetLastError(); + } + + auto temp_buffer = std::make_unique<BYTE[]>(size); + if (!::GetTokenInformation(token, info_class, temp_buffer.get(), size, + &size)) { + return ::GetLastError(); + } + + *buffer = std::move(temp_buffer); + return ERROR_SUCCESS; +} + } // namespace sandbox void ResolveNTFunctionPtr(const char* name, void* ptr) { diff --git a/chromium/sandbox/win/src/win_utils.h b/chromium/sandbox/win/src/win_utils.h index fed7b4c3f35..28ab11b00a8 100644 --- a/chromium/sandbox/win/src/win_utils.h +++ b/chromium/sandbox/win/src/win_utils.h @@ -7,6 +7,7 @@ #include <stddef.h> #include <windows.h> +#include <memory> #include <string> #include "base/macros.h" @@ -141,6 +142,12 @@ DWORD GetLastErrorFromNtStatus(NTSTATUS status); // the base address. This should only be called on new, suspended processes. void* GetProcessBaseAddress(HANDLE process); +// Calls GetTokenInformation with the desired |info_class| and returns a +// |buffer| and the Win32 error code. +DWORD GetTokenInformation(HANDLE token, + TOKEN_INFORMATION_CLASS info_class, + std::unique_ptr<BYTE[]>* buffer); + } // namespace sandbox // Resolves a function name in NTDLL to a function pointer. The second parameter |