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