# HG changeset patch # User Bob Owen # Date 1549645620 0 # Fri Feb 08 17:07:00 2019 +0000 # Node ID fb5e7c1090a7ddfde22fd2fb5f8a957ccc61fa64 # Parent 5ef34aa8c8918649528048dd60907862a4355e29 Bug 1515088 Part 2: Set LoaderThreads to 1 in the RTL_USER_PROCESS_PARAMETERS structure on child process start-up. r=aklotz diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc --- a/sandbox/win/src/win_utils.cc +++ b/sandbox/win/src/win_utils.cc @@ -170,16 +170,50 @@ void* GetProcessBaseAddress(HANDLE proce &bytes_read) || (sizeof(magic) != bytes_read)) { return nullptr; } if (magic[0] != 'M' || magic[1] != 'Z') return nullptr; +#if defined(_M_ARM64) + // Windows 10 on ARM64 has multi-threaded DLL loading that does not work with + // the sandbox. (On x86 this gets disabled by hook detection code that was not + // ported to ARM64). This overwrites the LoaderThreads value in the process + // parameters part of the PEB, if it is set to the default of 0 (which + // actually means it defaults to 4 loading threads). This is an undocumented + // field so there is a, probably small, risk that it might change or move in + // the future. In order to slightly guard against that we only update if the + // value is currently 0. + auto processParameters = reinterpret_cast(peb.ProcessParameters); + const uint32_t loaderThreadsOffset = 0x40c; + uint32_t maxLoaderThreads = 0; + BOOL memoryRead = ::ReadProcessMemory( + process, processParameters + loaderThreadsOffset, &maxLoaderThreads, + sizeof(maxLoaderThreads), &bytes_read); + if (memoryRead && (sizeof(maxLoaderThreads) == bytes_read) && + (maxLoaderThreads == 0)) { + maxLoaderThreads = 1; + auto address = processParameters + loaderThreadsOffset; + auto length = sizeof(maxLoaderThreads); + + // First, remove the protection. + DWORD old_protection; + if (::VirtualProtectEx(process, address, length, PAGE_READWRITE, + &old_protection)) { + ::WriteProcessMemory(process, address, &maxLoaderThreads, length, NULL); + + // Attempt to restore the original protection. + ::VirtualProtectEx(process, address, length, old_protection, + &old_protection); + } + } +#endif + return base_address; } absl::optional GetCurrentProcessHandles() { DWORD handle_count; if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) return absl::nullopt;