| 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 |