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_ENABLE
= 1;
91 static const int MEM_EXECUTE_OPTION_DISABLE
= 2;
92 static const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION
= 4;
93 static const int MEM_EXECUTE_OPTION_PERMANENT
= 8;
95 NtSetInformationProcessFunction set_information_process
= NULL
;
96 ResolveNTFunctionPtr("NtSetInformationProcess",
97 &set_information_process
);
98 if (!set_information_process
)
100 ULONG dep
= MEM_EXECUTE_OPTION_DISABLE
| MEM_EXECUTE_OPTION_PERMANENT
;
101 if (!(dep_flags
& PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
))
102 dep
|= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION
;
103 if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
105 &dep
, sizeof(dep
))) &&
106 ERROR_ACCESS_DENIED
!= ::GetLastError() && return_on_fail
) {
113 // This is all we can do in Win7 and below.
114 if (version
< base::win::VERSION_WIN8
)
117 SetProcessMitigationPolicyFunction set_process_mitigation_policy
=
118 reinterpret_cast<SetProcessMitigationPolicyFunction
>(
119 ::GetProcAddress(module
, "SetProcessMitigationPolicy"));
120 if (!set_process_mitigation_policy
)
123 // Enable ASLR policies.
124 if (flags
& MITIGATION_RELOCATE_IMAGE
) {
125 PROCESS_MITIGATION_ASLR_POLICY policy
= { 0 };
126 policy
.EnableForceRelocateImages
= true;
127 policy
.DisallowStrippedImages
= (flags
&
128 MITIGATION_RELOCATE_IMAGE_REQUIRED
) ==
129 MITIGATION_RELOCATE_IMAGE_REQUIRED
;
131 if (!set_process_mitigation_policy(ProcessASLRPolicy
, &policy
,
133 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
138 // Enable strict handle policies.
139 if (flags
& MITIGATION_STRICT_HANDLE_CHECKS
) {
140 PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy
= { 0 };
141 policy
.HandleExceptionsPermanentlyEnabled
=
142 policy
.RaiseExceptionOnInvalidHandleReference
= true;
144 if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy
, &policy
,
146 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
151 // Enable system call policies.
152 if (flags
& MITIGATION_WIN32K_DISABLE
) {
153 PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy
= { 0 };
154 policy
.DisallowWin32kSystemCalls
= true;
156 if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy
, &policy
,
158 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
163 // Enable system call policies.
164 if (flags
& MITIGATION_EXTENSION_DLL_DISABLE
) {
165 PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy
= { 0 };
166 policy
.DisableExtensionPoints
= true;
168 if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy
,
169 &policy
, sizeof(policy
)) &&
170 ERROR_ACCESS_DENIED
!= ::GetLastError()) {
178 void ConvertProcessMitigationsToPolicy(MitigationFlags flags
,
179 DWORD64
* policy_flags
, size_t* size
) {
180 base::win::Version version
= base::win::GetVersion();
184 *size
= sizeof(*policy_flags
);
185 #elif defined(_M_IX86)
186 // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
187 if (version
< base::win::VERSION_WIN8
)
188 *size
= sizeof(DWORD
);
190 *size
= sizeof(*policy_flags
);
192 #error This platform is not supported.
195 // Nothing for Win XP or Vista.
196 if (version
<= base::win::VERSION_VISTA
)
199 // DEP and SEHOP are not valid for 64-bit Windows
201 if (flags
& MITIGATION_DEP
) {
202 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE
;
203 if (!(flags
& MITIGATION_DEP_NO_ATL_THUNK
))
204 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE
;
207 if (flags
& MITIGATION_SEHOP
)
208 *policy_flags
|= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE
;
212 if (version
< base::win::VERSION_WIN8
)
215 if (flags
& MITIGATION_RELOCATE_IMAGE
) {
217 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON
;
218 if (flags
& MITIGATION_RELOCATE_IMAGE_REQUIRED
) {
220 PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS
;
224 if (flags
& MITIGATION_HEAP_TERMINATE
) {
226 PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON
;
229 if (flags
& MITIGATION_BOTTOM_UP_ASLR
) {
231 PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON
;
234 if (flags
& MITIGATION_HIGH_ENTROPY_ASLR
) {
236 PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON
;
239 if (flags
& MITIGATION_STRICT_HANDLE_CHECKS
) {
241 PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON
;
244 if (flags
& MITIGATION_WIN32K_DISABLE
) {
246 PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON
;
249 if (flags
& MITIGATION_EXTENSION_DLL_DISABLE
) {
251 PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON
;
255 MitigationFlags
FilterPostStartupProcessMitigations(MitigationFlags flags
) {
256 base::win::Version version
= base::win::GetVersion();
259 if (version
< base::win::VERSION_VISTA
) {
260 return flags
& (MITIGATION_DEP
|
261 MITIGATION_DEP_NO_ATL_THUNK
);
265 if (version
< base::win::VERSION_WIN7
) {
266 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
267 MITIGATION_DLL_SEARCH_ORDER
|
268 MITIGATION_HEAP_TERMINATE
);
272 if (version
< base::win::VERSION_WIN8
) {
273 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
274 MITIGATION_DLL_SEARCH_ORDER
|
275 MITIGATION_HEAP_TERMINATE
);
278 // Windows 8 and above.
279 return flags
& (MITIGATION_BOTTOM_UP_ASLR
|
280 MITIGATION_DLL_SEARCH_ORDER
);
283 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process
,
284 MitigationFlags flags
) {
285 // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
287 if (flags
& MITIGATION_BOTTOM_UP_ASLR
) {
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
);
295 MEMORY_BASIC_INFORMATION memory_info
;
296 if (!::VirtualQueryEx(process
, ptr
, &memory_info
, sizeof(memory_info
)))
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
);
310 bool CanSetProcessMitigationsPostStartup(MitigationFlags flags
) {
311 // All of these mitigations can be enabled after startup.
312 return !(flags
& ~(MITIGATION_HEAP_TERMINATE
|
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_EXTENSION_DLL_DISABLE
|
320 MITIGATION_DLL_SEARCH_ORDER
|
321 MITIGATION_HARDEN_TOKEN_IL_POLICY
));
324 bool CanSetProcessMitigationsPreStartup(MitigationFlags flags
) {
325 // These mitigations cannot be enabled prior to startup.
326 return !(flags
& (MITIGATION_STRICT_HANDLE_CHECKS
|
327 MITIGATION_DLL_SEARCH_ORDER
));
330 } // namespace sandbox