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/restricted_token_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 base::win::Version version
= base::win::GetVersion();
36 HMODULE module
= ::GetModuleHandleA("kernel32.dll");
38 if (version
>= base::win::VERSION_VISTA
&&
39 (flags
& MITIGATION_DLL_SEARCH_ORDER
)) {
40 SetDefaultDllDirectoriesFunction set_default_dll_directories
=
41 reinterpret_cast<SetDefaultDllDirectoriesFunction
>(
42 ::GetProcAddress(module
, "SetDefaultDllDirectories"));
44 // Check for SetDefaultDllDirectories since it requires KB2533623.
45 if (set_default_dll_directories
) {
46 if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
) &&
47 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
53 // Set the heap to terminate on corruption
54 if (version
>= base::win::VERSION_VISTA
&&
55 (flags
& MITIGATION_HEAP_TERMINATE
)) {
56 if (!::HeapSetInformation(NULL
, HeapEnableTerminationOnCorruption
,
58 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
63 if (version
>= base::win::VERSION_WIN7
&&
64 (flags
& MITIGATION_HARDEN_TOKEN_IL_POLICY
)) {
65 DWORD error
= HardenProcessIntegrityLevelPolicy();
66 if ((error
!= ERROR_SUCCESS
) && (error
!= ERROR_ACCESS_DENIED
))
70 #if !defined(_WIN64) // DEP is always enabled on 64-bit.
71 if (flags
& MITIGATION_DEP
) {
72 DWORD dep_flags
= PROCESS_DEP_ENABLE
;
73 // DEP support is quirky on XP, so don't force a failure in that case.
74 const bool return_on_fail
= version
>= base::win::VERSION_VISTA
;
76 if (flags
& MITIGATION_DEP_NO_ATL_THUNK
)
77 dep_flags
|= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
;
79 SetProcessDEPPolicyFunction set_process_dep_policy
=
80 reinterpret_cast<SetProcessDEPPolicyFunction
>(
81 ::GetProcAddress(module
, "SetProcessDEPPolicy"));
82 if (set_process_dep_policy
) {
83 if (!set_process_dep_policy(dep_flags
) &&
84 ERROR_ACCESS_DENIED
!= ::GetLastError() && return_on_fail
) {
88 // We're on XP sp2, so use the less standard approach.
89 // For reference: http://www.uninformed.org/?v=2&a=4
90 static const int MEM_EXECUTE_OPTION_DISABLE
= 2;
91 static const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION
= 4;
92 static const int MEM_EXECUTE_OPTION_PERMANENT
= 8;
94 NtSetInformationProcessFunction set_information_process
= NULL
;
95 ResolveNTFunctionPtr("NtSetInformationProcess",
96 &set_information_process
);
97 if (!set_information_process
)
99 ULONG dep
= MEM_EXECUTE_OPTION_DISABLE
| MEM_EXECUTE_OPTION_PERMANENT
;
100 if (!(dep_flags
& PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
))
101 dep
|= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION
;
102 if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
104 &dep
, sizeof(dep
))) &&
105 ERROR_ACCESS_DENIED
!= ::GetLastError() && return_on_fail
) {
112 // This is all we can do in Win7 and below.
113 if (version
< base::win::VERSION_WIN8
)
116 SetProcessMitigationPolicyFunction set_process_mitigation_policy
=
117 reinterpret_cast<SetProcessMitigationPolicyFunction
>(
118 ::GetProcAddress(module
, "SetProcessMitigationPolicy"));
119 if (!set_process_mitigation_policy
)
122 // Enable ASLR policies.
123 if (flags
& MITIGATION_RELOCATE_IMAGE
) {
124 PROCESS_MITIGATION_ASLR_POLICY policy
= {};
125 policy
.EnableForceRelocateImages
= true;
126 policy
.DisallowStrippedImages
= (flags
&
127 MITIGATION_RELOCATE_IMAGE_REQUIRED
) ==
128 MITIGATION_RELOCATE_IMAGE_REQUIRED
;
130 if (!set_process_mitigation_policy(ProcessASLRPolicy
, &policy
,
132 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
137 // Enable strict handle policies.
138 if (flags
& MITIGATION_STRICT_HANDLE_CHECKS
) {
139 PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy
= {};
140 policy
.HandleExceptionsPermanentlyEnabled
=
141 policy
.RaiseExceptionOnInvalidHandleReference
= true;
143 if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy
, &policy
,
145 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
150 // Enable system call policies.
151 if (flags
& MITIGATION_WIN32K_DISABLE
) {
152 PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy
= {};
153 policy
.DisallowWin32kSystemCalls
= true;
155 if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy
, &policy
,
157 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
162 // Enable system call policies.
163 if (flags
& MITIGATION_EXTENSION_DLL_DISABLE
) {
164 PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy
= {};
165 policy
.DisableExtensionPoints
= true;
167 if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy
,
168 &policy
, sizeof(policy
)) &&
169 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
177 void ConvertProcessMitigationsToPolicy(MitigationFlags flags
,
178 DWORD64
* policy_flags
, size_t* size
) {
179 base::win::Version version
= base::win::GetVersion();
183 *size
= sizeof(*policy_flags
);
184 #elif defined(_M_IX86)
185 // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
186 if (version
< base::win::VERSION_WIN8
)
187 *size
= sizeof(DWORD
);
189 *size
= sizeof(*policy_flags
);
191 #error This platform is not supported.
194 // Nothing for Win XP or Vista.
195 if (version
<= base::win::VERSION_VISTA
)
198 // DEP and SEHOP are not valid for 64-bit Windows
200 if (flags
& MITIGATION_DEP
) {
201 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE
;
202 if (!(flags
& MITIGATION_DEP_NO_ATL_THUNK
))
203 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE
;
206 if (flags
& MITIGATION_SEHOP
)
207 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE
;
211 if (version
< base::win::VERSION_WIN8
)
214 if (flags
& MITIGATION_RELOCATE_IMAGE
) {
216 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON
;
217 if (flags
& MITIGATION_RELOCATE_IMAGE_REQUIRED
) {
219 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS
;
223 if (flags
& MITIGATION_HEAP_TERMINATE
) {
225 PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON
;
228 if (flags
& MITIGATION_BOTTOM_UP_ASLR
) {
230 PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON
;
233 if (flags
& MITIGATION_HIGH_ENTROPY_ASLR
) {
235 PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON
;
238 if (flags
& MITIGATION_STRICT_HANDLE_CHECKS
) {
240 PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON
;
243 if (flags
& MITIGATION_WIN32K_DISABLE
) {
245 PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON
;
248 if (flags
& MITIGATION_EXTENSION_DLL_DISABLE
) {
250 PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON
;
254 MitigationFlags
FilterPostStartupProcessMitigations(MitigationFlags flags
) {
255 base::win::Version version
= base::win::GetVersion();
258 if (version
< base::win::VERSION_VISTA
) {
259 return flags
& (MITIGATION_DEP
|
260 MITIGATION_DEP_NO_ATL_THUNK
);
264 if (version
< base::win::VERSION_WIN7
) {
265 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
266 MITIGATION_DLL_SEARCH_ORDER
|
267 MITIGATION_HEAP_TERMINATE
);
271 if (version
< base::win::VERSION_WIN8
) {
272 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
273 MITIGATION_DLL_SEARCH_ORDER
|
274 MITIGATION_HEAP_TERMINATE
);
277 // Windows 8 and above.
278 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
279 MITIGATION_DLL_SEARCH_ORDER
);
282 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process
,
283 MitigationFlags flags
) {
284 // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
286 if (flags
& MITIGATION_BOTTOM_UP_ASLR
) {
290 const size_t kMask64k
= 0xFFFF;
291 // Random range (512k-16.5mb) in 64k steps.
292 const char* end
= ptr
+ ((((limit
% 16384) + 512) * 1024) & ~kMask64k
);
294 MEMORY_BASIC_INFORMATION memory_info
;
295 if (!::VirtualQueryEx(process
, ptr
, &memory_info
, sizeof(memory_info
)))
297 size_t size
= std::min((memory_info
.RegionSize
+ kMask64k
) & ~kMask64k
,
298 static_cast<SIZE_T
>(end
- ptr
));
299 if (ptr
&& memory_info
.State
== MEM_FREE
)
300 ::VirtualAllocEx(process
, ptr
, size
, MEM_RESERVE
, PAGE_NOACCESS
);
309 bool CanSetProcessMitigationsPostStartup(MitigationFlags flags
) {
310 // All of these mitigations can be enabled after startup.
311 return !(flags
& ~(MITIGATION_HEAP_TERMINATE
|
313 MITIGATION_DEP_NO_ATL_THUNK
|
314 MITIGATION_RELOCATE_IMAGE
|
315 MITIGATION_RELOCATE_IMAGE_REQUIRED
|
316 MITIGATION_BOTTOM_UP_ASLR
|
317 MITIGATION_STRICT_HANDLE_CHECKS
|
318 MITIGATION_EXTENSION_DLL_DISABLE
|
319 MITIGATION_DLL_SEARCH_ORDER
|
320 MITIGATION_HARDEN_TOKEN_IL_POLICY
));
323 bool CanSetProcessMitigationsPreStartup(MitigationFlags flags
) {
324 // These mitigations cannot be enabled prior to startup.
325 return !(flags
& (MITIGATION_STRICT_HANDLE_CHECKS
|
326 MITIGATION_DLL_SEARCH_ORDER
));
329 } // namespace sandbox