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