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.
5 #include "sandbox/win/src/process_mitigations.h"
9 #include "base/win/windows_version.h"
10 #include "sandbox/win/src/nt_internals.h"
11 #include "sandbox/win/src/sandbox_utils.h"
12 #include "sandbox/win/src/win_utils.h"
16 // Functions for enabling policies.
17 typedef BOOL (WINAPI
*SetProcessDEPPolicyFunction
)(DWORD dwFlags
);
19 typedef BOOL (WINAPI
*SetProcessMitigationPolicyFunction
)(
20 PROCESS_MITIGATION_POLICY mitigation_policy
,
24 typedef BOOL (WINAPI
*SetDefaultDllDirectoriesFunction
)(
25 DWORD DirectoryFlags
);
31 bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags
) {
32 if (!CanSetProcessMitigationsPostStartup(flags
))
35 // We can't apply anything before Win XP, so just return cleanly.
36 if (!IsXPSP2OrLater())
39 base::win::Version version
= base::win::GetVersion();
40 HMODULE module
= ::GetModuleHandleA("kernel32.dll");
42 if (version
>= base::win::VERSION_VISTA
&&
43 (flags
& MITIGATION_DLL_SEARCH_ORDER
)) {
44 SetDefaultDllDirectoriesFunction set_default_dll_directories
=
45 reinterpret_cast<SetDefaultDllDirectoriesFunction
>(
46 ::GetProcAddress(module
, "SetDefaultDllDirectories"));
48 // Check for SetDefaultDllDirectories since it requires KB2533623.
49 if (set_default_dll_directories
) {
50 if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
) &&
51 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
57 // Set the heap to terminate on corruption
58 if (version
>= base::win::VERSION_VISTA
&&
59 (flags
& MITIGATION_HEAP_TERMINATE
)) {
60 if (!::HeapSetInformation(NULL
, HeapEnableTerminationOnCorruption
,
62 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
67 #if !defined(_WIN64) // DEP is always enabled on 64-bit.
68 if (flags
& MITIGATION_DEP
) {
69 DWORD dep_flags
= PROCESS_DEP_ENABLE
;
70 // DEP support is quirky on XP, so don't force a failure in that case.
71 const bool return_on_fail
= version
>= base::win::VERSION_VISTA
;
73 if (flags
& MITIGATION_DEP_NO_ATL_THUNK
)
74 dep_flags
|= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
;
76 SetProcessDEPPolicyFunction set_process_dep_policy
=
77 reinterpret_cast<SetProcessDEPPolicyFunction
>(
78 ::GetProcAddress(module
, "SetProcessDEPPolicy"));
79 if (set_process_dep_policy
) {
80 if (!set_process_dep_policy(dep_flags
) &&
81 ERROR_ACCESS_DENIED
!= ::GetLastError() && return_on_fail
) {
85 // We're on XP sp2, so use the less standard approach.
86 // For reference: http://www.uninformed.org/?v=2&a=4
87 const int MEM_EXECUTE_OPTION_ENABLE
= 1;
88 const int MEM_EXECUTE_OPTION_DISABLE
= 2;
89 const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION
= 4;
90 const int MEM_EXECUTE_OPTION_PERMANENT
= 8;
92 NtSetInformationProcessFunction set_information_process
= NULL
;
93 ResolveNTFunctionPtr("NtSetInformationProcess",
94 &set_information_process
);
95 if (!set_information_process
)
97 ULONG dep
= MEM_EXECUTE_OPTION_DISABLE
| MEM_EXECUTE_OPTION_PERMANENT
;
98 if (!(dep_flags
& PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
))
99 dep
|= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION
;
100 if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
102 &dep
, sizeof(dep
))) &&
103 ERROR_ACCESS_DENIED
!= ::GetLastError() && return_on_fail
) {
110 // This is all we can do in Win7 and below.
111 if (version
< base::win::VERSION_WIN8
)
114 SetProcessMitigationPolicyFunction set_process_mitigation_policy
=
115 reinterpret_cast<SetProcessMitigationPolicyFunction
>(
116 ::GetProcAddress(module
, "SetProcessMitigationPolicy"));
117 if (!set_process_mitigation_policy
)
120 // Enable ASLR policies.
121 if (flags
& MITIGATION_RELOCATE_IMAGE
) {
122 PROCESS_MITIGATION_ASLR_POLICY policy
= { 0 };
123 policy
.EnableForceRelocateImages
= true;
124 policy
.DisallowStrippedImages
= (flags
&
125 MITIGATION_RELOCATE_IMAGE_REQUIRED
) ==
126 MITIGATION_RELOCATE_IMAGE_REQUIRED
;
128 if (!set_process_mitigation_policy(ProcessASLRPolicy
, &policy
,
130 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
135 // Enable strict handle policies.
136 if (flags
& MITIGATION_STRICT_HANDLE_CHECKS
) {
137 PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy
= { 0 };
138 policy
.HandleExceptionsPermanentlyEnabled
=
139 policy
.RaiseExceptionOnInvalidHandleReference
= true;
141 if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy
, &policy
,
143 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
148 // Enable system call policies.
149 if (flags
& MITIGATION_WIN32K_DISABLE
) {
150 PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy
= { 0 };
151 policy
.DisallowWin32kSystemCalls
= true;
153 if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy
, &policy
,
155 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
160 // Enable system call policies.
161 if (flags
& MITIGATION_EXTENSION_DLL_DISABLE
) {
162 PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy
= { 0 };
163 policy
.DisableExtensionPoints
= true;
165 if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy
,
166 &policy
, sizeof(policy
)) &&
167 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
175 void ConvertProcessMitigationsToPolicy(MitigationFlags flags
,
176 DWORD64
* policy_flags
, size_t* size
) {
177 base::win::Version version
= base::win::GetVersion();
181 *size
= sizeof(*policy_flags
);
182 #elif defined(_M_IX86)
183 // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
184 if (version
< base::win::VERSION_WIN8
)
185 *size
= sizeof(DWORD
);
187 *size
= sizeof(*policy_flags
);
189 #error This platform is not supported.
192 // Nothing for Win XP or Vista.
193 if (version
<= base::win::VERSION_VISTA
)
196 // DEP and SEHOP are not valid for 64-bit Windows
198 if (flags
& MITIGATION_DEP
) {
199 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE
;
200 if (!(flags
& MITIGATION_DEP_NO_ATL_THUNK
))
201 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE
;
204 if (flags
& MITIGATION_SEHOP
)
205 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE
;
209 if (version
< base::win::VERSION_WIN8
)
212 if (flags
& MITIGATION_RELOCATE_IMAGE
) {
214 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON
;
215 if (flags
& MITIGATION_RELOCATE_IMAGE_REQUIRED
) {
217 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS
;
221 if (flags
& MITIGATION_HEAP_TERMINATE
) {
223 PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON
;
226 if (flags
& MITIGATION_BOTTOM_UP_ASLR
) {
228 PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON
;
231 if (flags
& MITIGATION_HIGH_ENTROPY_ASLR
) {
233 PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON
;
236 if (flags
& MITIGATION_STRICT_HANDLE_CHECKS
) {
238 PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON
;
241 if (flags
& MITIGATION_WIN32K_DISABLE
) {
243 PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON
;
246 if (flags
& MITIGATION_EXTENSION_DLL_DISABLE
) {
248 PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON
;
252 MitigationFlags
FilterPostStartupProcessMitigations(MitigationFlags flags
) {
253 // Anything prior to XP SP2.
254 if (!IsXPSP2OrLater())
257 base::win::Version version
= base::win::GetVersion();
260 if (version
< base::win::VERSION_VISTA
) {
261 return flags
& (MITIGATION_DEP
|
262 MITIGATION_DEP_NO_ATL_THUNK
);
265 if (version
< base::win::VERSION_WIN7
) {
266 return flags
& (MITIGATION_DEP
|
267 MITIGATION_DEP_NO_ATL_THUNK
|
268 MITIGATION_BOTTOM_UP_ASLR
|
269 MITIGATION_DLL_SEARCH_ORDER
|
270 MITIGATION_HEAP_TERMINATE
);
273 // Windows 7 and Vista.
274 } else if (version
< base::win::VERSION_WIN8
) {
275 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
276 MITIGATION_DLL_SEARCH_ORDER
|
277 MITIGATION_HEAP_TERMINATE
);
280 // Windows 8 and above.
281 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
282 MITIGATION_DLL_SEARCH_ORDER
);
285 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process
,
286 MitigationFlags flags
) {
287 // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
289 if (flags
& MITIGATION_BOTTOM_UP_ASLR
) {
293 const size_t kMask64k
= 0xFFFF;
294 // Random range (512k-16.5mb) in 64k steps.
295 const char* end
= ptr
+ ((((limit
% 16384) + 512) * 1024) & ~kMask64k
);
297 MEMORY_BASIC_INFORMATION memory_info
;
298 if (!::VirtualQueryEx(process
, ptr
, &memory_info
, sizeof(memory_info
)))
300 size_t size
= std::min((memory_info
.RegionSize
+ kMask64k
) & ~kMask64k
,
301 static_cast<SIZE_T
>(end
- ptr
));
302 if (ptr
&& memory_info
.State
== MEM_FREE
)
303 ::VirtualAllocEx(process
, ptr
, size
, MEM_RESERVE
, PAGE_NOACCESS
);
312 bool CanSetProcessMitigationsPostStartup(MitigationFlags flags
) {
313 // All of these mitigations can be enabled after startup.
314 return !(flags
& ~(MITIGATION_HEAP_TERMINATE
|
316 MITIGATION_DEP_NO_ATL_THUNK
|
317 MITIGATION_RELOCATE_IMAGE
|
318 MITIGATION_RELOCATE_IMAGE_REQUIRED
|
319 MITIGATION_BOTTOM_UP_ASLR
|
320 MITIGATION_STRICT_HANDLE_CHECKS
|
321 MITIGATION_WIN32K_DISABLE
|
322 MITIGATION_EXTENSION_DLL_DISABLE
|
323 MITIGATION_DLL_SEARCH_ORDER
));
326 bool CanSetProcessMitigationsPreStartup(MitigationFlags flags
) {
327 // These mitigations cannot be enabled prior to startup.
328 return !(flags
& (MITIGATION_STRICT_HANDLE_CHECKS
|
329 MITIGATION_WIN32K_DISABLE
|
330 MITIGATION_DLL_SEARCH_ORDER
));
333 } // namespace sandbox