# 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/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/sandbox/chromium/sandbox/win/src/win_utils.cc --- a/security/sandbox/chromium/sandbox/win/src/win_utils.cc +++ b/security/sandbox/chromium/sandbox/win/src/win_utils.cc @@ -456,20 +456,21 @@ bool GetNtPathFromWin32Path(const std::w bool rv = GetPathFromHandle(file, nt_path); ::CloseHandle(file); return rv; } bool WriteProtectedChildMemory(HANDLE child_process, void* address, const void* buffer, - size_t length) { + size_t length, + DWORD writeProtection) { // First, remove the protections. DWORD old_protection; - if (!::VirtualProtectEx(child_process, address, length, PAGE_WRITECOPY, + if (!::VirtualProtectEx(child_process, address, length, writeProtection, &old_protection)) return false; SIZE_T written; bool ok = ::WriteProcessMemory(child_process, address, buffer, length, &written) && (length == written); @@ -544,16 +545,40 @@ 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; + WriteProtectedChildMemory(process, processParameters + loaderThreadsOffset, + &maxLoaderThreads, sizeof(maxLoaderThreads), + PAGE_READWRITE); + } +#endif + return base_address; } DWORD GetTokenInformation(HANDLE token, TOKEN_INFORMATION_CLASS info_class, std::unique_ptr* buffer) { // Get the required buffer size. DWORD size = 0; diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.h b/security/sandbox/chromium/sandbox/win/src/win_utils.h --- a/security/sandbox/chromium/sandbox/win/src/win_utils.h +++ b/security/sandbox/chromium/sandbox/win/src/win_utils.h @@ -111,17 +111,18 @@ HKEY GetReservedKeyFromName(const std::w bool ResolveRegistryName(std::wstring name, std::wstring* resolved_name); // Writes |length| bytes from the provided |buffer| into the address space of // |child_process|, at the specified |address|, preserving the original write // protection attributes. Returns true on success. bool WriteProtectedChildMemory(HANDLE child_process, void* address, const void* buffer, - size_t length); + size_t length, + DWORD writeProtection = PAGE_WRITECOPY); // Allocates |buffer_bytes| in child (PAGE_READWRITE) and copies data // from |local_buffer| in this process into |child|. |remote_buffer| // contains the address in the chile. If a zero byte copy is // requested |true| is returned and no allocation or copying is // attempted. Returns false if allocation or copying fails. If // copying fails, the allocation will be reversed. bool CopyToChildMemory(HANDLE child,