summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium-shim/patches/after_update/arm64_set_LoaderThreads.patch
blob: 4d1817db17bd2f36c4ab6ae09f1f877217618a40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# HG changeset patch
# User Bob Owen <bobowencode@gmail.com>
# 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<uint8_t*>(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<BYTE[]>* 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,