1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sandbox/win/src/process_mitigations.h" 6 7 #include "base/win/windows_version.h" 8 #include "sandbox/win/src/nt_internals.h" 9 #include "sandbox/win/src/sandbox_utils.h" 10 #include "sandbox/win/src/win_utils.h" 11 12 namespace { 13 14 // Functions for enabling policies. 15 typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags); 16 17 typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)( 18 PROCESS_MITIGATION_POLICY mitigation_policy, 19 PVOID buffer, 20 SIZE_T length); 21 22 typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)( 23 DWORD DirectoryFlags); 24 25 } // namespace 26 27 namespace sandbox { 28 29 bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) { 30 if (!CanSetProcessMitigationsPostStartup(flags)) 31 return false; 32 33 // We can't apply anything before Win XP, so just return cleanly. 34 if (!IsXPSP2OrLater()) 35 return true; 36 37 base::win::Version version = base::win::GetVersion(); 38 HMODULE module = ::GetModuleHandleA("kernel32.dll"); 39 40 if (version >= base::win::VERSION_VISTA && 41 (flags & MITIGATION_DLL_SEARCH_ORDER)) { 42 SetDefaultDllDirectoriesFunction set_default_dll_directories = 43 reinterpret_cast<SetDefaultDllDirectoriesFunction>( 44 ::GetProcAddress(module, "SetDefaultDllDirectories")); 45 46 // Check for SetDefaultDllDirectories since it requires KB2533623. 47 if (set_default_dll_directories) { 48 if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) && 49 ERROR_ACCESS_DENIED != ::GetLastError()) { 50 return false; 51 } 52 } 53 } 54 55 // Set the heap to terminate on corruption 56 if (version >= base::win::VERSION_VISTA && 57 (flags & MITIGATION_HEAP_TERMINATE)) { 58 if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, 59 NULL, 0) && 60 ERROR_ACCESS_DENIED != ::GetLastError()) { 61 return false; 62 } 63 } 64 65 #if !defined(_WIN64) // DEP is always enabled on 64-bit. 66 if (flags & MITIGATION_DEP) { 67 DWORD dep_flags = PROCESS_DEP_ENABLE; 68 // DEP support is quirky on XP, so don't force a failure in that case. 69 const bool return_on_fail = version >= base::win::VERSION_VISTA; 70 71 if (flags & MITIGATION_DEP_NO_ATL_THUNK) 72 dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION; 73 74 SetProcessDEPPolicyFunction set_process_dep_policy = 75 reinterpret_cast<SetProcessDEPPolicyFunction>( 76 ::GetProcAddress(module, "SetProcessDEPPolicy")); 77 if (set_process_dep_policy) { 78 if (!set_process_dep_policy(dep_flags) && 79 ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) { 80 return false; 81 } 82 } else { 83 // We're on XP sp2, so use the less standard approach. 84 // For reference: http://www.uninformed.org/?v=2&a=4 85 const int MEM_EXECUTE_OPTION_ENABLE = 1; 86 const int MEM_EXECUTE_OPTION_DISABLE = 2; 87 const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4; 88 const int MEM_EXECUTE_OPTION_PERMANENT = 8; 89 90 NtSetInformationProcessFunction set_information_process = NULL; 91 ResolveNTFunctionPtr("NtSetInformationProcess", 92 &set_information_process); 93 if (!set_information_process) 94 return false; 95 ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT; 96 if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION)) 97 dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION; 98 if (!SUCCEEDED(set_information_process(GetCurrentProcess(), 99 ProcessExecuteFlags, 100 &dep, sizeof(dep))) && 101 ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) { 102 return false; 103 } 104 } 105 } 106 #endif 107 108 // This is all we can do in Win7 and below. 109 if (version < base::win::VERSION_WIN8) 110 return true; 111 112 SetProcessMitigationPolicyFunction set_process_mitigation_policy = 113 reinterpret_cast<SetProcessMitigationPolicyFunction>( 114 ::GetProcAddress(module, "SetProcessMitigationPolicy")); 115 if (!set_process_mitigation_policy) 116 return false; 117 118 // Enable ASLR policies. 119 if (flags & MITIGATION_RELOCATE_IMAGE) { 120 PROCESS_MITIGATION_ASLR_POLICY policy = { 0 }; 121 policy.EnableForceRelocateImages = true; 122 policy.DisallowStrippedImages = (flags & 123 MITIGATION_RELOCATE_IMAGE_REQUIRED) == 124 MITIGATION_RELOCATE_IMAGE_REQUIRED; 125 126 if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy, 127 sizeof(policy)) && 128 ERROR_ACCESS_DENIED != ::GetLastError()) { 129 return false; 130 } 131 } 132 133 // Enable strict handle policies. 134 if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { 135 PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 }; 136 policy.HandleExceptionsPermanentlyEnabled = 137 policy.RaiseExceptionOnInvalidHandleReference = true; 138 139 if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy, 140 sizeof(policy)) && 141 ERROR_ACCESS_DENIED != ::GetLastError()) { 142 return false; 143 } 144 } 145 146 // Enable system call policies. 147 if (flags & MITIGATION_WIN32K_DISABLE) { 148 PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 }; 149 policy.DisallowWin32kSystemCalls = true; 150 151 if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy, 152 sizeof(policy)) && 153 ERROR_ACCESS_DENIED != ::GetLastError()) { 154 return false; 155 } 156 } 157 158 // Enable system call policies. 159 if (flags & MITIGATION_EXTENSION_DLL_DISABLE) { 160 PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 }; 161 policy.DisableExtensionPoints = true; 162 163 if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy, 164 &policy, sizeof(policy)) && 165 ERROR_ACCESS_DENIED != ::GetLastError()) { 166 return false; 167 } 168 } 169 170 return true; 171 } 172 173 void ConvertProcessMitigationsToPolicy(MitigationFlags flags, 174 DWORD64* policy_flags, size_t* size) { 175 base::win::Version version = base::win::GetVersion(); 176 177 *policy_flags = 0; 178 #if defined(_WIN64) 179 *size = sizeof(*policy_flags); 180 #elif defined(_M_IX86) 181 // A 64-bit flags attribute is illegal on 32-bit Win 7 and below. 182 if (version < base::win::VERSION_WIN8) 183 *size = sizeof(DWORD); 184 else 185 *size = sizeof(*policy_flags); 186 #else 187 #error This platform is not supported. 188 #endif 189 190 // Nothing for Win XP or Vista. 191 if (version <= base::win::VERSION_VISTA) 192 return; 193 194 // DEP and SEHOP are not valid for 64-bit Windows 195 #if !defined(_WIN64) 196 if (flags & MITIGATION_DEP) { 197 *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE; 198 if (!(flags & MITIGATION_DEP_NO_ATL_THUNK)) 199 *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE; 200 } 201 202 if (flags & MITIGATION_SEHOP) 203 *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE; 204 #endif 205 206 // Win 7 207 if (version < base::win::VERSION_WIN8) 208 return; 209 210 if (flags & MITIGATION_RELOCATE_IMAGE) { 211 *policy_flags |= 212 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON; 213 if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) { 214 *policy_flags |= 215 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS; 216 } 217 } 218 219 if (flags & MITIGATION_HEAP_TERMINATE) { 220 *policy_flags |= 221 PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON; 222 } 223 224 if (flags & MITIGATION_BOTTOM_UP_ASLR) { 225 *policy_flags |= 226 PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON; 227 } 228 229 if (flags & MITIGATION_HIGH_ENTROPY_ASLR) { 230 *policy_flags |= 231 PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON; 232 } 233 234 if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { 235 *policy_flags |= 236 PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON; 237 } 238 239 if (flags & MITIGATION_WIN32K_DISABLE) { 240 *policy_flags |= 241 PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON; 242 } 243 244 if (flags & MITIGATION_EXTENSION_DLL_DISABLE) { 245 *policy_flags |= 246 PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON; 247 } 248 } 249 250 MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) { 251 // Anything prior to XP SP2. 252 if (!IsXPSP2OrLater()) 253 return 0; 254 255 base::win::Version version = base::win::GetVersion(); 256 257 // Windows XP SP2+. 258 if (version < base::win::VERSION_VISTA) { 259 return flags & (MITIGATION_DEP | 260 MITIGATION_DEP_NO_ATL_THUNK); 261 262 // Windows Vista 263 if (version < base::win::VERSION_WIN7) { 264 return flags & (MITIGATION_DEP | 265 MITIGATION_DEP_NO_ATL_THUNK | 266 MITIGATION_BOTTOM_UP_ASLR | 267 MITIGATION_DLL_SEARCH_ORDER | 268 MITIGATION_HEAP_TERMINATE); 269 } 270 271 // Windows 7 and Vista. 272 } else if (version < base::win::VERSION_WIN8) { 273 return flags & (MITIGATION_BOTTOM_UP_ASLR | 274 MITIGATION_DLL_SEARCH_ORDER | 275 MITIGATION_HEAP_TERMINATE); 276 } 277 278 // Windows 8 and above. 279 return flags & (MITIGATION_BOTTOM_UP_ASLR | 280 MITIGATION_DLL_SEARCH_ORDER); 281 } 282 283 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process, 284 MitigationFlags flags) { 285 // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows. 286 #if !defined(_WIN64) 287 if (flags & MITIGATION_BOTTOM_UP_ASLR) { 288 unsigned int limit; 289 rand_s(&limit); 290 char* ptr = 0; 291 const size_t kMask64k = 0xFFFF; 292 // Random range (512k-16.5mb) in 64k steps. 293 const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k); 294 while (ptr < end) { 295 MEMORY_BASIC_INFORMATION memory_info; 296 if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info))) 297 break; 298 size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k, 299 static_cast<SIZE_T>(end - ptr)); 300 if (ptr && memory_info.State == MEM_FREE) 301 ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS); 302 ptr += size; 303 } 304 } 305 #endif 306 307 return true; 308 } 309 310 bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) { 311 // All of these mitigations can be enabled after startup. 312 return !(flags & ~(MITIGATION_HEAP_TERMINATE | 313 MITIGATION_DEP | 314 MITIGATION_DEP_NO_ATL_THUNK | 315 MITIGATION_RELOCATE_IMAGE | 316 MITIGATION_RELOCATE_IMAGE_REQUIRED | 317 MITIGATION_BOTTOM_UP_ASLR | 318 MITIGATION_STRICT_HANDLE_CHECKS | 319 MITIGATION_WIN32K_DISABLE | 320 MITIGATION_EXTENSION_DLL_DISABLE | 321 MITIGATION_DLL_SEARCH_ORDER)); 322 } 323 324 bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) { 325 // These mitigations cannot be enabled prior to startup. 326 return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS | 327 MITIGATION_WIN32K_DISABLE | 328 MITIGATION_DLL_SEARCH_ORDER)); 329 } 330 331 } // namespace sandbox 332 333