OLD | NEW |
| (Empty) |
1 // Copyright 2011 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 <d3d9.h> | |
8 #include <initguid.h> | |
9 #include <opmapi.h> | |
10 #include <psapi.h> | |
11 #include <windows.h> | |
12 | |
13 #include <map> | |
14 #include <string> | |
15 | |
16 #include "base/command_line.h" | |
17 #include "base/files/file_util.h" | |
18 #include "base/files/scoped_temp_dir.h" | |
19 #include "base/memory/ref_counted.h" | |
20 #include "base/path_service.h" | |
21 #include "base/process/launch.h" | |
22 #include "base/scoped_native_library.h" | |
23 #include "base/strings/stringprintf.h" | |
24 #include "base/strings/utf_string_conversions.h" | |
25 #include "base/test/test_timeouts.h" | |
26 #include "base/win/registry.h" | |
27 #include "base/win/scoped_handle.h" | |
28 #include "base/win/startup_information.h" | |
29 #include "base/win/win_util.h" | |
30 #include "base/win/windows_version.h" | |
31 #include "sandbox/win/src/nt_internals.h" | |
32 #include "sandbox/win/src/process_mitigations_win32k_policy.h" | |
33 #include "sandbox/win/src/sandbox.h" | |
34 #include "sandbox/win/src/sandbox_factory.h" | |
35 #include "sandbox/win/src/target_services.h" | |
36 #include "sandbox/win/tests/common/controller.h" | |
37 #include "sandbox/win/tests/integration_tests/integration_tests_common.h" | |
38 #include "testing/gtest/include/gtest/gtest.h" | |
39 | |
40 namespace { | |
41 | |
42 // Timeouts for synchronization. | |
43 #define event_timeout \ | |
44 static_cast<DWORD>((TestTimeouts::action_timeout()).InMillisecondsRoundedUp()) | |
45 | |
46 // API defined in winbase.h. | |
47 typedef decltype(GetProcessDEPPolicy)* GetProcessDEPPolicyFunction; | |
48 | |
49 // API defined in processthreadsapi.h. | |
50 typedef decltype( | |
51 GetProcessMitigationPolicy)* GetProcessMitigationPolicyFunction; | |
52 GetProcessMitigationPolicyFunction get_process_mitigation_policy; | |
53 | |
54 // APIs defined in wingdi.h. | |
55 typedef decltype(AddFontMemResourceEx)* AddFontMemResourceExFunction; | |
56 typedef decltype(RemoveFontMemResourceEx)* RemoveFontMemResourceExFunction; | |
57 | |
58 // APIs defined in integration_tests_common.h | |
59 typedef decltype(WasHookCalled)* WasHookCalledFunction; | |
60 typedef decltype(SetHook)* SetHookFunction; | |
61 | |
62 #if !defined(_WIN64) | |
63 bool CheckWin8DepPolicy() { | |
64 PROCESS_MITIGATION_DEP_POLICY policy = {}; | |
65 if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDEPPolicy, | |
66 &policy, sizeof(policy))) { | |
67 return false; | |
68 } | |
69 return policy.Enable && policy.Permanent; | |
70 } | |
71 #endif // !defined(_WIN64) | |
72 | |
73 bool CheckWin8AslrPolicy() { | |
74 PROCESS_MITIGATION_ASLR_POLICY policy = {}; | |
75 if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy, | |
76 &policy, sizeof(policy))) { | |
77 return false; | |
78 } | |
79 return policy.EnableForceRelocateImages && policy.DisallowStrippedImages; | |
80 } | |
81 | |
82 bool CheckWin8StrictHandlePolicy() { | |
83 PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {}; | |
84 if (!get_process_mitigation_policy(::GetCurrentProcess(), | |
85 ProcessStrictHandleCheckPolicy, &policy, | |
86 sizeof(policy))) { | |
87 return false; | |
88 } | |
89 return policy.RaiseExceptionOnInvalidHandleReference && | |
90 policy.HandleExceptionsPermanentlyEnabled; | |
91 } | |
92 | |
93 bool CheckWin8Win32CallPolicy() { | |
94 PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {}; | |
95 if (!get_process_mitigation_policy(::GetCurrentProcess(), | |
96 ProcessSystemCallDisablePolicy, &policy, | |
97 sizeof(policy))) { | |
98 return false; | |
99 } | |
100 return policy.DisallowWin32kSystemCalls; | |
101 } | |
102 | |
103 bool CheckWin8ExtensionPointPolicy() { | |
104 PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {}; | |
105 if (!get_process_mitigation_policy(::GetCurrentProcess(), | |
106 ProcessExtensionPointDisablePolicy, | |
107 &policy, sizeof(policy))) { | |
108 return false; | |
109 } | |
110 return policy.DisableExtensionPoints; | |
111 } | |
112 | |
113 bool CheckWin10FontPolicy() { | |
114 PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {}; | |
115 if (!get_process_mitigation_policy(::GetCurrentProcess(), | |
116 ProcessFontDisablePolicy, &policy, | |
117 sizeof(policy))) { | |
118 return false; | |
119 } | |
120 return policy.DisableNonSystemFonts; | |
121 } | |
122 | |
123 bool CheckWin10ImageLoadNoRemotePolicy() { | |
124 PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {}; | |
125 if (!get_process_mitigation_policy(::GetCurrentProcess(), | |
126 ProcessImageLoadPolicy, &policy, | |
127 sizeof(policy))) { | |
128 return false; | |
129 } | |
130 return policy.NoRemoteImages; | |
131 } | |
132 | |
133 // Spawn Windows process (with or without mitigation enabled). | |
134 bool SpawnWinProc(PROCESS_INFORMATION* pi, bool success_test, HANDLE* event) { | |
135 base::win::StartupInformation startup_info; | |
136 DWORD creation_flags = 0; | |
137 | |
138 if (!success_test) { | |
139 DWORD64 flags = | |
140 PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON; | |
141 // This test only runs on >= Win8, so don't have to handle | |
142 // illegal 64-bit flags on 32-bit <= Win7. | |
143 size_t flags_size = sizeof(flags); | |
144 | |
145 if (!startup_info.InitializeProcThreadAttributeList(1) || | |
146 !startup_info.UpdateProcThreadAttribute( | |
147 PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &flags, flags_size)) { | |
148 ADD_FAILURE(); | |
149 return false; | |
150 } | |
151 creation_flags = EXTENDED_STARTUPINFO_PRESENT; | |
152 } | |
153 | |
154 // Command line must be writable. | |
155 base::string16 cmd_writeable(g_winproc_file); | |
156 | |
157 if (!::CreateProcessW(NULL, &cmd_writeable[0], NULL, NULL, FALSE, | |
158 creation_flags, NULL, NULL, startup_info.startup_info(), | |
159 pi)) { | |
160 ADD_FAILURE(); | |
161 return false; | |
162 } | |
163 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(*event, event_timeout)); | |
164 | |
165 return true; | |
166 } | |
167 | |
168 //------------------------------------------------------------------------------ | |
169 // 1. Spawn a Windows process (with or without mitigation enabled). | |
170 // 2. Load the hook Dll locally. | |
171 // 3. Create a global named event for the hook to trigger. | |
172 // 4. Start the hook (for the specific WinProc or globally). | |
173 // 5. Send a keystroke event. | |
174 // 6. Ask the hook Dll if it received a hook callback. | |
175 // 7. Cleanup the hooking. | |
176 // 8. Signal the Windows process to shutdown. | |
177 // | |
178 // Do NOT use any ASSERTs in this function. Cleanup required. | |
179 //------------------------------------------------------------------------------ | |
180 void TestWin8ExtensionPointHookWrapper(bool is_success_test, bool global_hook) { | |
181 // Set up a couple global events that this test will use. | |
182 HANDLE winproc_event = ::CreateEventW(NULL, FALSE, FALSE, g_winproc_event); | |
183 if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) { | |
184 ADD_FAILURE(); | |
185 return; | |
186 } | |
187 base::win::ScopedHandle scoped_winproc_event(winproc_event); | |
188 | |
189 HANDLE hook_event = ::CreateEventW(NULL, FALSE, FALSE, g_hook_event); | |
190 if (hook_event == NULL || hook_event == INVALID_HANDLE_VALUE) { | |
191 ADD_FAILURE(); | |
192 return; | |
193 } | |
194 base::win::ScopedHandle scoped_hook_event(hook_event); | |
195 | |
196 // 1. Spawn WinProc. | |
197 PROCESS_INFORMATION proc_info = {}; | |
198 if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event)) | |
199 return; | |
200 | |
201 // From this point on, no return on failure. Cleanup required. | |
202 bool all_good = true; | |
203 | |
204 // 2. Load the hook DLL. | |
205 base::FilePath hook_dll_path(g_hook_dll_file); | |
206 base::ScopedNativeLibrary dll(hook_dll_path); | |
207 EXPECT_TRUE(dll.is_valid()); | |
208 | |
209 HOOKPROC hook_proc = | |
210 reinterpret_cast<HOOKPROC>(dll.GetFunctionPointer(g_hook_handler_func)); | |
211 WasHookCalledFunction was_hook_called = | |
212 reinterpret_cast<WasHookCalledFunction>( | |
213 dll.GetFunctionPointer(g_was_hook_called_func)); | |
214 SetHookFunction set_hook = reinterpret_cast<SetHookFunction>( | |
215 dll.GetFunctionPointer(g_set_hook_func)); | |
216 if (!hook_proc || !was_hook_called || !set_hook) { | |
217 ADD_FAILURE(); | |
218 all_good = false; | |
219 } | |
220 | |
221 // 3. Try installing the hook (either on a remote target thread, | |
222 // or globally). | |
223 HHOOK hook = nullptr; | |
224 if (all_good) { | |
225 DWORD target = 0; | |
226 if (!global_hook) | |
227 target = proc_info.dwThreadId; | |
228 hook = ::SetWindowsHookExW(WH_KEYBOARD, hook_proc, dll.get(), target); | |
229 if (!hook) { | |
230 ADD_FAILURE(); | |
231 all_good = false; | |
232 } else | |
233 // Pass the hook DLL the hook handle. | |
234 set_hook(hook); | |
235 } | |
236 | |
237 // 4. Inject a keyboard event. | |
238 if (all_good) { | |
239 // Note: that PostThreadMessage and SendMessage APIs will not deliver | |
240 // a keystroke in such a way that triggers a "legitimate" hook. | |
241 // Have to use targetless SendInput or keybd_event. The latter is | |
242 // less code and easier to work with. | |
243 keybd_event(VkKeyScan(L'A'), 0, 0, 0); | |
244 keybd_event(VkKeyScan(L'A'), 0, KEYEVENTF_KEYUP, 0); | |
245 // Give it a chance to hit the hook handler... | |
246 ::WaitForSingleObject(hook_event, event_timeout); | |
247 | |
248 // 5. Did the hook get hit? Was it expected to? | |
249 if (global_hook) | |
250 EXPECT_EQ((is_success_test ? true : false), was_hook_called()); | |
251 else | |
252 // ***IMPORTANT: when targeting a specific thread id, the | |
253 // PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE | |
254 // mitigation does NOT disable the hook API. It ONLY | |
255 // stops global hooks from running in a process. Hence, | |
256 // the hook will hit (TRUE) even in the "failure" | |
257 // case for a non-global/targeted hook. | |
258 EXPECT_EQ((is_success_test ? true : true), was_hook_called()); | |
259 } | |
260 | |
261 // 6. Disable hook. | |
262 if (hook) | |
263 EXPECT_TRUE(::UnhookWindowsHookEx(hook)); | |
264 | |
265 // 7. Trigger shutdown of WinProc. | |
266 if (proc_info.hProcess) { | |
267 if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) { | |
268 // Note: The combination/perfect-storm of a Global Hook, in a | |
269 // WinProc that has the EXTENSION_POINT_DISABLE mitigation ON, and the | |
270 // use of the SendInput or keybd_event API to inject a keystroke, | |
271 // results in the target becoming unresponsive. If any one of these | |
272 // states are changed, the problem does not occur. This means the WM_QUIT | |
273 // message is not handled and the call to WaitForSingleObject times out. | |
274 // Therefore not checking the return val. | |
275 ::WaitForSingleObject(winproc_event, event_timeout); | |
276 } else { | |
277 // Ensure no strays. | |
278 ::TerminateProcess(proc_info.hProcess, 0); | |
279 ADD_FAILURE(); | |
280 } | |
281 EXPECT_TRUE(::CloseHandle(proc_info.hThread)); | |
282 EXPECT_TRUE(::CloseHandle(proc_info.hProcess)); | |
283 } | |
284 } | |
285 | |
286 //------------------------------------------------------------------------------ | |
287 // 1. Set up the AppInit Dll in registry settings. (Enable) | |
288 // 2. Spawn a Windows process (with or without mitigation enabled). | |
289 // 3. Check if the AppInit Dll got loaded in the Windows process or not. | |
290 // 4. Signal the Windows process to shutdown. | |
291 // 5. Restore original reg settings. | |
292 // | |
293 // Do NOT use any ASSERTs in this function. Cleanup required. | |
294 //------------------------------------------------------------------------------ | |
295 void TestWin8ExtensionPointAppInitWrapper(bool is_success_test) { | |
296 // 0.5 Get path of current module. The appropriate build of the | |
297 // AppInit DLL will be in the same directory (and the | |
298 // full path is needed for reg). | |
299 wchar_t path[MAX_PATH]; | |
300 if (!::GetModuleFileNameW(NULL, path, MAX_PATH)) { | |
301 ADD_FAILURE(); | |
302 return; | |
303 } | |
304 // Only want the directory. Switch file name for the AppInit DLL. | |
305 base::FilePath full_dll_path(path); | |
306 full_dll_path = full_dll_path.DirName(); | |
307 full_dll_path = full_dll_path.Append(g_hook_dll_file); | |
308 wchar_t* non_const = const_cast<wchar_t*>(full_dll_path.value().c_str()); | |
309 // Now make sure the path is in "short-name" form for registry. | |
310 DWORD length = ::GetShortPathNameW(non_const, NULL, 0); | |
311 std::vector<wchar_t> short_name(length); | |
312 if (!::GetShortPathNameW(non_const, &short_name[0], length)) { | |
313 ADD_FAILURE(); | |
314 return; | |
315 } | |
316 | |
317 // 1. Reg setup. | |
318 const wchar_t* app_init_reg_path = | |
319 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; | |
320 const wchar_t* dlls_value_name = L"AppInit_DLLs"; | |
321 const wchar_t* enabled_value_name = L"LoadAppInit_DLLs"; | |
322 const wchar_t* signing_value_name = L"RequireSignedAppInit_DLLs"; | |
323 std::wstring orig_dlls; | |
324 std::wstring new_dlls; | |
325 DWORD orig_enabled_value = 0; | |
326 DWORD orig_signing_value = 0; | |
327 base::win::RegKey app_init_key(HKEY_LOCAL_MACHINE, app_init_reg_path, | |
328 KEY_QUERY_VALUE | KEY_SET_VALUE); | |
329 // Backup the existing settings. | |
330 if (!app_init_key.Valid() || !app_init_key.HasValue(dlls_value_name) || | |
331 !app_init_key.HasValue(enabled_value_name) || | |
332 ERROR_SUCCESS != app_init_key.ReadValue(dlls_value_name, &orig_dlls) || | |
333 ERROR_SUCCESS != | |
334 app_init_key.ReadValueDW(enabled_value_name, &orig_enabled_value)) { | |
335 ADD_FAILURE(); | |
336 return; | |
337 } | |
338 if (app_init_key.HasValue(signing_value_name)) { | |
339 if (ERROR_SUCCESS != | |
340 app_init_key.ReadValueDW(signing_value_name, &orig_signing_value)) { | |
341 ADD_FAILURE(); | |
342 return; | |
343 } | |
344 } | |
345 | |
346 // Set the new settings (obviously requires local admin privileges). | |
347 new_dlls = orig_dlls; | |
348 if (!orig_dlls.empty()) | |
349 new_dlls.append(L","); | |
350 new_dlls.append(short_name.data()); | |
351 | |
352 // From this point on, no return on failure. Cleanup required. | |
353 bool all_good = true; | |
354 | |
355 if (app_init_key.HasValue(signing_value_name)) { | |
356 if (ERROR_SUCCESS != | |
357 app_init_key.WriteValue(signing_value_name, static_cast<DWORD>(0))) { | |
358 ADD_FAILURE(); | |
359 all_good = false; | |
360 } | |
361 } | |
362 if (ERROR_SUCCESS != | |
363 app_init_key.WriteValue(dlls_value_name, new_dlls.c_str()) || | |
364 ERROR_SUCCESS != | |
365 app_init_key.WriteValue(enabled_value_name, static_cast<DWORD>(1))) { | |
366 ADD_FAILURE(); | |
367 all_good = false; | |
368 } | |
369 | |
370 // 2. Spawn WinProc. | |
371 HANDLE winproc_event = INVALID_HANDLE_VALUE; | |
372 base::win::ScopedHandle scoped_event; | |
373 PROCESS_INFORMATION proc_info = {}; | |
374 if (all_good) { | |
375 winproc_event = ::CreateEventW(NULL, FALSE, FALSE, g_winproc_event); | |
376 if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) { | |
377 ADD_FAILURE(); | |
378 all_good = false; | |
379 } else { | |
380 scoped_event.Set(winproc_event); | |
381 if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event)) | |
382 all_good = false; | |
383 } | |
384 } | |
385 | |
386 // 3. Check loaded modules in WinProc to see if the AppInit dll is loaded. | |
387 bool dll_loaded = false; | |
388 if (all_good) { | |
389 std::vector<HMODULE>(modules); | |
390 if (!base::win::GetLoadedModulesSnapshot(proc_info.hProcess, &modules)) { | |
391 ADD_FAILURE(); | |
392 all_good = false; | |
393 } else { | |
394 for (HMODULE module : modules) { | |
395 wchar_t name[MAX_PATH] = {}; | |
396 if (::GetModuleFileNameExW(proc_info.hProcess, module, name, | |
397 MAX_PATH) && | |
398 ::wcsstr(name, g_hook_dll_file)) { | |
399 // Found it. | |
400 dll_loaded = true; | |
401 break; | |
402 } | |
403 } | |
404 } | |
405 } | |
406 | |
407 // Was the test result as expected? | |
408 if (all_good) | |
409 EXPECT_EQ((is_success_test ? true : false), dll_loaded); | |
410 | |
411 // 4. Trigger shutdown of WinProc. | |
412 if (proc_info.hProcess) { | |
413 if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) { | |
414 ::WaitForSingleObject(winproc_event, event_timeout); | |
415 } else { | |
416 // Ensure no strays. | |
417 ::TerminateProcess(proc_info.hProcess, 0); | |
418 ADD_FAILURE(); | |
419 } | |
420 EXPECT_TRUE(::CloseHandle(proc_info.hThread)); | |
421 EXPECT_TRUE(::CloseHandle(proc_info.hProcess)); | |
422 } | |
423 | |
424 // 5. Reg Restore | |
425 EXPECT_EQ(ERROR_SUCCESS, | |
426 app_init_key.WriteValue(enabled_value_name, orig_enabled_value)); | |
427 if (app_init_key.HasValue(signing_value_name)) | |
428 EXPECT_EQ(ERROR_SUCCESS, | |
429 app_init_key.WriteValue(signing_value_name, orig_signing_value)); | |
430 EXPECT_EQ(ERROR_SUCCESS, | |
431 app_init_key.WriteValue(dlls_value_name, orig_dlls.c_str())); | |
432 } | |
433 | |
434 void TestWin10ImageLoadRemote(bool is_success_test) { | |
435 // ***Insert a manual testing share UNC path here! | |
436 // E.g.: \\\\hostname\\sharename\\calc.exe | |
437 std::wstring unc = L"\"\\\\hostname\\sharename\\calc.exe\""; | |
438 | |
439 sandbox::TestRunner runner; | |
440 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
441 | |
442 // Set a policy that would normally allow for process creation. | |
443 policy->SetJobLevel(sandbox::JOB_NONE, 0); | |
444 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED); | |
445 runner.SetDisableCsrss(false); | |
446 | |
447 if (!is_success_test) { | |
448 // Enable the NoRemote mitigation. | |
449 EXPECT_EQ(policy->SetDelayedProcessMitigations( | |
450 sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE), | |
451 sandbox::SBOX_ALL_OK); | |
452 } | |
453 | |
454 std::wstring test = L"TestChildProcess "; | |
455 test += unc.c_str(); | |
456 EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED | |
457 : sandbox::SBOX_TEST_FAILED), | |
458 runner.RunTest(test.c_str())); | |
459 } | |
460 | |
461 bool CheckWin10ImageLoadNoLowLabelPolicy() { | |
462 PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {}; | |
463 if (!get_process_mitigation_policy(::GetCurrentProcess(), | |
464 ProcessImageLoadPolicy, &policy, | |
465 sizeof(policy))) { | |
466 return false; | |
467 } | |
468 return policy.NoLowMandatoryLabelImages; | |
469 } | |
470 | |
471 void TestWin10ImageLoadLowLabel(bool is_success_test) { | |
472 // Setup a mandatory low executable for this test (calc.exe). | |
473 // If anything fails during setup, ASSERT to end test. | |
474 base::FilePath orig_path; | |
475 ASSERT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &orig_path)); | |
476 orig_path = orig_path.Append(L"calc.exe"); | |
477 | |
478 base::ScopedTempDir temp_dir; | |
479 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
480 base::FilePath new_path = temp_dir.GetPath(); | |
481 new_path = new_path.Append(L"lowIL_calc.exe"); | |
482 | |
483 // Test file will be cleaned up by the ScopedTempDir. | |
484 ASSERT_TRUE(base::CopyFileW(orig_path, new_path)); | |
485 | |
486 std::wstring cmd_line = L"icacls \""; | |
487 cmd_line += new_path.value().c_str(); | |
488 cmd_line += L"\" /setintegritylevel Low"; | |
489 | |
490 base::LaunchOptions options = base::LaunchOptionsForTest(); | |
491 base::Process setup_proc = base::LaunchProcess(cmd_line.c_str(), options); | |
492 ASSERT_TRUE(setup_proc.IsValid()); | |
493 | |
494 int exit_code = 1; | |
495 if (!setup_proc.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(10), | |
496 &exit_code)) { | |
497 // Might have timed out, or might have failed. | |
498 // Terminate to make sure we clean up any mess. | |
499 setup_proc.Terminate(0, false); | |
500 ASSERT_TRUE(false); | |
501 } | |
502 // Make sure icacls was successful. | |
503 ASSERT_EQ(0, exit_code); | |
504 | |
505 sandbox::TestRunner runner; | |
506 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
507 | |
508 // Set a policy that would normally allow for process creation. | |
509 policy->SetJobLevel(sandbox::JOB_NONE, 0); | |
510 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED); | |
511 runner.SetDisableCsrss(false); | |
512 | |
513 if (!is_success_test) { | |
514 // Enable the NoLowLabel mitigation. | |
515 EXPECT_EQ(policy->SetDelayedProcessMitigations( | |
516 sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL), | |
517 sandbox::SBOX_ALL_OK); | |
518 } | |
519 | |
520 std::wstring test = L"TestChildProcess "; | |
521 test += new_path.value().c_str(); | |
522 | |
523 EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED | |
524 : sandbox::SBOX_TEST_FAILED), | |
525 runner.RunTest(test.c_str())); | |
526 } | |
527 | |
528 BOOL CALLBACK MonitorEnumCallback(HMONITOR monitor, | |
529 HDC hdc_monitor, | |
530 LPRECT rect_monitor, | |
531 LPARAM data) { | |
532 std::map<HMONITOR, base::string16>& monitors = | |
533 *reinterpret_cast<std::map<HMONITOR, base::string16>*>(data); | |
534 MONITORINFOEXW monitor_info = {}; | |
535 monitor_info.cbSize = sizeof(monitor_info); | |
536 | |
537 if (!::GetMonitorInfoW(monitor, | |
538 reinterpret_cast<MONITORINFO*>(&monitor_info))) | |
539 return FALSE; | |
540 monitors[monitor] = monitor_info.szDevice; | |
541 return TRUE; | |
542 } | |
543 | |
544 std::map<HMONITOR, std::wstring> EnumerateMonitors() { | |
545 std::map<HMONITOR, std::wstring> result; | |
546 ::EnumDisplayMonitors(nullptr, nullptr, MonitorEnumCallback, | |
547 reinterpret_cast<LPARAM>(&result)); | |
548 return result; | |
549 } | |
550 | |
551 #define HMONITOR_ENTRY(monitor) \ | |
552 result[reinterpret_cast<HMONITOR>(monitor)] = \ | |
553 base::StringPrintf(L"\\\\.\\DISPLAY%X", monitor) | |
554 | |
555 std::map<HMONITOR, std::wstring> GetTestMonitors() { | |
556 std::map<HMONITOR, std::wstring> result; | |
557 | |
558 HMONITOR_ENTRY(0x11111111); | |
559 HMONITOR_ENTRY(0x22222222); | |
560 HMONITOR_ENTRY(0x44444444); | |
561 HMONITOR_ENTRY(0x88888888); | |
562 return result; | |
563 } | |
564 | |
565 std::wstring UnicodeStringToString(PUNICODE_STRING name) { | |
566 return std::wstring(name->Buffer, | |
567 name->Buffer + (name->Length / sizeof(name->Buffer[0]))); | |
568 } | |
569 | |
570 // Returns an index 1, 2, 4 or 8 depening on the device. 0 on error. | |
571 DWORD GetTestDeviceMonitorIndex(PUNICODE_STRING device_name) { | |
572 std::wstring name = UnicodeStringToString(device_name); | |
573 std::map<HMONITOR, std::wstring> monitors = GetTestMonitors(); | |
574 for (const auto& monitor : monitors) { | |
575 if (name == monitor.second) | |
576 return static_cast<DWORD>(reinterpret_cast<uintptr_t>(monitor.first)) & | |
577 0xF; | |
578 } | |
579 return 0; | |
580 } | |
581 | |
582 NTSTATUS WINAPI GetSuggestedOPMProtectedOutputArraySizeTest( | |
583 PUNICODE_STRING device_name, | |
584 DWORD* suggested_output_array_size) { | |
585 DWORD monitor = GetTestDeviceMonitorIndex(device_name); | |
586 if (!monitor) | |
587 return STATUS_OBJECT_NAME_NOT_FOUND; | |
588 *suggested_output_array_size = monitor; | |
589 return STATUS_SUCCESS; | |
590 } | |
591 | |
592 NTSTATUS WINAPI | |
593 CreateOPMProtectedOutputsTest(PUNICODE_STRING device_name, | |
594 DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos, | |
595 DWORD output_array_size, | |
596 DWORD* num_in_output_array, | |
597 OPM_PROTECTED_OUTPUT_HANDLE* output_array) { | |
598 DWORD monitor = GetTestDeviceMonitorIndex(device_name); | |
599 if (!monitor) | |
600 return STATUS_OBJECT_NAME_NOT_FOUND; | |
601 if (vos != DXGKMDT_OPM_VOS_OPM_SEMANTICS) | |
602 return STATUS_INVALID_PARAMETER; | |
603 if (output_array_size != monitor) | |
604 return STATUS_INVALID_PARAMETER; | |
605 *num_in_output_array = monitor - 1; | |
606 for (DWORD index = 0; index < monitor - 1; ++index) { | |
607 output_array[index] = | |
608 reinterpret_cast<OPM_PROTECTED_OUTPUT_HANDLE>((monitor << 4) + index); | |
609 } | |
610 return STATUS_SUCCESS; | |
611 } | |
612 | |
613 ULONG CalculateCertLength(ULONG monitor) { | |
614 return (monitor * 0x800) + 0xabc; | |
615 } | |
616 | |
617 NTSTATUS WINAPI GetCertificateTest(PUNICODE_STRING device_name, | |
618 DXGKMDT_CERTIFICATE_TYPE certificate_type, | |
619 BYTE* certificate, | |
620 ULONG certificate_length) { | |
621 DWORD monitor = GetTestDeviceMonitorIndex(device_name); | |
622 if (!monitor) | |
623 return STATUS_OBJECT_NAME_NOT_FOUND; | |
624 if (certificate_type != DXGKMDT_OPM_CERTIFICATE) | |
625 return STATUS_INVALID_PARAMETER; | |
626 if (certificate_length != CalculateCertLength(monitor)) | |
627 return STATUS_INVALID_PARAMETER; | |
628 memset(certificate, 'A' + monitor, certificate_length); | |
629 return STATUS_SUCCESS; | |
630 } | |
631 | |
632 NTSTATUS WINAPI | |
633 GetCertificateSizeTest(PUNICODE_STRING device_name, | |
634 DXGKMDT_CERTIFICATE_TYPE certificate_type, | |
635 ULONG* certificate_length) { | |
636 DWORD monitor = GetTestDeviceMonitorIndex(device_name); | |
637 if (!monitor) | |
638 return STATUS_OBJECT_NAME_NOT_FOUND; | |
639 if (certificate_type != DXGKMDT_OPM_CERTIFICATE) | |
640 return STATUS_INVALID_PARAMETER; | |
641 *certificate_length = CalculateCertLength(monitor); | |
642 return STATUS_SUCCESS; | |
643 } | |
644 | |
645 // Check for valid output handle and return the monitor index. | |
646 DWORD IsValidProtectedOutput(OPM_PROTECTED_OUTPUT_HANDLE protected_output) { | |
647 uintptr_t handle = reinterpret_cast<uintptr_t>(protected_output); | |
648 uintptr_t monitor = handle >> 4; | |
649 uintptr_t index = handle & 0xF; | |
650 switch (monitor) { | |
651 case 1: | |
652 case 2: | |
653 case 4: | |
654 case 8: | |
655 break; | |
656 default: | |
657 return 0; | |
658 } | |
659 if (index >= (monitor - 1)) | |
660 return 0; | |
661 return static_cast<DWORD>(monitor); | |
662 } | |
663 | |
664 NTSTATUS WINAPI | |
665 GetCertificateByHandleTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output, | |
666 DXGKMDT_CERTIFICATE_TYPE certificate_type, | |
667 BYTE* certificate, | |
668 ULONG certificate_length) { | |
669 DWORD monitor = IsValidProtectedOutput(protected_output); | |
670 if (!monitor) | |
671 return STATUS_INVALID_HANDLE; | |
672 if (certificate_type != DXGKMDT_OPM_CERTIFICATE) | |
673 return STATUS_INVALID_PARAMETER; | |
674 if (certificate_length != CalculateCertLength(monitor)) | |
675 return STATUS_INVALID_PARAMETER; | |
676 memset(certificate, 'A' + monitor, certificate_length); | |
677 return STATUS_SUCCESS; | |
678 } | |
679 | |
680 NTSTATUS WINAPI | |
681 GetCertificateSizeByHandleTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output, | |
682 DXGKMDT_CERTIFICATE_TYPE certificate_type, | |
683 ULONG* certificate_length) { | |
684 DWORD monitor = IsValidProtectedOutput(protected_output); | |
685 if (!monitor) | |
686 return STATUS_INVALID_HANDLE; | |
687 if (certificate_type != DXGKMDT_OPM_CERTIFICATE) | |
688 return STATUS_INVALID_PARAMETER; | |
689 *certificate_length = CalculateCertLength(monitor); | |
690 return STATUS_SUCCESS; | |
691 } | |
692 | |
693 NTSTATUS WINAPI | |
694 DestroyOPMProtectedOutputTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output) { | |
695 if (!IsValidProtectedOutput(protected_output)) | |
696 return STATUS_INVALID_HANDLE; | |
697 return STATUS_SUCCESS; | |
698 } | |
699 | |
700 NTSTATUS WINAPI ConfigureOPMProtectedOutputTest( | |
701 OPM_PROTECTED_OUTPUT_HANDLE protected_output, | |
702 const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters, | |
703 ULONG additional_parameters_size, | |
704 const BYTE* additional_parameters) { | |
705 if (!IsValidProtectedOutput(protected_output)) | |
706 return STATUS_INVALID_HANDLE; | |
707 if (additional_parameters && additional_parameters_size) | |
708 return STATUS_INVALID_PARAMETER; | |
709 return STATUS_SUCCESS; | |
710 } | |
711 | |
712 NTSTATUS WINAPI GetOPMInformationTest( | |
713 OPM_PROTECTED_OUTPUT_HANDLE protected_output, | |
714 const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters, | |
715 DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information) { | |
716 DWORD monitor = IsValidProtectedOutput(protected_output); | |
717 if (!monitor) | |
718 return STATUS_INVALID_HANDLE; | |
719 memset(requested_information, '0' + monitor, | |
720 sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION)); | |
721 return STATUS_SUCCESS; | |
722 } | |
723 | |
724 NTSTATUS WINAPI | |
725 GetOPMRandomNumberTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output, | |
726 DXGKMDT_OPM_RANDOM_NUMBER* random_number) { | |
727 DWORD monitor = IsValidProtectedOutput(protected_output); | |
728 if (!monitor) | |
729 return STATUS_INVALID_HANDLE; | |
730 memset(random_number->abRandomNumber, '!' + monitor, | |
731 sizeof(random_number->abRandomNumber)); | |
732 return STATUS_SUCCESS; | |
733 } | |
734 | |
735 NTSTATUS WINAPI SetOPMSigningKeyAndSequenceNumbersTest( | |
736 OPM_PROTECTED_OUTPUT_HANDLE protected_output, | |
737 const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters) { | |
738 DWORD monitor = IsValidProtectedOutput(protected_output); | |
739 if (!monitor) | |
740 return STATUS_INVALID_HANDLE; | |
741 DXGKMDT_OPM_ENCRYPTED_PARAMETERS test_params = {}; | |
742 memset(test_params.abEncryptedParameters, 'a' + monitor, | |
743 sizeof(test_params.abEncryptedParameters)); | |
744 if (memcmp(test_params.abEncryptedParameters, | |
745 parameters->abEncryptedParameters, | |
746 sizeof(test_params.abEncryptedParameters)) != 0) | |
747 return STATUS_INVALID_PARAMETER; | |
748 return STATUS_SUCCESS; | |
749 } | |
750 | |
751 BOOL WINAPI EnumDisplayMonitorsTest(HDC hdc, | |
752 LPCRECT clip_rect, | |
753 MONITORENUMPROC enum_function, | |
754 LPARAM data) { | |
755 RECT rc = {}; | |
756 for (const auto& monitor : GetTestMonitors()) { | |
757 if (!enum_function(monitor.first, hdc, &rc, data)) | |
758 return FALSE; | |
759 } | |
760 return TRUE; | |
761 } | |
762 | |
763 BOOL WINAPI GetMonitorInfoWTest(HMONITOR monitor, LPMONITORINFO monitor_info) { | |
764 std::map<HMONITOR, std::wstring> monitors = GetTestMonitors(); | |
765 if (monitor_info->cbSize != sizeof(MONITORINFO) && | |
766 monitor_info->cbSize != sizeof(MONITORINFOEXW)) | |
767 return FALSE; | |
768 auto it = monitors.find(monitor); | |
769 if (it == monitors.end()) | |
770 return FALSE; | |
771 if (monitor_info->cbSize == sizeof(MONITORINFOEXW)) { | |
772 MONITORINFOEXW* monitor_info_ex = | |
773 reinterpret_cast<MONITORINFOEXW*>(monitor_info); | |
774 size_t copy_size = (it->second.size() + 1) * sizeof(WCHAR); | |
775 if (copy_size > sizeof(monitor_info_ex->szDevice) - sizeof(WCHAR)) | |
776 copy_size = sizeof(monitor_info_ex->szDevice) - sizeof(WCHAR); | |
777 memset(monitor_info_ex->szDevice, 0, sizeof(monitor_info_ex->szDevice)); | |
778 memcpy(monitor_info_ex->szDevice, it->second.c_str(), copy_size); | |
779 } | |
780 return TRUE; | |
781 } | |
782 | |
783 #define RETURN_TEST_FUNC(n) \ | |
784 if (strcmp(name, #n) == 0) { \ | |
785 return n##Test; \ | |
786 } | |
787 | |
788 void* FunctionOverrideForTest(const char* name) { | |
789 RETURN_TEST_FUNC(GetSuggestedOPMProtectedOutputArraySize); | |
790 RETURN_TEST_FUNC(CreateOPMProtectedOutputs); | |
791 RETURN_TEST_FUNC(GetCertificate); | |
792 RETURN_TEST_FUNC(GetCertificateSize); | |
793 RETURN_TEST_FUNC(DestroyOPMProtectedOutput); | |
794 RETURN_TEST_FUNC(ConfigureOPMProtectedOutput); | |
795 RETURN_TEST_FUNC(GetOPMInformation); | |
796 RETURN_TEST_FUNC(GetOPMRandomNumber); | |
797 RETURN_TEST_FUNC(SetOPMSigningKeyAndSequenceNumbers); | |
798 RETURN_TEST_FUNC(EnumDisplayMonitors); | |
799 RETURN_TEST_FUNC(GetMonitorInfoW); | |
800 RETURN_TEST_FUNC(GetCertificateByHandle); | |
801 RETURN_TEST_FUNC(GetCertificateSizeByHandle); | |
802 NOTREACHED(); | |
803 return nullptr; | |
804 } | |
805 | |
806 } // namespace | |
807 | |
808 namespace sandbox { | |
809 | |
810 // A shared helper test command that will attempt to CreateProcess with a given | |
811 // command line. The second optional parameter will cause the child process to | |
812 // return that as an exit code on termination. | |
813 // | |
814 // ***Make sure you've enabled basic process creation in the | |
815 // test sandbox settings via: | |
816 // sandbox::TargetPolicy::SetJobLevel(), | |
817 // sandbox::TargetPolicy::SetTokenLevel(), | |
818 // and TestRunner::SetDisableCsrss(). | |
819 SBOX_TESTS_COMMAND int TestChildProcess(int argc, wchar_t** argv) { | |
820 if (argc < 1) | |
821 return SBOX_TEST_INVALID_PARAMETER; | |
822 | |
823 int desired_exit_code = 0; | |
824 | |
825 if (argc == 2) { | |
826 desired_exit_code = wcstoul(argv[1], nullptr, 0); | |
827 } | |
828 | |
829 std::wstring cmd = argv[0]; | |
830 base::LaunchOptions options = base::LaunchOptionsForTest(); | |
831 base::Process setup_proc = base::LaunchProcess(cmd.c_str(), options); | |
832 | |
833 if (setup_proc.IsValid()) { | |
834 setup_proc.Terminate(desired_exit_code, false); | |
835 return SBOX_TEST_SUCCEEDED; | |
836 } | |
837 // Note: GetLastError from CreateProcess returns 5, "ERROR_ACCESS_DENIED". | |
838 return SBOX_TEST_FAILED; | |
839 } | |
840 | |
841 //------------------------------------------------------------------------------ | |
842 // Win8 Checks: | |
843 // MITIGATION_DEP(_NO_ATL_THUNK) | |
844 // MITIGATION_RELOCATE_IMAGE(_REQUIRED) - ASLR | |
845 // MITIGATION_STRICT_HANDLE_CHECKS | |
846 // >= Win8 | |
847 //------------------------------------------------------------------------------ | |
848 | |
849 SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t** argv) { | |
850 get_process_mitigation_policy = | |
851 reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress( | |
852 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); | |
853 if (!get_process_mitigation_policy) | |
854 return SBOX_TEST_NOT_FOUND; | |
855 | |
856 #if !defined(_WIN64) // DEP is always enabled on 64-bit. | |
857 if (!CheckWin8DepPolicy()) | |
858 return SBOX_TEST_FIRST_ERROR; | |
859 #endif | |
860 | |
861 if (!CheckWin8AslrPolicy()) | |
862 return SBOX_TEST_SECOND_ERROR; | |
863 | |
864 if (!CheckWin8StrictHandlePolicy()) | |
865 return SBOX_TEST_THIRD_ERROR; | |
866 | |
867 return SBOX_TEST_SUCCEEDED; | |
868 } | |
869 | |
870 TEST(ProcessMitigationsTest, CheckWin8) { | |
871 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
872 return; | |
873 | |
874 TestRunner runner; | |
875 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
876 | |
877 // ASLR cannot be forced on start in debug builds. | |
878 constexpr sandbox::MitigationFlags kDebugDelayedMitigations = | |
879 MITIGATION_RELOCATE_IMAGE | MITIGATION_RELOCATE_IMAGE_REQUIRED; | |
880 | |
881 sandbox::MitigationFlags mitigations = | |
882 MITIGATION_DEP | MITIGATION_DEP_NO_ATL_THUNK; | |
883 #if defined(NDEBUG) | |
884 mitigations |= kDebugDelayedMitigations; | |
885 #endif | |
886 | |
887 EXPECT_EQ(policy->SetProcessMitigations(mitigations), SBOX_ALL_OK); | |
888 | |
889 mitigations |= MITIGATION_STRICT_HANDLE_CHECKS; | |
890 | |
891 #if !defined(NDEBUG) | |
892 mitigations |= kDebugDelayedMitigations; | |
893 #endif | |
894 | |
895 EXPECT_EQ(policy->SetDelayedProcessMitigations(mitigations), SBOX_ALL_OK); | |
896 | |
897 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8")); | |
898 } | |
899 | |
900 //------------------------------------------------------------------------------ | |
901 // DEP (MITIGATION_DEP) | |
902 // < Win8 x86 | |
903 //------------------------------------------------------------------------------ | |
904 | |
905 SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t** argv) { | |
906 GetProcessDEPPolicyFunction get_process_dep_policy = | |
907 reinterpret_cast<GetProcessDEPPolicyFunction>(::GetProcAddress( | |
908 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy")); | |
909 if (get_process_dep_policy) { | |
910 BOOL is_permanent = FALSE; | |
911 DWORD dep_flags = 0; | |
912 | |
913 if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags, | |
914 &is_permanent)) { | |
915 return SBOX_TEST_FIRST_ERROR; | |
916 } | |
917 | |
918 if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent) | |
919 return SBOX_TEST_SECOND_ERROR; | |
920 | |
921 } else { | |
922 NtQueryInformationProcessFunction query_information_process = NULL; | |
923 ResolveNTFunctionPtr("NtQueryInformationProcess", | |
924 &query_information_process); | |
925 if (!query_information_process) | |
926 return SBOX_TEST_NOT_FOUND; | |
927 | |
928 ULONG size = 0; | |
929 ULONG dep_flags = 0; | |
930 if (!SUCCEEDED(query_information_process(::GetCurrentProcess(), | |
931 ProcessExecuteFlags, &dep_flags, | |
932 sizeof(dep_flags), &size))) { | |
933 return SBOX_TEST_THIRD_ERROR; | |
934 } | |
935 | |
936 static const int MEM_EXECUTE_OPTION_DISABLE = 2; | |
937 static const int MEM_EXECUTE_OPTION_PERMANENT = 8; | |
938 dep_flags &= 0xff; | |
939 | |
940 if (dep_flags != | |
941 (MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT)) { | |
942 return SBOX_TEST_FOURTH_ERROR; | |
943 } | |
944 } | |
945 | |
946 return SBOX_TEST_SUCCEEDED; | |
947 } | |
948 | |
949 #if !defined(_WIN64) // DEP is always enabled on 64-bit. | |
950 TEST(ProcessMitigationsTest, CheckDep) { | |
951 if (base::win::GetVersion() >= base::win::VERSION_WIN8) | |
952 return; | |
953 | |
954 TestRunner runner; | |
955 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
956 | |
957 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_DEP | | |
958 MITIGATION_DEP_NO_ATL_THUNK | | |
959 MITIGATION_SEHOP), | |
960 SBOX_ALL_OK); | |
961 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep")); | |
962 } | |
963 #endif | |
964 | |
965 //------------------------------------------------------------------------------ | |
966 // Win32k Lockdown (MITIGATION_WIN32K_DISABLE) | |
967 // >= Win8 | |
968 //------------------------------------------------------------------------------ | |
969 | |
970 SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t** argv) { | |
971 get_process_mitigation_policy = | |
972 reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress( | |
973 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); | |
974 if (!get_process_mitigation_policy) | |
975 return SBOX_TEST_NOT_FOUND; | |
976 | |
977 if (!CheckWin8Win32CallPolicy()) | |
978 return SBOX_TEST_FIRST_ERROR; | |
979 return SBOX_TEST_SUCCEEDED; | |
980 } | |
981 | |
982 SBOX_TESTS_COMMAND int CheckWin8MonitorsRedirection(int argc, wchar_t** argv) { | |
983 std::map<HMONITOR, base::string16> monitors = EnumerateMonitors(); | |
984 std::map<HMONITOR, base::string16> monitors_to_test = GetTestMonitors(); | |
985 if (monitors.size() != monitors_to_test.size()) | |
986 return SBOX_TEST_FIRST_ERROR; | |
987 | |
988 for (const auto& monitor : monitors) { | |
989 auto result = monitors_to_test.find(monitor.first); | |
990 if (result == monitors_to_test.end()) | |
991 return SBOX_TEST_SECOND_ERROR; | |
992 if (result->second != monitor.second) | |
993 return SBOX_TEST_THIRD_ERROR; | |
994 } | |
995 return SBOX_TEST_SUCCEEDED; | |
996 } | |
997 | |
998 SBOX_TESTS_COMMAND int CheckWin8MonitorInfo(int argc, wchar_t** argv) { | |
999 std::map<HMONITOR, base::string16> monitors_to_test = GetTestMonitors(); | |
1000 MONITORINFO monitor_info = {}; | |
1001 MONITORINFOEXW monitor_info_exw = {}; | |
1002 MONITORINFOEXA monitor_info_exa = {}; | |
1003 HMONITOR valid_monitor = monitors_to_test.begin()->first; | |
1004 std::wstring valid_device = monitors_to_test.begin()->second; | |
1005 monitor_info.cbSize = sizeof(MONITORINFO); | |
1006 if (!::GetMonitorInfoW(valid_monitor, &monitor_info)) | |
1007 return SBOX_TEST_FIRST_ERROR; | |
1008 monitor_info.cbSize = sizeof(MONITORINFO); | |
1009 if (!::GetMonitorInfoA(valid_monitor, &monitor_info)) | |
1010 return SBOX_TEST_SECOND_ERROR; | |
1011 monitor_info_exw.cbSize = sizeof(MONITORINFOEXW); | |
1012 if (!::GetMonitorInfoW(valid_monitor, | |
1013 reinterpret_cast<MONITORINFO*>(&monitor_info_exw)) || | |
1014 valid_device != monitor_info_exw.szDevice) { | |
1015 return SBOX_TEST_THIRD_ERROR; | |
1016 } | |
1017 monitor_info_exa.cbSize = sizeof(MONITORINFOEXA); | |
1018 if (!::GetMonitorInfoA(valid_monitor, | |
1019 reinterpret_cast<MONITORINFO*>(&monitor_info_exa)) || | |
1020 valid_device != base::ASCIIToUTF16(monitor_info_exa.szDevice)) { | |
1021 return SBOX_TEST_FOURTH_ERROR; | |
1022 } | |
1023 | |
1024 // Invalid size checks. | |
1025 monitor_info.cbSize = 0; | |
1026 if (::GetMonitorInfoW(valid_monitor, &monitor_info)) | |
1027 return SBOX_TEST_FIFTH_ERROR; | |
1028 monitor_info.cbSize = 0x10000; | |
1029 if (::GetMonitorInfoW(valid_monitor, &monitor_info)) | |
1030 return SBOX_TEST_SIXTH_ERROR; | |
1031 | |
1032 // Check that an invalid handle isn't accepted. | |
1033 HMONITOR invalid_monitor = reinterpret_cast<HMONITOR>(-1); | |
1034 monitor_info.cbSize = sizeof(MONITORINFO); | |
1035 if (::GetMonitorInfoW(invalid_monitor, &monitor_info)) | |
1036 return SBOX_TEST_SEVENTH_ERROR; | |
1037 | |
1038 return SBOX_TEST_SUCCEEDED; | |
1039 } | |
1040 | |
1041 bool RunTestsOnVideoOutputConfigure(uintptr_t monitor_index, | |
1042 IOPMVideoOutput* video_output) { | |
1043 OPM_CONFIGURE_PARAMETERS config_params = {}; | |
1044 OPM_SET_PROTECTION_LEVEL_PARAMETERS* protection_level = | |
1045 reinterpret_cast<OPM_SET_PROTECTION_LEVEL_PARAMETERS*>( | |
1046 config_params.abParameters); | |
1047 protection_level->ulProtectionType = OPM_PROTECTION_TYPE_HDCP; | |
1048 protection_level->ulProtectionLevel = OPM_HDCP_ON; | |
1049 config_params.guidSetting = OPM_SET_PROTECTION_LEVEL; | |
1050 config_params.cbParametersSize = sizeof(OPM_SET_PROTECTION_LEVEL_PARAMETERS); | |
1051 HRESULT hr = video_output->Configure(&config_params, 0, nullptr); | |
1052 if (FAILED(hr)) | |
1053 return false; | |
1054 protection_level->ulProtectionType = OPM_PROTECTION_TYPE_DPCP; | |
1055 hr = video_output->Configure(&config_params, 0, nullptr); | |
1056 if (FAILED(hr)) | |
1057 return false; | |
1058 protection_level->ulProtectionLevel = OPM_HDCP_OFF; | |
1059 hr = video_output->Configure(&config_params, 0, nullptr); | |
1060 if (FAILED(hr)) | |
1061 return false; | |
1062 BYTE dummy_byte = 0; | |
1063 hr = video_output->Configure(&config_params, 1, &dummy_byte); | |
1064 if (SUCCEEDED(hr)) | |
1065 return false; | |
1066 protection_level->ulProtectionType = 0xFFFFFFFF; | |
1067 hr = video_output->Configure(&config_params, 0, nullptr); | |
1068 if (SUCCEEDED(hr)) | |
1069 return false; | |
1070 // Invalid protection level test. | |
1071 protection_level->ulProtectionType = OPM_PROTECTION_TYPE_HDCP; | |
1072 protection_level->ulProtectionLevel = OPM_HDCP_ON + 1; | |
1073 hr = video_output->Configure(&config_params, 0, nullptr); | |
1074 if (SUCCEEDED(hr)) | |
1075 return false; | |
1076 hr = video_output->Configure(&config_params, 0, nullptr); | |
1077 if (SUCCEEDED(hr)) | |
1078 return false; | |
1079 config_params.guidSetting = OPM_SET_HDCP_SRM; | |
1080 OPM_SET_HDCP_SRM_PARAMETERS* srm_parameters = | |
1081 reinterpret_cast<OPM_SET_HDCP_SRM_PARAMETERS*>( | |
1082 config_params.abParameters); | |
1083 srm_parameters->ulSRMVersion = 1; | |
1084 config_params.cbParametersSize = sizeof(OPM_SET_HDCP_SRM_PARAMETERS); | |
1085 hr = video_output->Configure(&config_params, 0, nullptr); | |
1086 if (SUCCEEDED(hr)) | |
1087 return false; | |
1088 return true; | |
1089 } | |
1090 | |
1091 bool RunTestsOnVideoOutputFinishInitialization(uintptr_t monitor_index, | |
1092 IOPMVideoOutput* video_output) { | |
1093 OPM_ENCRYPTED_INITIALIZATION_PARAMETERS init_params = {}; | |
1094 memset(init_params.abEncryptedInitializationParameters, 'a' + monitor_index, | |
1095 sizeof(init_params.abEncryptedInitializationParameters)); | |
1096 HRESULT hr = video_output->FinishInitialization(&init_params); | |
1097 if (FAILED(hr)) | |
1098 return false; | |
1099 memset(init_params.abEncryptedInitializationParameters, 'Z' + monitor_index, | |
1100 sizeof(init_params.abEncryptedInitializationParameters)); | |
1101 hr = video_output->FinishInitialization(&init_params); | |
1102 if (SUCCEEDED(hr)) | |
1103 return false; | |
1104 return true; | |
1105 } | |
1106 | |
1107 bool RunTestsOnVideoOutputStartInitialization(uintptr_t monitor_index, | |
1108 IOPMVideoOutput* video_output) { | |
1109 OPM_RANDOM_NUMBER random_number = {}; | |
1110 BYTE* certificate = nullptr; | |
1111 ULONG certificate_length = 0; | |
1112 | |
1113 HRESULT hr = video_output->StartInitialization(&random_number, &certificate, | |
1114 &certificate_length); | |
1115 if (FAILED(hr)) | |
1116 return false; | |
1117 | |
1118 if (certificate_length != CalculateCertLength(monitor_index)) | |
1119 return false; | |
1120 | |
1121 for (ULONG i = 0; i < certificate_length; ++i) { | |
1122 if (certificate[i] != 'A' + monitor_index) | |
1123 return false; | |
1124 } | |
1125 | |
1126 for (ULONG i = 0; i < sizeof(random_number.abRandomNumber); ++i) { | |
1127 if (random_number.abRandomNumber[i] != '!' + monitor_index) | |
1128 return false; | |
1129 } | |
1130 | |
1131 return true; | |
1132 } | |
1133 | |
1134 static bool SendSingleGetInfoRequest(uintptr_t monitor_index, | |
1135 IOPMVideoOutput* video_output, | |
1136 const GUID& request, | |
1137 ULONG data_length, | |
1138 void* data) { | |
1139 OPM_GET_INFO_PARAMETERS params = {}; | |
1140 OPM_REQUESTED_INFORMATION requested_information = {}; | |
1141 BYTE* requested_information_ptr = | |
1142 reinterpret_cast<BYTE*>(&requested_information); | |
1143 params.guidInformation = request; | |
1144 params.cbParametersSize = data_length; | |
1145 memcpy(params.abParameters, data, data_length); | |
1146 HRESULT hr = video_output->GetInformation(¶ms, &requested_information); | |
1147 if (FAILED(hr)) | |
1148 return false; | |
1149 for (size_t i = 0; i < sizeof(OPM_REQUESTED_INFORMATION); ++i) { | |
1150 if (requested_information_ptr[i] != '0' + monitor_index) | |
1151 return false; | |
1152 } | |
1153 return true; | |
1154 } | |
1155 | |
1156 bool RunTestsOnVideoOutputGetInformation(uintptr_t monitor_index, | |
1157 IOPMVideoOutput* video_output) { | |
1158 ULONG dummy = 0; | |
1159 if (!SendSingleGetInfoRequest(monitor_index, video_output, | |
1160 OPM_GET_CONNECTOR_TYPE, 0, nullptr)) { | |
1161 return false; | |
1162 } | |
1163 if (!SendSingleGetInfoRequest(monitor_index, video_output, | |
1164 OPM_GET_SUPPORTED_PROTECTION_TYPES, 0, | |
1165 nullptr)) { | |
1166 return false; | |
1167 } | |
1168 // These should fail due to invalid parameter sizes. | |
1169 if (SendSingleGetInfoRequest(monitor_index, video_output, | |
1170 OPM_GET_CONNECTOR_TYPE, sizeof(dummy), &dummy)) { | |
1171 return false; | |
1172 } | |
1173 if (SendSingleGetInfoRequest(monitor_index, video_output, | |
1174 OPM_GET_SUPPORTED_PROTECTION_TYPES, | |
1175 sizeof(dummy), &dummy)) { | |
1176 return false; | |
1177 } | |
1178 ULONG protection_type = OPM_PROTECTION_TYPE_HDCP; | |
1179 if (!SendSingleGetInfoRequest(monitor_index, video_output, | |
1180 OPM_GET_ACTUAL_PROTECTION_LEVEL, | |
1181 sizeof(protection_type), &protection_type)) { | |
1182 return false; | |
1183 } | |
1184 protection_type = OPM_PROTECTION_TYPE_DPCP; | |
1185 if (!SendSingleGetInfoRequest(monitor_index, video_output, | |
1186 OPM_GET_ACTUAL_PROTECTION_LEVEL, | |
1187 sizeof(protection_type), &protection_type)) { | |
1188 return false; | |
1189 } | |
1190 // These should fail as unsupported or invalid parameters. | |
1191 protection_type = OPM_PROTECTION_TYPE_ACP; | |
1192 if (SendSingleGetInfoRequest(monitor_index, video_output, | |
1193 OPM_GET_ACTUAL_PROTECTION_LEVEL, | |
1194 sizeof(protection_type), &protection_type)) { | |
1195 return false; | |
1196 } | |
1197 if (SendSingleGetInfoRequest(monitor_index, video_output, | |
1198 OPM_GET_ACTUAL_PROTECTION_LEVEL, 0, nullptr)) { | |
1199 return false; | |
1200 } | |
1201 protection_type = OPM_PROTECTION_TYPE_HDCP; | |
1202 if (!SendSingleGetInfoRequest(monitor_index, video_output, | |
1203 OPM_GET_VIRTUAL_PROTECTION_LEVEL, | |
1204 sizeof(protection_type), &protection_type)) { | |
1205 return false; | |
1206 } | |
1207 protection_type = OPM_PROTECTION_TYPE_DPCP; | |
1208 if (!SendSingleGetInfoRequest(monitor_index, video_output, | |
1209 OPM_GET_VIRTUAL_PROTECTION_LEVEL, | |
1210 sizeof(protection_type), &protection_type)) { | |
1211 return false; | |
1212 } | |
1213 // These should fail as unsupported or invalid parameters. | |
1214 protection_type = OPM_PROTECTION_TYPE_ACP; | |
1215 if (SendSingleGetInfoRequest(monitor_index, video_output, | |
1216 OPM_GET_VIRTUAL_PROTECTION_LEVEL, | |
1217 sizeof(protection_type), &protection_type)) { | |
1218 return false; | |
1219 } | |
1220 if (SendSingleGetInfoRequest(monitor_index, video_output, | |
1221 OPM_GET_VIRTUAL_PROTECTION_LEVEL, 0, nullptr)) { | |
1222 return false; | |
1223 } | |
1224 // This should fail with unsupported request. | |
1225 if (SendSingleGetInfoRequest(monitor_index, video_output, OPM_GET_CODEC_INFO, | |
1226 0, nullptr)) { | |
1227 return false; | |
1228 } | |
1229 return true; | |
1230 } | |
1231 | |
1232 int RunTestsOnVideoOutput(uintptr_t monitor_index, | |
1233 IOPMVideoOutput* video_output) { | |
1234 if (!RunTestsOnVideoOutputStartInitialization(monitor_index, video_output)) | |
1235 return SBOX_TEST_FIRST_ERROR; | |
1236 | |
1237 if (!RunTestsOnVideoOutputFinishInitialization(monitor_index, video_output)) | |
1238 return SBOX_TEST_SECOND_ERROR; | |
1239 | |
1240 if (!RunTestsOnVideoOutputConfigure(monitor_index, video_output)) | |
1241 return SBOX_TEST_THIRD_ERROR; | |
1242 | |
1243 if (!RunTestsOnVideoOutputGetInformation(monitor_index, video_output)) | |
1244 return SBOX_TEST_FOURTH_ERROR; | |
1245 | |
1246 return SBOX_TEST_SUCCEEDED; | |
1247 } | |
1248 | |
1249 SBOX_TESTS_COMMAND int CheckWin8OPMApis(int argc, wchar_t** argv) { | |
1250 std::map<HMONITOR, base::string16> monitors = GetTestMonitors(); | |
1251 for (const auto& monitor : monitors) { | |
1252 ULONG output_count = 0; | |
1253 IOPMVideoOutput** outputs = nullptr; | |
1254 uintptr_t monitor_index = reinterpret_cast<uintptr_t>(monitor.first) & 0xF; | |
1255 HRESULT hr = OPMGetVideoOutputsFromHMONITOR( | |
1256 monitor.first, OPM_VOS_OPM_SEMANTICS, &output_count, &outputs); | |
1257 if (monitor_index > 4) { | |
1258 // These should fail because the certificate is too large. | |
1259 if (SUCCEEDED(hr)) | |
1260 return SBOX_TEST_FIRST_ERROR; | |
1261 continue; | |
1262 } | |
1263 if (FAILED(hr)) | |
1264 return SBOX_TEST_SECOND_ERROR; | |
1265 if (output_count != monitor_index - 1) | |
1266 return SBOX_TEST_THIRD_ERROR; | |
1267 for (ULONG output_index = 0; output_index < output_count; ++output_index) { | |
1268 int result = RunTestsOnVideoOutput(monitor_index, outputs[output_index]); | |
1269 outputs[output_index]->Release(); | |
1270 if (result != SBOX_TEST_SUCCEEDED) | |
1271 return result; | |
1272 } | |
1273 ::CoTaskMemFree(outputs); | |
1274 } | |
1275 return SBOX_TEST_SUCCEEDED; | |
1276 } | |
1277 | |
1278 // This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation on | |
1279 // the target process causes the launch to fail in process initialization. | |
1280 // The test process itself links against user32/gdi32. | |
1281 TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownFailure) { | |
1282 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1283 return; | |
1284 | |
1285 TestRunner runner; | |
1286 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1287 | |
1288 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE), | |
1289 SBOX_ALL_OK); | |
1290 EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown")); | |
1291 } | |
1292 | |
1293 // This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation | |
1294 // along with the policy to fake user32 and gdi32 initialization successfully | |
1295 // launches the target process. | |
1296 // The test process itself links against user32/gdi32. | |
1297 TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownSuccess) { | |
1298 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1299 return; | |
1300 | |
1301 TestRunner runner; | |
1302 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1303 ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback( | |
1304 FunctionOverrideForTest); | |
1305 | |
1306 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE), | |
1307 SBOX_ALL_OK); | |
1308 EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN, | |
1309 sandbox::TargetPolicy::FAKE_USER_GDI_INIT, NULL), | |
1310 sandbox::SBOX_ALL_OK); | |
1311 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown")); | |
1312 EXPECT_NE(SBOX_TEST_SUCCEEDED, | |
1313 runner.RunTest(L"CheckWin8MonitorsRedirection")); | |
1314 EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8MonitorInfo")); | |
1315 EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8OPMApis")); | |
1316 } | |
1317 | |
1318 // This test validates the even though we're running under win32k lockdown | |
1319 // we can use the IPC redirection to enumerate the list of monitors. | |
1320 TEST(ProcessMitigationsTest, CheckWin8Win32KRedirection) { | |
1321 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1322 return; | |
1323 | |
1324 TestRunner runner; | |
1325 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1326 ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback( | |
1327 FunctionOverrideForTest); | |
1328 | |
1329 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE), | |
1330 SBOX_ALL_OK); | |
1331 EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN, | |
1332 sandbox::TargetPolicy::IMPLEMENT_OPM_APIS, NULL), | |
1333 sandbox::SBOX_ALL_OK); | |
1334 policy->SetEnableOPMRedirection(); | |
1335 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown")); | |
1336 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
1337 runner.RunTest(L"CheckWin8MonitorsRedirection")); | |
1338 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8MonitorInfo")); | |
1339 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8OPMApis")); | |
1340 } | |
1341 | |
1342 //------------------------------------------------------------------------------ | |
1343 // Disable extension points (MITIGATION_EXTENSION_POINT_DISABLE). | |
1344 // >= Win8 | |
1345 //------------------------------------------------------------------------------ | |
1346 SBOX_TESTS_COMMAND int CheckWin8ExtensionPointSetting(int argc, | |
1347 wchar_t** argv) { | |
1348 get_process_mitigation_policy = | |
1349 reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress( | |
1350 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); | |
1351 if (!get_process_mitigation_policy) | |
1352 return SBOX_TEST_NOT_FOUND; | |
1353 | |
1354 if (!CheckWin8ExtensionPointPolicy()) | |
1355 return SBOX_TEST_FIRST_ERROR; | |
1356 return SBOX_TEST_SUCCEEDED; | |
1357 } | |
1358 | |
1359 // This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE | |
1360 // mitigation enables the setting on a process. | |
1361 TEST(ProcessMitigationsTest, CheckWin8ExtensionPointPolicySuccess) { | |
1362 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1363 return; | |
1364 | |
1365 TestRunner runner; | |
1366 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1367 | |
1368 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_EXTENSION_POINT_DISABLE), | |
1369 SBOX_ALL_OK); | |
1370 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
1371 runner.RunTest(L"CheckWin8ExtensionPointSetting")); | |
1372 } | |
1373 | |
1374 // This test validates that a "legitimate" global hook CAN be set on the | |
1375 // sandboxed proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE | |
1376 // mitigation is not set. | |
1377 // | |
1378 // MANUAL testing only. | |
1379 TEST(ProcessMitigationsTest, | |
1380 DISABLED_CheckWin8ExtensionPoint_GlobalHook_Success) { | |
1381 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1382 return; | |
1383 | |
1384 HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex); | |
1385 EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE); | |
1386 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout)); | |
1387 | |
1388 // (is_success_test, global_hook) | |
1389 TestWin8ExtensionPointHookWrapper(true, true); | |
1390 | |
1391 EXPECT_TRUE(::ReleaseMutex(mutex)); | |
1392 EXPECT_TRUE(::CloseHandle(mutex)); | |
1393 } | |
1394 | |
1395 // This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE | |
1396 // mitigation prevents a global hook on WinProc. | |
1397 // | |
1398 // MANUAL testing only. | |
1399 TEST(ProcessMitigationsTest, | |
1400 DISABLED_CheckWin8ExtensionPoint_GlobalHook_Failure) { | |
1401 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1402 return; | |
1403 | |
1404 HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex); | |
1405 EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE); | |
1406 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout)); | |
1407 | |
1408 // (is_success_test, global_hook) | |
1409 TestWin8ExtensionPointHookWrapper(false, true); | |
1410 | |
1411 EXPECT_TRUE(::ReleaseMutex(mutex)); | |
1412 EXPECT_TRUE(::CloseHandle(mutex)); | |
1413 } | |
1414 | |
1415 // This test validates that a "legitimate" hook CAN be set on the sandboxed | |
1416 // proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set. | |
1417 // | |
1418 // MANUAL testing only. | |
1419 TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Success) { | |
1420 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1421 return; | |
1422 | |
1423 HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex); | |
1424 EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE); | |
1425 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout)); | |
1426 | |
1427 // (is_success_test, global_hook) | |
1428 TestWin8ExtensionPointHookWrapper(true, false); | |
1429 | |
1430 EXPECT_TRUE(::ReleaseMutex(mutex)); | |
1431 EXPECT_TRUE(::CloseHandle(mutex)); | |
1432 } | |
1433 | |
1434 // *** Important: MITIGATION_EXTENSION_POINT_DISABLE does NOT prevent | |
1435 // hooks targetted at a specific thread id. It only prevents | |
1436 // global hooks. So this test does NOT actually expect the hook | |
1437 // to fail (see TestWin8ExtensionPointHookWrapper function) even | |
1438 // with the mitigation on. | |
1439 // | |
1440 // MANUAL testing only. | |
1441 TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Failure) { | |
1442 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1443 return; | |
1444 | |
1445 HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex); | |
1446 EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE); | |
1447 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout)); | |
1448 | |
1449 // (is_success_test, global_hook) | |
1450 TestWin8ExtensionPointHookWrapper(false, false); | |
1451 | |
1452 EXPECT_TRUE(::ReleaseMutex(mutex)); | |
1453 EXPECT_TRUE(::CloseHandle(mutex)); | |
1454 } | |
1455 | |
1456 // This test validates that an AppInit Dll CAN be added to a target | |
1457 // WinProc if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set. | |
1458 // | |
1459 // MANUAL testing only. | |
1460 // Must run this test as admin/elevated. | |
1461 TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Success) { | |
1462 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1463 return; | |
1464 | |
1465 HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex); | |
1466 EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE); | |
1467 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout)); | |
1468 | |
1469 TestWin8ExtensionPointAppInitWrapper(true); | |
1470 | |
1471 EXPECT_TRUE(::ReleaseMutex(mutex)); | |
1472 EXPECT_TRUE(::CloseHandle(mutex)); | |
1473 } | |
1474 | |
1475 // This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE | |
1476 // mitigation prevents the loading of any AppInit Dll into WinProc. | |
1477 // | |
1478 // MANUAL testing only. | |
1479 // Must run this test as admin/elevated. | |
1480 TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Failure) { | |
1481 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
1482 return; | |
1483 | |
1484 HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex); | |
1485 EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE); | |
1486 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout)); | |
1487 | |
1488 TestWin8ExtensionPointAppInitWrapper(false); | |
1489 | |
1490 EXPECT_TRUE(::ReleaseMutex(mutex)); | |
1491 EXPECT_TRUE(::CloseHandle(mutex)); | |
1492 } | |
1493 | |
1494 //------------------------------------------------------------------------------ | |
1495 // Disable non-system font loads (MITIGATION_NONSYSTEM_FONT_DISABLE) | |
1496 // >= Win10 | |
1497 //------------------------------------------------------------------------------ | |
1498 | |
1499 SBOX_TESTS_COMMAND int CheckWin10FontLockDown(int argc, wchar_t** argv) { | |
1500 get_process_mitigation_policy = | |
1501 reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress( | |
1502 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); | |
1503 if (!get_process_mitigation_policy) | |
1504 return SBOX_TEST_NOT_FOUND; | |
1505 | |
1506 if (!CheckWin10FontPolicy()) | |
1507 return SBOX_TEST_FIRST_ERROR; | |
1508 return SBOX_TEST_SUCCEEDED; | |
1509 } | |
1510 | |
1511 SBOX_TESTS_COMMAND int CheckWin10FontLoad(int argc, wchar_t** argv) { | |
1512 if (argc < 1) | |
1513 return SBOX_TEST_INVALID_PARAMETER; | |
1514 | |
1515 HMODULE gdi_module = ::LoadLibraryW(L"gdi32.dll"); | |
1516 if (!gdi_module) | |
1517 return SBOX_TEST_NOT_FOUND; | |
1518 | |
1519 AddFontMemResourceExFunction add_font_mem_resource = | |
1520 reinterpret_cast<AddFontMemResourceExFunction>( | |
1521 ::GetProcAddress(gdi_module, "AddFontMemResourceEx")); | |
1522 | |
1523 RemoveFontMemResourceExFunction rem_font_mem_resource = | |
1524 reinterpret_cast<RemoveFontMemResourceExFunction>( | |
1525 ::GetProcAddress(gdi_module, "RemoveFontMemResourceEx")); | |
1526 | |
1527 if (!add_font_mem_resource || !rem_font_mem_resource) | |
1528 return SBOX_TEST_NOT_FOUND; | |
1529 | |
1530 // Open font file passed in as an argument. | |
1531 base::File file(base::FilePath(argv[0]), | |
1532 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
1533 if (!file.IsValid()) | |
1534 // Failed to open the font file passed in. | |
1535 return SBOX_TEST_NOT_FOUND; | |
1536 | |
1537 std::vector<char> font_data; | |
1538 int64_t len = file.GetLength(); | |
1539 if (len < 0) | |
1540 return SBOX_TEST_NOT_FOUND; | |
1541 font_data.resize(len); | |
1542 | |
1543 int read = file.Read(0, &font_data[0], len); | |
1544 file.Close(); | |
1545 | |
1546 if (read != len) | |
1547 return SBOX_TEST_NOT_FOUND; | |
1548 | |
1549 DWORD font_count = 0; | |
1550 HANDLE font_handle = add_font_mem_resource( | |
1551 &font_data[0], static_cast<DWORD>(font_data.size()), NULL, &font_count); | |
1552 | |
1553 if (font_handle) { | |
1554 rem_font_mem_resource(font_handle); | |
1555 return SBOX_TEST_SUCCEEDED; | |
1556 } | |
1557 | |
1558 return SBOX_TEST_FAILED; | |
1559 } | |
1560 | |
1561 // This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE | |
1562 // mitigation enables the setting on a process. | |
1563 TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownPolicySuccess) { | |
1564 if (base::win::GetVersion() < base::win::VERSION_WIN10) | |
1565 return; | |
1566 | |
1567 TestRunner runner; | |
1568 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1569 | |
1570 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_NONSYSTEM_FONT_DISABLE), | |
1571 SBOX_ALL_OK); | |
1572 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin10FontLockDown")); | |
1573 } | |
1574 | |
1575 // This test validates that we can load a non-system font | |
1576 // if the MITIGATION_NON_SYSTEM_FONTS_DISABLE | |
1577 // mitigation is NOT set. | |
1578 TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownLoadSuccess) { | |
1579 if (base::win::GetVersion() < base::win::VERSION_WIN10) | |
1580 return; | |
1581 | |
1582 base::FilePath font_path; | |
1583 EXPECT_TRUE(base::PathService::Get(base::DIR_WINDOWS_FONTS, &font_path)); | |
1584 // Arial font should always be available | |
1585 font_path = font_path.Append(L"arial.ttf"); | |
1586 | |
1587 TestRunner runner; | |
1588 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, | |
1589 font_path.value().c_str())); | |
1590 | |
1591 std::wstring test_command = L"CheckWin10FontLoad \""; | |
1592 test_command += font_path.value().c_str(); | |
1593 test_command += L"\""; | |
1594 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str())); | |
1595 } | |
1596 | |
1597 // This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE | |
1598 // mitigation prevents the loading of a non-system font. | |
1599 TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownLoadFailure) { | |
1600 if (base::win::GetVersion() < base::win::VERSION_WIN10) | |
1601 return; | |
1602 | |
1603 base::FilePath font_path; | |
1604 EXPECT_TRUE(base::PathService::Get(base::DIR_WINDOWS_FONTS, &font_path)); | |
1605 // Arial font should always be available | |
1606 font_path = font_path.Append(L"arial.ttf"); | |
1607 | |
1608 TestRunner runner; | |
1609 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1610 EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, | |
1611 font_path.value().c_str())); | |
1612 | |
1613 // Turn on the non-system font disable mitigation. | |
1614 EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_NONSYSTEM_FONT_DISABLE), | |
1615 SBOX_ALL_OK); | |
1616 | |
1617 std::wstring test_command = L"CheckWin10FontLoad \""; | |
1618 test_command += font_path.value().c_str(); | |
1619 test_command += L"\""; | |
1620 | |
1621 EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(test_command.c_str())); | |
1622 } | |
1623 | |
1624 //------------------------------------------------------------------------------ | |
1625 // Disable image load from remote devices (MITIGATION_IMAGE_LOAD_NO_REMOTE). | |
1626 // >= Win10_TH2 | |
1627 //------------------------------------------------------------------------------ | |
1628 | |
1629 SBOX_TESTS_COMMAND int CheckWin10ImageLoadNoRemote(int argc, wchar_t** argv) { | |
1630 get_process_mitigation_policy = | |
1631 reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress( | |
1632 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); | |
1633 if (!get_process_mitigation_policy) | |
1634 return SBOX_TEST_NOT_FOUND; | |
1635 | |
1636 if (!CheckWin10ImageLoadNoRemotePolicy()) | |
1637 return SBOX_TEST_FIRST_ERROR; | |
1638 return SBOX_TEST_SUCCEEDED; | |
1639 } | |
1640 | |
1641 // This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE | |
1642 // mitigation enables the setting on a process. | |
1643 TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoRemotePolicySuccess) { | |
1644 if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2) | |
1645 return; | |
1646 | |
1647 TestRunner runner; | |
1648 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1649 | |
1650 EXPECT_EQ( | |
1651 policy->SetDelayedProcessMitigations(MITIGATION_IMAGE_LOAD_NO_REMOTE), | |
1652 SBOX_ALL_OK); | |
1653 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
1654 runner.RunTest(L"CheckWin10ImageLoadNoRemote")); | |
1655 } | |
1656 | |
1657 // This test validates that we CAN create a new process from | |
1658 // a remote UNC device, if the MITIGATION_IMAGE_LOAD_NO_REMOTE | |
1659 // mitigation is NOT set. | |
1660 // | |
1661 // MANUAL testing only. | |
1662 TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteSuccess) { | |
1663 if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2) | |
1664 return; | |
1665 | |
1666 TestWin10ImageLoadRemote(true); | |
1667 } | |
1668 | |
1669 // This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE | |
1670 // mitigation prevents creating a new process from a remote | |
1671 // UNC device. | |
1672 // | |
1673 // MANUAL testing only. | |
1674 TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteFailure) { | |
1675 if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2) | |
1676 return; | |
1677 | |
1678 TestWin10ImageLoadRemote(false); | |
1679 } | |
1680 | |
1681 //------------------------------------------------------------------------------ | |
1682 // Disable image load when "mandatory low label" (integrity level). | |
1683 // (MITIGATION_IMAGE_LOAD_NO_LOW_LABEL) | |
1684 // >= Win10_TH2 | |
1685 //------------------------------------------------------------------------------ | |
1686 | |
1687 SBOX_TESTS_COMMAND int CheckWin10ImageLoadNoLowLabel(int argc, wchar_t** argv) { | |
1688 get_process_mitigation_policy = | |
1689 reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress( | |
1690 ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); | |
1691 if (!get_process_mitigation_policy) | |
1692 return SBOX_TEST_NOT_FOUND; | |
1693 | |
1694 if (!CheckWin10ImageLoadNoLowLabelPolicy()) | |
1695 return SBOX_TEST_FIRST_ERROR; | |
1696 return SBOX_TEST_SUCCEEDED; | |
1697 } | |
1698 | |
1699 // This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL | |
1700 // mitigation enables the setting on a process. | |
1701 TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelPolicySuccess) { | |
1702 if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2) | |
1703 return; | |
1704 | |
1705 TestRunner runner; | |
1706 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1707 | |
1708 EXPECT_EQ( | |
1709 policy->SetDelayedProcessMitigations(MITIGATION_IMAGE_LOAD_NO_LOW_LABEL), | |
1710 SBOX_ALL_OK); | |
1711 EXPECT_EQ(SBOX_TEST_SUCCEEDED, | |
1712 runner.RunTest(L"CheckWin10ImageLoadNoLowLabel")); | |
1713 } | |
1714 | |
1715 // This test validates that we CAN create a new process with | |
1716 // low mandatory label (IL), if the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL | |
1717 // mitigation is NOT set. | |
1718 TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelSuccess) { | |
1719 if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2) | |
1720 return; | |
1721 | |
1722 TestWin10ImageLoadLowLabel(true); | |
1723 } | |
1724 | |
1725 // This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL | |
1726 // mitigation prevents creating a new process with low mandatory label (IL). | |
1727 TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelFailure) { | |
1728 if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2) | |
1729 return; | |
1730 | |
1731 TestWin10ImageLoadLowLabel(false); | |
1732 } | |
1733 | |
1734 //------------------------------------------------------------------------------ | |
1735 // Disable child process creation. | |
1736 // - JobLevel <= JOB_LIMITED_USER (on < WIN10_TH2). | |
1737 // - JobLevel <= JOB_LIMITED_USER which also triggers setting | |
1738 // PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY to | |
1739 // PROCESS_CREATION_CHILD_PROCESS_RESTRICTED in | |
1740 // BrokerServicesBase::SpawnTarget (on >= WIN10_TH2). | |
1741 //------------------------------------------------------------------------------ | |
1742 | |
1743 // This test validates that we can spawn a child process if | |
1744 // MITIGATION_CHILD_PROCESS_CREATION_RESTRICTED mitigation is | |
1745 // not set. | |
1746 TEST(ProcessMitigationsTest, CheckChildProcessSuccess) { | |
1747 TestRunner runner; | |
1748 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1749 | |
1750 // Set a policy that would normally allow for process creation. | |
1751 policy->SetJobLevel(JOB_INTERACTIVE, 0); | |
1752 policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED); | |
1753 runner.SetDisableCsrss(false); | |
1754 | |
1755 base::FilePath cmd; | |
1756 EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd)); | |
1757 cmd = cmd.Append(L"calc.exe"); | |
1758 | |
1759 std::wstring test_command = L"TestChildProcess "; | |
1760 test_command += cmd.value().c_str(); | |
1761 | |
1762 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str())); | |
1763 } | |
1764 | |
1765 // This test validates that setting the | |
1766 // MITIGATION_CHILD_PROCESS_CREATION_RESTRICTED mitigation prevents | |
1767 // the spawning of child processes. | |
1768 TEST(ProcessMitigationsTest, CheckChildProcessFailure) { | |
1769 TestRunner runner; | |
1770 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1771 | |
1772 // Now set the job level to be <= JOB_LIMITED_USER | |
1773 // and ensure we can no longer create a child process. | |
1774 policy->SetJobLevel(JOB_LIMITED_USER, 0); | |
1775 policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED); | |
1776 runner.SetDisableCsrss(false); | |
1777 | |
1778 base::FilePath cmd; | |
1779 EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd)); | |
1780 cmd = cmd.Append(L"calc.exe"); | |
1781 | |
1782 std::wstring test_command = L"TestChildProcess "; | |
1783 test_command += cmd.value().c_str(); | |
1784 | |
1785 EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(test_command.c_str())); | |
1786 } | |
1787 | |
1788 // This test validates that when the sandboxed target within a job spawns a | |
1789 // child process and the target process exits abnormally, the broker correctly | |
1790 // handles the JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS message. | |
1791 // Because this involves spawning a child process from the target process and is | |
1792 // very similar to the above CheckChildProcess* tests, this test is here rather | |
1793 // than elsewhere closer to the other Job tests. | |
1794 TEST(ProcessMitigationsTest, CheckChildProcessAbnormalExit) { | |
1795 TestRunner runner; | |
1796 sandbox::TargetPolicy* policy = runner.GetPolicy(); | |
1797 | |
1798 // Set a policy that would normally allow for process creation. | |
1799 policy->SetJobLevel(JOB_INTERACTIVE, 0); | |
1800 policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED); | |
1801 runner.SetDisableCsrss(false); | |
1802 | |
1803 base::FilePath cmd; | |
1804 EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd)); | |
1805 cmd = cmd.Append(L"calc.exe"); | |
1806 | |
1807 std::wstring test_command(base::StringPrintf(L"TestChildProcess %ls 0x%08X", | |
1808 cmd.value().c_str(), | |
1809 STATUS_ACCESS_VIOLATION)); | |
1810 | |
1811 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str())); | |
1812 } | |
1813 | |
1814 } // namespace sandbox | |
OLD | NEW |