- add sources.
[platform/framework/web/crosswalk.git] / src / sandbox / win / src / process_mitigations.cc
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 <algorithm>
8
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"
13
14 namespace {
15
16 // Functions for enabling policies.
17 typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags);
18
19 typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)(
20     PROCESS_MITIGATION_POLICY mitigation_policy,
21     PVOID buffer,
22     SIZE_T length);
23
24 typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)(
25     DWORD DirectoryFlags);
26
27 }  // namespace
28
29 namespace sandbox {
30
31 bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
32   if (!CanSetProcessMitigationsPostStartup(flags))
33     return false;
34
35   // We can't apply anything before Win XP, so just return cleanly.
36   if (!IsXPSP2OrLater())
37     return true;
38
39   base::win::Version version = base::win::GetVersion();
40   HMODULE module = ::GetModuleHandleA("kernel32.dll");
41
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"));
47
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()) {
52         return false;
53       }
54     }
55   }
56
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,
61                               NULL, 0) &&
62         ERROR_ACCESS_DENIED != ::GetLastError()) {
63       return false;
64     }
65   }
66
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;
72
73     if (flags & MITIGATION_DEP_NO_ATL_THUNK)
74       dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
75
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) {
82         return false;
83       }
84     } else {
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;
91
92       NtSetInformationProcessFunction set_information_process = NULL;
93       ResolveNTFunctionPtr("NtSetInformationProcess",
94                            &set_information_process);
95       if (!set_information_process)
96         return false;
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(),
101                                              ProcessExecuteFlags,
102                                              &dep, sizeof(dep))) &&
103           ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
104         return false;
105       }
106     }
107   }
108 #endif
109
110   // This is all we can do in Win7 and below.
111   if (version < base::win::VERSION_WIN8)
112     return true;
113
114   SetProcessMitigationPolicyFunction set_process_mitigation_policy =
115       reinterpret_cast<SetProcessMitigationPolicyFunction>(
116           ::GetProcAddress(module, "SetProcessMitigationPolicy"));
117   if (!set_process_mitigation_policy)
118     return false;
119
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;
127
128     if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
129                                        sizeof(policy)) &&
130         ERROR_ACCESS_DENIED != ::GetLastError()) {
131       return false;
132     }
133   }
134
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;
140
141     if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
142                                        sizeof(policy)) &&
143         ERROR_ACCESS_DENIED != ::GetLastError()) {
144       return false;
145     }
146   }
147
148   // Enable system call policies.
149   if (flags & MITIGATION_WIN32K_DISABLE) {
150     PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 };
151     policy.DisallowWin32kSystemCalls = true;
152
153     if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
154                                        sizeof(policy)) &&
155         ERROR_ACCESS_DENIED != ::GetLastError()) {
156       return false;
157     }
158   }
159
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;
164
165     if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
166                                        &policy, sizeof(policy)) &&
167         ERROR_ACCESS_DENIED != ::GetLastError()) {
168       return false;
169     }
170   }
171
172   return true;
173 }
174
175 void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
176                                        DWORD64* policy_flags, size_t* size) {
177   base::win::Version version = base::win::GetVersion();
178
179   *policy_flags = 0;
180 #if defined(_WIN64)
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);
186   else
187     *size = sizeof(*policy_flags);
188 #else
189 #error This platform is not supported.
190 #endif
191
192   // Nothing for Win XP or Vista.
193   if (version <= base::win::VERSION_VISTA)
194     return;
195
196   // DEP and SEHOP are not valid for 64-bit Windows
197 #if !defined(_WIN64)
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;
202   }
203
204   if (flags & MITIGATION_SEHOP)
205     *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;
206 #endif
207
208   // Win 7
209   if (version < base::win::VERSION_WIN8)
210     return;
211
212   if (flags & MITIGATION_RELOCATE_IMAGE) {
213     *policy_flags |=
214         PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
215     if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
216       *policy_flags |=
217           PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
218     }
219   }
220
221   if (flags & MITIGATION_HEAP_TERMINATE) {
222     *policy_flags |=
223         PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
224   }
225
226   if (flags & MITIGATION_BOTTOM_UP_ASLR) {
227     *policy_flags |=
228         PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
229   }
230
231   if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
232     *policy_flags |=
233         PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
234   }
235
236   if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
237     *policy_flags |=
238         PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
239   }
240
241   if (flags & MITIGATION_WIN32K_DISABLE) {
242     *policy_flags |=
243         PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
244   }
245
246   if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
247     *policy_flags |=
248         PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
249   }
250 }
251
252 MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
253   // Anything prior to XP SP2.
254   if (!IsXPSP2OrLater())
255     return 0;
256
257   base::win::Version version = base::win::GetVersion();
258
259   // Windows XP SP2+.
260   if (version < base::win::VERSION_VISTA) {
261     return flags & (MITIGATION_DEP |
262                     MITIGATION_DEP_NO_ATL_THUNK);
263
264   // Windows Vista
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);
271   }
272
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);
278   }
279
280   // Windows 8 and above.
281   return flags & (MITIGATION_BOTTOM_UP_ASLR |
282                   MITIGATION_DLL_SEARCH_ORDER);
283 }
284
285 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
286                                                MitigationFlags flags) {
287 // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
288 #if !defined(_WIN64)
289   if (flags & MITIGATION_BOTTOM_UP_ASLR) {
290     unsigned int limit;
291     rand_s(&limit);
292     char* ptr = 0;
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);
296     while (ptr < end) {
297       MEMORY_BASIC_INFORMATION memory_info;
298       if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
299         break;
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);
304       ptr += size;
305     }
306   }
307 #endif
308
309   return true;
310 }
311
312 bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
313   // All of these mitigations can be enabled after startup.
314   return !(flags & ~(MITIGATION_HEAP_TERMINATE |
315                      MITIGATION_DEP |
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));
324 }
325
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));
331 }
332
333 }  // namespace sandbox
334