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