SandboxInitialization.cpp (7331B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "SandboxInitialization.h" 8 9 #include "base/memory/ref_counted.h" 10 #include "nsWindowsDllInterceptor.h" 11 #include "sandbox/win/src/process_mitigations.h" 12 #include "sandbox/win/src/sandbox_factory.h" 13 #include "mozilla/DebugOnly.h" 14 #include "mozilla/WindowsProcessMitigations.h" 15 16 namespace mozilla { 17 namespace sandboxing { 18 19 typedef BOOL(WINAPI* CloseHandle_func)(HANDLE hObject); 20 static WindowsDllInterceptor::FuncHookType<CloseHandle_func> stub_CloseHandle; 21 22 typedef BOOL(WINAPI* DuplicateHandle_func)( 23 HANDLE hSourceProcessHandle, HANDLE hSourceHandle, 24 HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, 25 BOOL bInheritHandle, DWORD dwOptions); 26 static WindowsDllInterceptor::FuncHookType<DuplicateHandle_func> 27 stub_DuplicateHandle; 28 29 static BOOL WINAPI patched_CloseHandle(HANDLE hObject) { 30 // Check all handles being closed against the sandbox's tracked handles. 31 base::win::OnHandleBeingClosed(hObject, 32 base::win::HandleOperation::kCloseHandleHook); 33 return stub_CloseHandle(hObject); 34 } 35 36 static BOOL WINAPI patched_DuplicateHandle( 37 HANDLE hSourceProcessHandle, HANDLE hSourceHandle, 38 HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, 39 BOOL bInheritHandle, DWORD dwOptions) { 40 // If closing a source handle from our process check it against the sandbox's 41 // tracked handles. 42 if ((dwOptions & DUPLICATE_CLOSE_SOURCE) && 43 (GetProcessId(hSourceProcessHandle) == ::GetCurrentProcessId())) { 44 base::win::OnHandleBeingClosed( 45 hSourceHandle, base::win::HandleOperation::kDuplicateHandleHook); 46 } 47 48 return stub_DuplicateHandle(hSourceProcessHandle, hSourceHandle, 49 hTargetProcessHandle, lpTargetHandle, 50 dwDesiredAccess, bInheritHandle, dwOptions); 51 } 52 53 typedef BOOL(WINAPI* ApiSetQueryApiSetPresence_func)(PCUNICODE_STRING, 54 PBOOLEAN); 55 static WindowsDllInterceptor::FuncHookType<ApiSetQueryApiSetPresence_func> 56 stub_ApiSetQueryApiSetPresence; 57 58 static const WCHAR gApiSetNtUserWindowStation[] = 59 L"ext-ms-win-ntuser-windowstation-l1-1-0"; 60 61 static BOOL WINAPI patched_ApiSetQueryApiSetPresence( 62 PCUNICODE_STRING aNamespace, PBOOLEAN aPresent) { 63 if (aNamespace && aPresent && 64 !wcsncmp(aNamespace->Buffer, gApiSetNtUserWindowStation, 65 aNamespace->Length / sizeof(WCHAR))) { 66 *aPresent = FALSE; 67 return TRUE; 68 } 69 70 return stub_ApiSetQueryApiSetPresence(aNamespace, aPresent); 71 } 72 73 MOZ_RUNINIT static WindowsDllInterceptor Kernel32Intercept; 74 MOZ_RUNINIT static WindowsDllInterceptor gApiQueryIntercept; 75 76 static bool EnableHandleCloseMonitoring() { 77 Kernel32Intercept.Init("kernel32.dll"); 78 bool hooked = stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle", 79 &patched_CloseHandle); 80 if (!hooked) { 81 return false; 82 } 83 84 hooked = stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle", 85 &patched_DuplicateHandle); 86 if (!hooked) { 87 return false; 88 } 89 90 return true; 91 } 92 93 /** 94 * There is a bug in COM that causes its initialization to fail when user32.dll 95 * is loaded but Win32k lockdown is enabled. COM uses ApiSetQueryApiSetPresence 96 * to make this check. When we are under Win32k lockdown, we hook 97 * ApiSetQueryApiSetPresence and force it to tell the caller that the DLL of 98 * interest is not present. 99 */ 100 static void EnableApiQueryInterception() { 101 if (!IsWin32kLockedDown()) { 102 return; 103 } 104 105 gApiQueryIntercept.Init(L"Api-ms-win-core-apiquery-l1-1-0.dll"); 106 DebugOnly<bool> hookSetOk = stub_ApiSetQueryApiSetPresence.Set( 107 gApiQueryIntercept, "ApiSetQueryApiSetPresence", 108 &patched_ApiSetQueryApiSetPresence); 109 MOZ_ASSERT(hookSetOk); 110 } 111 112 static bool ShouldDisableHandleVerifier() { 113 #if defined(_X86_) && (defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)) 114 // Chromium only has the verifier enabled for 32-bit and our close monitoring 115 // hooks cause debug assertions for 64-bit anyway. 116 // For x86 keep the verifier enabled by default only for Nightly or debug. 117 // The handle verifier uses thread local storage, which at least one gtest 118 // manipulates causing it to crash, so we have to disable. 119 return !!getenv("MOZ_RUN_GTEST"); 120 #else 121 return !getenv("MOZ_ENABLE_HANDLE_VERIFIER"); 122 #endif 123 } 124 125 static void InitializeHandleVerifier() { 126 // Disable the handle verifier if we don't want it or can't enable the close 127 // monitoring hooks. 128 if (ShouldDisableHandleVerifier() || !EnableHandleCloseMonitoring()) { 129 base::win::DisableHandleVerifier(); 130 } 131 } 132 133 static sandbox::TargetServices* InitializeTargetServices() { 134 // This might disable the verifier, so we want to do it before it is used. 135 InitializeHandleVerifier(); 136 137 EnableApiQueryInterception(); 138 139 sandbox::TargetServices* targetServices = 140 sandbox::SandboxFactory::GetTargetServices(); 141 if (!targetServices) { 142 return nullptr; 143 } 144 145 if (targetServices->Init() != sandbox::SBOX_ALL_OK) { 146 return nullptr; 147 } 148 149 return targetServices; 150 } 151 152 sandbox::TargetServices* GetInitializedTargetServices() { 153 static sandbox::TargetServices* sInitializedTargetServices = 154 InitializeTargetServices(); 155 156 return sInitializedTargetServices; 157 } 158 159 void LowerSandbox() { GetInitializedTargetServices()->LowerToken(); } 160 161 static sandbox::BrokerServices* InitializeBrokerServices() { 162 // This might disable the verifier, so we want to do it before it is used. 163 InitializeHandleVerifier(); 164 165 sandbox::BrokerServices* brokerServices = 166 sandbox::SandboxFactory::GetBrokerServices(); 167 if (!brokerServices) { 168 return nullptr; 169 } 170 171 if (brokerServices->Init() != sandbox::SBOX_ALL_OK) { 172 return nullptr; 173 } 174 175 // Comment below copied from Chromium code. 176 // Precreate the desktop and window station used by the renderers. 177 // IMPORTANT: This piece of code needs to run as early as possible in the 178 // process because it will initialize the sandbox broker, which requires 179 // the process to swap its window station. During this time all the UI 180 // will be broken. This has to run before threads and windows are created. 181 (void)brokerServices->CreateAlternateDesktop( 182 sandbox::Desktop::kAlternateWinstation); 183 184 // Ensure the relevant mitigations are enforced. 185 mozilla::sandboxing::ApplyParentProcessMitigations(); 186 187 return brokerServices; 188 } 189 190 sandbox::BrokerServices* GetInitializedBrokerServices() { 191 static sandbox::BrokerServices* sInitializedBrokerServices = 192 InitializeBrokerServices(); 193 194 return sInitializedBrokerServices; 195 } 196 197 void ApplyParentProcessMitigations() { 198 // The main reason for this call is for the token hardening, but chromium code 199 // also ensures DEP without ATL thunk so we do the same. 200 sandbox::RatchetDownSecurityMitigations( 201 sandbox::MITIGATION_DEP | sandbox::MITIGATION_DEP_NO_ATL_THUNK | 202 sandbox::MITIGATION_HARDEN_TOKEN_IL_POLICY); 203 } 204 205 } // namespace sandboxing 206 } // namespace mozilla