1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/process_mitigations.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,334 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/process_mitigations.h" 1.9 + 1.10 +#include <algorithm> 1.11 + 1.12 +#include "base/win/windows_version.h" 1.13 +#include "sandbox/win/src/nt_internals.h" 1.14 +#include "sandbox/win/src/sandbox_utils.h" 1.15 +#include "sandbox/win/src/win_utils.h" 1.16 + 1.17 +namespace { 1.18 + 1.19 +// Functions for enabling policies. 1.20 +typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags); 1.21 + 1.22 +typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)( 1.23 + PROCESS_MITIGATION_POLICY mitigation_policy, 1.24 + PVOID buffer, 1.25 + SIZE_T length); 1.26 + 1.27 +typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)( 1.28 + DWORD DirectoryFlags); 1.29 + 1.30 +} // namespace 1.31 + 1.32 +namespace sandbox { 1.33 + 1.34 +bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) { 1.35 + if (!CanSetProcessMitigationsPostStartup(flags)) 1.36 + return false; 1.37 + 1.38 + // We can't apply anything before Win XP, so just return cleanly. 1.39 + if (!IsXPSP2OrLater()) 1.40 + return true; 1.41 + 1.42 + base::win::Version version = base::win::GetVersion(); 1.43 + HMODULE module = ::GetModuleHandleA("kernel32.dll"); 1.44 + 1.45 + if (version >= base::win::VERSION_VISTA && 1.46 + (flags & MITIGATION_DLL_SEARCH_ORDER)) { 1.47 + SetDefaultDllDirectoriesFunction set_default_dll_directories = 1.48 + reinterpret_cast<SetDefaultDllDirectoriesFunction>( 1.49 + ::GetProcAddress(module, "SetDefaultDllDirectories")); 1.50 + 1.51 + // Check for SetDefaultDllDirectories since it requires KB2533623. 1.52 + if (set_default_dll_directories) { 1.53 + if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) && 1.54 + ERROR_ACCESS_DENIED != ::GetLastError()) { 1.55 + return false; 1.56 + } 1.57 + } 1.58 + } 1.59 + 1.60 + // Set the heap to terminate on corruption 1.61 + if (version >= base::win::VERSION_VISTA && 1.62 + (flags & MITIGATION_HEAP_TERMINATE)) { 1.63 + if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, 1.64 + NULL, 0) && 1.65 + ERROR_ACCESS_DENIED != ::GetLastError()) { 1.66 + return false; 1.67 + } 1.68 + } 1.69 + 1.70 +#if !defined(_WIN64) // DEP is always enabled on 64-bit. 1.71 + if (flags & MITIGATION_DEP) { 1.72 + DWORD dep_flags = PROCESS_DEP_ENABLE; 1.73 + // DEP support is quirky on XP, so don't force a failure in that case. 1.74 + const bool return_on_fail = version >= base::win::VERSION_VISTA; 1.75 + 1.76 + if (flags & MITIGATION_DEP_NO_ATL_THUNK) 1.77 + dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION; 1.78 + 1.79 + SetProcessDEPPolicyFunction set_process_dep_policy = 1.80 + reinterpret_cast<SetProcessDEPPolicyFunction>( 1.81 + ::GetProcAddress(module, "SetProcessDEPPolicy")); 1.82 + if (set_process_dep_policy) { 1.83 + if (!set_process_dep_policy(dep_flags) && 1.84 + ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) { 1.85 + return false; 1.86 + } 1.87 + } else { 1.88 + // We're on XP sp2, so use the less standard approach. 1.89 + // For reference: http://www.uninformed.org/?v=2&a=4 1.90 + const int MEM_EXECUTE_OPTION_ENABLE = 1; 1.91 + const int MEM_EXECUTE_OPTION_DISABLE = 2; 1.92 + const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4; 1.93 + const int MEM_EXECUTE_OPTION_PERMANENT = 8; 1.94 + 1.95 + NtSetInformationProcessFunction set_information_process = NULL; 1.96 + ResolveNTFunctionPtr("NtSetInformationProcess", 1.97 + &set_information_process); 1.98 + if (!set_information_process) 1.99 + return false; 1.100 + ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT; 1.101 + if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION)) 1.102 + dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION; 1.103 + if (!SUCCEEDED(set_information_process(GetCurrentProcess(), 1.104 + ProcessExecuteFlags, 1.105 + &dep, sizeof(dep))) && 1.106 + ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) { 1.107 + return false; 1.108 + } 1.109 + } 1.110 + } 1.111 +#endif 1.112 + 1.113 + // This is all we can do in Win7 and below. 1.114 + if (version < base::win::VERSION_WIN8) 1.115 + return true; 1.116 + 1.117 + SetProcessMitigationPolicyFunction set_process_mitigation_policy = 1.118 + reinterpret_cast<SetProcessMitigationPolicyFunction>( 1.119 + ::GetProcAddress(module, "SetProcessMitigationPolicy")); 1.120 + if (!set_process_mitigation_policy) 1.121 + return false; 1.122 + 1.123 + // Enable ASLR policies. 1.124 + if (flags & MITIGATION_RELOCATE_IMAGE) { 1.125 + PROCESS_MITIGATION_ASLR_POLICY policy = { 0 }; 1.126 + policy.EnableForceRelocateImages = true; 1.127 + policy.DisallowStrippedImages = (flags & 1.128 + MITIGATION_RELOCATE_IMAGE_REQUIRED) == 1.129 + MITIGATION_RELOCATE_IMAGE_REQUIRED; 1.130 + 1.131 + if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy, 1.132 + sizeof(policy)) && 1.133 + ERROR_ACCESS_DENIED != ::GetLastError()) { 1.134 + return false; 1.135 + } 1.136 + } 1.137 + 1.138 + // Enable strict handle policies. 1.139 + if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { 1.140 + PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 }; 1.141 + policy.HandleExceptionsPermanentlyEnabled = 1.142 + policy.RaiseExceptionOnInvalidHandleReference = true; 1.143 + 1.144 + if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy, 1.145 + sizeof(policy)) && 1.146 + ERROR_ACCESS_DENIED != ::GetLastError()) { 1.147 + return false; 1.148 + } 1.149 + } 1.150 + 1.151 + // Enable system call policies. 1.152 + if (flags & MITIGATION_WIN32K_DISABLE) { 1.153 + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 }; 1.154 + policy.DisallowWin32kSystemCalls = true; 1.155 + 1.156 + if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy, 1.157 + sizeof(policy)) && 1.158 + ERROR_ACCESS_DENIED != ::GetLastError()) { 1.159 + return false; 1.160 + } 1.161 + } 1.162 + 1.163 + // Enable system call policies. 1.164 + if (flags & MITIGATION_EXTENSION_DLL_DISABLE) { 1.165 + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 }; 1.166 + policy.DisableExtensionPoints = true; 1.167 + 1.168 + if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy, 1.169 + &policy, sizeof(policy)) && 1.170 + ERROR_ACCESS_DENIED != ::GetLastError()) { 1.171 + return false; 1.172 + } 1.173 + } 1.174 + 1.175 + return true; 1.176 +} 1.177 + 1.178 +void ConvertProcessMitigationsToPolicy(MitigationFlags flags, 1.179 + DWORD64* policy_flags, size_t* size) { 1.180 + base::win::Version version = base::win::GetVersion(); 1.181 + 1.182 + *policy_flags = 0; 1.183 +#if defined(_WIN64) 1.184 + *size = sizeof(*policy_flags); 1.185 +#elif defined(_M_IX86) 1.186 + // A 64-bit flags attribute is illegal on 32-bit Win 7 and below. 1.187 + if (version < base::win::VERSION_WIN8) 1.188 + *size = sizeof(DWORD); 1.189 + else 1.190 + *size = sizeof(*policy_flags); 1.191 +#else 1.192 +#error This platform is not supported. 1.193 +#endif 1.194 + 1.195 + // Nothing for Win XP or Vista. 1.196 + if (version <= base::win::VERSION_VISTA) 1.197 + return; 1.198 + 1.199 + // DEP and SEHOP are not valid for 64-bit Windows 1.200 +#if !defined(_WIN64) 1.201 + if (flags & MITIGATION_DEP) { 1.202 + *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE; 1.203 + if (!(flags & MITIGATION_DEP_NO_ATL_THUNK)) 1.204 + *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE; 1.205 + } 1.206 + 1.207 + if (flags & MITIGATION_SEHOP) 1.208 + *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE; 1.209 +#endif 1.210 + 1.211 + // Win 7 1.212 + if (version < base::win::VERSION_WIN8) 1.213 + return; 1.214 + 1.215 + if (flags & MITIGATION_RELOCATE_IMAGE) { 1.216 + *policy_flags |= 1.217 + PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON; 1.218 + if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) { 1.219 + *policy_flags |= 1.220 + PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS; 1.221 + } 1.222 + } 1.223 + 1.224 + if (flags & MITIGATION_HEAP_TERMINATE) { 1.225 + *policy_flags |= 1.226 + PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON; 1.227 + } 1.228 + 1.229 + if (flags & MITIGATION_BOTTOM_UP_ASLR) { 1.230 + *policy_flags |= 1.231 + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON; 1.232 + } 1.233 + 1.234 + if (flags & MITIGATION_HIGH_ENTROPY_ASLR) { 1.235 + *policy_flags |= 1.236 + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON; 1.237 + } 1.238 + 1.239 + if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { 1.240 + *policy_flags |= 1.241 + PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON; 1.242 + } 1.243 + 1.244 + if (flags & MITIGATION_WIN32K_DISABLE) { 1.245 + *policy_flags |= 1.246 + PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON; 1.247 + } 1.248 + 1.249 + if (flags & MITIGATION_EXTENSION_DLL_DISABLE) { 1.250 + *policy_flags |= 1.251 + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON; 1.252 + } 1.253 +} 1.254 + 1.255 +MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) { 1.256 + // Anything prior to XP SP2. 1.257 + if (!IsXPSP2OrLater()) 1.258 + return 0; 1.259 + 1.260 + base::win::Version version = base::win::GetVersion(); 1.261 + 1.262 + // Windows XP SP2+. 1.263 + if (version < base::win::VERSION_VISTA) { 1.264 + return flags & (MITIGATION_DEP | 1.265 + MITIGATION_DEP_NO_ATL_THUNK); 1.266 + 1.267 + // Windows Vista 1.268 + if (version < base::win::VERSION_WIN7) { 1.269 + return flags & (MITIGATION_DEP | 1.270 + MITIGATION_DEP_NO_ATL_THUNK | 1.271 + MITIGATION_BOTTOM_UP_ASLR | 1.272 + MITIGATION_DLL_SEARCH_ORDER | 1.273 + MITIGATION_HEAP_TERMINATE); 1.274 + } 1.275 + 1.276 + // Windows 7 and Vista. 1.277 + } else if (version < base::win::VERSION_WIN8) { 1.278 + return flags & (MITIGATION_BOTTOM_UP_ASLR | 1.279 + MITIGATION_DLL_SEARCH_ORDER | 1.280 + MITIGATION_HEAP_TERMINATE); 1.281 + } 1.282 + 1.283 + // Windows 8 and above. 1.284 + return flags & (MITIGATION_BOTTOM_UP_ASLR | 1.285 + MITIGATION_DLL_SEARCH_ORDER); 1.286 +} 1.287 + 1.288 +bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process, 1.289 + MitigationFlags flags) { 1.290 +// This is a hack to fake a weak bottom-up ASLR on 32-bit Windows. 1.291 +#if !defined(_WIN64) 1.292 + if (flags & MITIGATION_BOTTOM_UP_ASLR) { 1.293 + unsigned int limit; 1.294 + rand_s(&limit); 1.295 + char* ptr = 0; 1.296 + const size_t kMask64k = 0xFFFF; 1.297 + // Random range (512k-16.5mb) in 64k steps. 1.298 + const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k); 1.299 + while (ptr < end) { 1.300 + MEMORY_BASIC_INFORMATION memory_info; 1.301 + if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info))) 1.302 + break; 1.303 + size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k, 1.304 + static_cast<SIZE_T>(end - ptr)); 1.305 + if (ptr && memory_info.State == MEM_FREE) 1.306 + ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS); 1.307 + ptr += size; 1.308 + } 1.309 + } 1.310 +#endif 1.311 + 1.312 + return true; 1.313 +} 1.314 + 1.315 +bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) { 1.316 + // All of these mitigations can be enabled after startup. 1.317 + return !(flags & ~(MITIGATION_HEAP_TERMINATE | 1.318 + MITIGATION_DEP | 1.319 + MITIGATION_DEP_NO_ATL_THUNK | 1.320 + MITIGATION_RELOCATE_IMAGE | 1.321 + MITIGATION_RELOCATE_IMAGE_REQUIRED | 1.322 + MITIGATION_BOTTOM_UP_ASLR | 1.323 + MITIGATION_STRICT_HANDLE_CHECKS | 1.324 + MITIGATION_WIN32K_DISABLE | 1.325 + MITIGATION_EXTENSION_DLL_DISABLE | 1.326 + MITIGATION_DLL_SEARCH_ORDER)); 1.327 +} 1.328 + 1.329 +bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) { 1.330 + // These mitigations cannot be enabled prior to startup. 1.331 + return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS | 1.332 + MITIGATION_WIN32K_DISABLE | 1.333 + MITIGATION_DLL_SEARCH_ORDER)); 1.334 +} 1.335 + 1.336 +} // namespace sandbox 1.337 +