123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- // Copyright 2011 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/memory/raw_ptr.h"
- #include "sandbox/win/src/process_mitigations.h"
- #include <windows.h>
- #include <string>
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/path_service.h"
- #include "base/strings/stringprintf.h"
- #include "base/win/windows_version.h"
- #include "sandbox/win/src/process_mitigations.h"
- #include "sandbox/win/src/sandbox.h"
- #include "sandbox/win/src/target_services.h"
- #include "sandbox/win/tests/common/controller.h"
- #include "sandbox/win/tests/integration_tests/hooking_dll.h"
- #include "sandbox/win/tests/integration_tests/integration_tests_common.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace {
- //------------------------------------------------------------------------------
- // Internal Defines & Functions
- //------------------------------------------------------------------------------
- // Enum the dynamic code APIs being tested, to prevent hard coded int values.
- enum DynCodeAPI {
- VIRTUALALLOC = 1,
- VIRTUALPROTECT,
- MAPVIEWCUSTOM,
- MAPVIEWFILE,
- NOTSUPPORTED // Always leave this as the last enum.
- };
- // Advanced private function declaration.
- void DynamicCodeTestHarness(sandbox::MitigationFlags which_mitigation,
- bool expect_success,
- bool enable_mitigation,
- bool with_thread_opt_out = false);
- // Common helper function for the different child process dynamic code tests.
- //
- // - VirtualAlloc with PAGE_EXECUTE_*
- // - VirtualProtect with PAGE_EXECUTE_*
- // - MapViewOfFile with FILE_MAP_EXECUTE | FILE_MAP_WRITE
- int DynamicCodeTest(DynCodeAPI which_test, wchar_t* path) {
- switch (which_test) {
- case VIRTUALALLOC: {
- // Test VirtualAlloc with PAGE_EXECUTE_READWRITE.
- //-----------------------------------------------
- // Size rounds up to one page.
- void* allocation = ::VirtualAlloc(nullptr, 1, MEM_RESERVE | MEM_COMMIT,
- PAGE_EXECUTE_READWRITE);
- if (!allocation) {
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- ::VirtualFree(allocation, 0, MEM_RELEASE);
- break;
- }
- case VIRTUALPROTECT: {
- // Test VirtualProtect with PAGE_EXECUTE_READWRITE.
- //-------------------------------------------------
- // Use an existing executable function pointer.
- BYTE* function = reinterpret_cast<BYTE*>(&DynamicCodeTestHarness);
- DWORD old_protect, temp = 0;
- // Test making executable binary writable.
- if (!::VirtualProtect(function, sizeof(size_t), PAGE_EXECUTE_READWRITE,
- &old_protect)) {
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- // Make sure to test the change back to executable.
- if (!::VirtualProtect(function, sizeof(size_t), old_protect, &temp)) {
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- break;
- }
- case MAPVIEWCUSTOM: {
- // Test MapViewOfFile with FILE_MAP_EXECUTE | FILE_MAP_WRITE.
- // (Custom created mapping.)
- //-----------------------------------------------------------
- HANDLE section =
- ::CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
- PAGE_EXECUTE_READWRITE, 0, 4096, L"TestMapping");
- if (!section) {
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- // Note: this test hinges on FILE_MAP_EXECUTE | FILE_MAP_WRITE access.
- // Any other access request will succeed even with the mitigation enabled.
- HANDLE* view = reinterpret_cast<HANDLE*>(::MapViewOfFile(
- section, FILE_MAP_EXECUTE | FILE_MAP_WRITE, 0, 0, 4096));
- if (!view) {
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- ::UnmapViewOfFile(view);
- ::CloseHandle(section);
- break;
- }
- case MAPVIEWFILE: {
- // Test MapViewOfFile with FILE_MAP_EXECUTE | FILE_MAP_WRITE.
- // (Existing file on disk mapping.)
- //-----------------------------------------------------------
- // Caller should have passed in a non-null file path.
- if (!path)
- return sandbox::SBOX_TEST_INVALID_PARAMETER;
- // Note: INVALID_HANDLE_VALUE
- HANDLE file_handle =
- ::CreateFile(path, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
- if (file_handle == INVALID_HANDLE_VALUE) {
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- HANDLE mapping_handle = ::CreateFileMapping(
- file_handle, nullptr, PAGE_EXECUTE_READWRITE, 0, 1, nullptr);
- if (!mapping_handle) {
- ::CloseHandle(file_handle);
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- // Note: this test hinges on FILE_MAP_EXECUTE | FILE_MAP_WRITE access.
- // Any other access request will succeed even with the mitigation enabled.
- void* view_start = ::MapViewOfFile(
- mapping_handle, FILE_MAP_EXECUTE | FILE_MAP_WRITE, 0, 0, 0);
- if (!view_start) {
- ::CloseHandle(mapping_handle);
- ::CloseHandle(file_handle);
- DWORD error = ::GetLastError();
- return static_cast<int>(error);
- }
- ::UnmapViewOfFile(view_start);
- ::CloseHandle(mapping_handle);
- ::CloseHandle(file_handle);
- break;
- }
- default:
- return sandbox::SBOX_TEST_INVALID_PARAMETER;
- }
- return sandbox::SBOX_TEST_SUCCEEDED;
- }
- // Thread class for testing dynamic code per-thread opt-out.
- class DynamicCodeOptOutThread {
- public:
- // |path| optional, depending on |which_test|.
- DynamicCodeOptOutThread(bool mitigation,
- DynCodeAPI which_test,
- wchar_t* path = nullptr)
- : thread_(nullptr),
- opt_out_(mitigation),
- which_api_test_(which_test),
- file_path_(path),
- return_code_(sandbox::SBOX_TEST_NOT_FOUND) {}
- DynamicCodeOptOutThread(const DynamicCodeOptOutThread&) = delete;
- DynamicCodeOptOutThread& operator=(const DynamicCodeOptOutThread&) = delete;
- ~DynamicCodeOptOutThread() {
- if (thread_) {
- ::CloseHandle(thread_);
- thread_ = nullptr;
- }
- }
- // LPTHREAD_START_ROUTINE
- static DWORD WINAPI StaticThreadFunc(LPVOID lpParam) {
- DynamicCodeOptOutThread* this_thread =
- reinterpret_cast<DynamicCodeOptOutThread*>(lpParam);
- return this_thread->ThreadFunc();
- }
- // Main function. Call this to create and start the test thread.
- // Call Join() to get the test result.
- void Start() {
- if (thread_)
- return;
- thread_ = ::CreateThread(nullptr, 0, StaticThreadFunc, this, 0, nullptr);
- if (!thread_) {
- return_code_ = ::GetLastError();
- return;
- }
- }
- // Wait for test thread to finish, and get the final test result.
- int Join() {
- // Handle case where thread creation failed.
- if (!thread_)
- return return_code_;
- // NOTE: TestTimeouts::action_max_timeout() is not long enough here. In
- // debug build this times out.
- DWORD timeout = ::IsDebuggerPresent() ? INFINITE : 5000;
- return_code_ = ::WaitForSingleObject(thread_, timeout);
- // Handle case of abnormal thread exit (or timeout).
- if (return_code_ != WAIT_OBJECT_0)
- return return_code_;
- if (!::GetExitCodeThread(thread_,
- reinterpret_cast<DWORD*>(&return_code_))) {
- // Handle unexpected case of failing to get thread exit code.
- return_code_ = ::GetLastError();
- return return_code_;
- }
- return return_code_;
- }
- private:
- DWORD ThreadFunc() {
- // Opt-out this thread from disabled dynamic code.
- if (opt_out_) {
- if (!sandbox::ApplyMitigationsToCurrentThread(
- sandbox::MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD)) {
- return ::GetLastError();
- }
- }
- // Run the test.
- return DynamicCodeTest(which_api_test_, file_path_);
- }
- HANDLE thread_;
- bool opt_out_;
- DynCodeAPI which_api_test_;
- raw_ptr<wchar_t> file_path_;
- int return_code_;
- };
- // Helpers to set up rules for dynamic code tests, needed as policy
- // (from the TestRunner) can only be applied to a single process.
- std::unique_ptr<sandbox::TestRunner> RunnerWithMitigation(
- sandbox::MitigationFlags mitigations) {
- auto runner = std::make_unique<sandbox::TestRunner>();
- runner->GetPolicy()->SetDelayedProcessMitigations(mitigations);
- return runner;
- }
- //------------------------------------------------------------------------------
- // DisableDynamicCode test harness helper function. Tests numerous APIs.
- // - APIs fail with ERROR_DYNAMIC_CODE_BLOCKED if this mitigation is
- // enabled and the target tries to meddle.
- // - Acquire the global g_hooking_dll_mutex mutex before calling
- // (as we meddle with a shared system resource).
- // - Note: Do not use ASSERTs in this function, as a global mutex is held.
- //
- // Trigger test child processes (with or without mitigation enabled).
- //------------------------------------------------------------------------------
- void DynamicCodeTestHarness(sandbox::MitigationFlags which_mitigation,
- bool expect_success,
- bool enable_mitigation,
- bool with_thread_opt_out) {
- if (which_mitigation != sandbox::MITIGATION_DYNAMIC_CODE_DISABLE &&
- which_mitigation !=
- sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT) {
- ADD_FAILURE();
- return;
- }
- std::wstring shared =
- (which_mitigation == sandbox::MITIGATION_DYNAMIC_CODE_DISABLE)
- ? L"TestWin81DynamicCode "
- : L"TestWin10DynamicCodeWithOptOut ";
- if (which_mitigation ==
- sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT) {
- shared += (with_thread_opt_out) ? L"true" : L"false";
- }
- // Test 1:
- auto runner = enable_mitigation ? RunnerWithMitigation(which_mitigation)
- : std::make_unique<sandbox::TestRunner>();
- std::wstring test =
- base::StringPrintf(L"%ls %u", shared.c_str(), VIRTUALALLOC);
- EXPECT_EQ((expect_success ? sandbox::SBOX_TEST_SUCCEEDED
- : ERROR_DYNAMIC_CODE_BLOCKED),
- runner->RunTest(test.c_str()));
- // Test 2:
- runner = enable_mitigation ? RunnerWithMitigation(which_mitigation)
- : std::make_unique<sandbox::TestRunner>();
- test = base::StringPrintf(L"%ls %u", shared.c_str(), VIRTUALPROTECT);
- EXPECT_EQ((expect_success ? sandbox::SBOX_TEST_SUCCEEDED
- : ERROR_DYNAMIC_CODE_BLOCKED),
- runner->RunTest(test.c_str()));
- // Test 3:
- // Need token level >= USER_LIMITED to be able to successfully run test 3.
- runner = enable_mitigation ? RunnerWithMitigation(which_mitigation)
- : std::make_unique<sandbox::TestRunner>();
- runner->GetPolicy()->SetTokenLevel(
- sandbox::TokenLevel::USER_RESTRICTED_SAME_ACCESS,
- sandbox::TokenLevel::USER_LIMITED);
- test = base::StringPrintf(L"%ls %u", shared.c_str(), MAPVIEWCUSTOM);
- EXPECT_EQ((expect_success ? sandbox::SBOX_TEST_SUCCEEDED
- : ERROR_DYNAMIC_CODE_BLOCKED),
- runner->RunTest(test.c_str()));
- // Ensure sandbox access to the file on disk.
- base::FilePath dll_path;
- ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &dll_path));
- dll_path = dll_path.Append(hooking_dll::g_hook_dll_file);
- // File must be writable, so create a writable copy in a temporary directory.
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath temp_dll_path =
- temp_dir.GetPath().Append(hooking_dll::g_hook_dll_file);
- ASSERT_TRUE(base::CopyFile(dll_path, temp_dll_path));
- runner = enable_mitigation ? RunnerWithMitigation(which_mitigation)
- : std::make_unique<sandbox::TestRunner>();
- EXPECT_TRUE(runner->AddFsRule(sandbox::Semantics::kFilesAllowAny,
- temp_dll_path.value().c_str()));
- test = base::StringPrintf(L"%ls %u \"%ls\"", shared.c_str(), MAPVIEWFILE,
- temp_dll_path.value().c_str());
- EXPECT_EQ((expect_success ? sandbox::SBOX_TEST_SUCCEEDED
- : ERROR_DYNAMIC_CODE_BLOCKED),
- runner->RunTest(test.c_str()));
- }
- } // namespace
- namespace sandbox {
- //------------------------------------------------------------------------------
- // Exported functions called by child test processes.
- //------------------------------------------------------------------------------
- // Parse arguments and do the test.
- //
- // - Arg1 is a DynCodeAPI indicating which API to test.
- // - [OPTIONAL] If Arg1 is MAPVIEWFILE, Arg2 is a file path to map.
- SBOX_TESTS_COMMAND int TestWin81DynamicCode(int argc, wchar_t** argv) {
- if (argc < 1 || !argv[0])
- return SBOX_TEST_INVALID_PARAMETER;
- // Arg1
- int test = ::_wtoi(argv[0]);
- if (test <= 0 || test >= NOTSUPPORTED)
- return SBOX_TEST_INVALID_PARAMETER;
- // [OPTIONAL] Arg2
- wchar_t* path = nullptr;
- if (argc > 1)
- path = argv[1];
- return DynamicCodeTest(static_cast<DynCodeAPI>(test), path);
- }
- // Parse arguments and spawn the test thread.
- //
- // - Arg1 is a bool indicating whether to opt-out the test thread.
- // - Arg2 is a DynCodeAPI indicating which API to test.
- // - [OPTIONAL] If Arg2 is MAPVIEWFILE, Arg3 is a file path to map.
- SBOX_TESTS_COMMAND int TestWin10DynamicCodeWithOptOut(int argc,
- wchar_t** argv) {
- if (argc < 2 || !argv[0] || !argv[1])
- return SBOX_TEST_INVALID_PARAMETER;
- // Arg1
- bool opt_out = false;
- if (::wcsicmp(argv[0], L"true") == 0)
- opt_out = true;
- // Arg2
- int test = ::_wtoi(argv[1]);
- if (test <= 0 || test >= NOTSUPPORTED)
- return SBOX_TEST_INVALID_PARAMETER;
- // [OPTIONAL] Arg3
- wchar_t* path = nullptr;
- if (argc > 2)
- path = argv[2];
- // Spawn new thread and wait for it to finish!
- DynamicCodeOptOutThread opt_out_thread(opt_out, static_cast<DynCodeAPI>(test),
- path);
- opt_out_thread.Start();
- return opt_out_thread.Join();
- }
- //------------------------------------------------------------------------------
- // Exported Dynamic Code Tests
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- // Disable dynamic code (MITIGATION_DYNAMIC_CODE_DISABLE)
- // >= Win8.1
- //------------------------------------------------------------------------------
- // This test validates that setting the MITIGATION_DYNAMIC_CODE_DISABLE
- // mitigation enables the setting on a process.
- TEST(ProcessMitigationsTest, CheckWin81DynamicCodePolicySuccess) {
- if (base::win::GetVersion() < base::win::Version::WIN8_1)
- return;
- // TODO(crbug.com/805414): Windows ASan hotpatching requires dynamic code.
- #if !defined(ADDRESS_SANITIZER)
- std::wstring test_command = L"CheckPolicy ";
- test_command += std::to_wstring(TESTPOLICY_DYNAMICCODE);
- //---------------------------------
- // 1) Test setting pre-startup.
- // **Currently only running pre-startup in release. Due to the sandbox in the
- // child using dynamic code for hooks, calls to "dynamic code APIs" are
- // failing... silently in release, but assert/breakpoint in debug. Since
- // this test is only to check the policy setting, ignoring the failures is ok.
- //---------------------------------
- #if defined(NDEBUG)
- TestRunner runner;
- sandbox::TargetPolicy* policy = runner.GetPolicy();
- EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_DYNAMIC_CODE_DISABLE),
- SBOX_ALL_OK);
- EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
- #endif // defined(NDEBUG)
- //---------------------------------
- // 2) Test setting post-startup.
- //---------------------------------
- TestRunner runner2;
- sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
- EXPECT_EQ(
- policy2->SetDelayedProcessMitigations(MITIGATION_DYNAMIC_CODE_DISABLE),
- SBOX_ALL_OK);
- EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
- #endif
- }
- // This test validates that we can meddle with dynamic code if the
- // MITIGATION_DYNAMIC_CODE_DISABLE mitigation is NOT set.
- TEST(ProcessMitigationsTest, CheckWin81DynamicCode_BaseCase) {
- if (base::win::GetVersion() < base::win::Version::WIN8_1)
- return;
- ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
- // Expect success, no mitigation.
- DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE,
- true /* expect_success */,
- false /* enable_mitigation */);
- }
- // This test validates that setting the MITIGATION_DYNAMIC_CODE_DISABLE
- // mitigation prevents meddling with dynamic code.
- TEST(ProcessMitigationsTest, CheckWin81DynamicCode_TestMitigation) {
- if (base::win::GetVersion() < base::win::Version::WIN8_1)
- return;
- ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
- // Expect failure, with mitigation.
- DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE,
- false /* expect_success */,
- true /* enable_mitigation */);
- }
- //------------------------------------------------------------------------------
- // Disable dynamic code, with per-thread opt-out enabled
- // (MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT).
- // >= Win10_RS1 (Anniversary)
- //------------------------------------------------------------------------------
- // This test validates that setting the
- // MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT mitigation enables the setting
- // on a process.
- TEST(ProcessMitigationsTest, CheckWin10DynamicCodeOptOutPolicySuccess) {
- if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
- return;
- // TODO(crbug.com/805414): Windows ASan hotpatching requires dynamic code.
- #if !defined(ADDRESS_SANITIZER)
- std::wstring test_command = L"CheckPolicy ";
- test_command += std::to_wstring(TESTPOLICY_DYNAMICCODEOPTOUT);
- //---------------------------------
- // 1) Test setting pre-startup.
- // **Currently only running pre-startup in release. Due to the sandbox in the
- // child using dynamic code for hooks, calls to "dynamic code APIs" are
- // failing... silently in release, but assert/breakpoint in debug. Since
- // this test is only to check the policy setting, ignoring the failures is ok.
- //---------------------------------
- #if defined(NDEBUG)
- TestRunner runner;
- sandbox::TargetPolicy* policy = runner.GetPolicy();
- EXPECT_EQ(policy->SetProcessMitigations(
- MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT),
- SBOX_ALL_OK);
- EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
- #endif // defined(NDEBUG)
- //---------------------------------
- // 2) Test setting post-startup.
- //---------------------------------
- TestRunner runner2;
- sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
- EXPECT_EQ(policy2->SetDelayedProcessMitigations(
- MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT),
- SBOX_ALL_OK);
- EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
- #endif
- }
- // This test validates that we CAN meddle with dynamic code if the
- // MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT mitigation is NOT set.
- TEST(ProcessMitigationsTest, CheckWin10DynamicCodeOptOut_BaseCase) {
- if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
- return;
- ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
- // Expect success, no mitigation (and therefore no thread opt-out).
- DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT,
- true /* expect_success */,
- false /* enable_mitigation */,
- false /* with_thread_opt_out */);
- }
- // This test validates that setting the
- // MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT mitigation BLOCKS meddling
- // with dynamic code.
- TEST(ProcessMitigationsTest, CheckWin10DynamicCodeOptOut_TestMitigation) {
- if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
- return;
- ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
- // Expect failure, with mitigation, no thread opt-out.
- DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT,
- false /* expect_success */,
- true /* enable_mitigation */,
- false /* with_thread_opt_out */);
- }
- // This test validates that setting the
- // MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT mitigation AND using
- // thread-specific opt-out ALLOWS meddling with dynamic code.
- TEST(ProcessMitigationsTest,
- CheckWin10DynamicCodeOptOut_TestMitigationWithOptOut) {
- if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
- return;
- ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex);
- // Expect success, with mitigation, with thread opt-out.
- DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT,
- true /* expect_success */,
- true /* enable_mitigation */,
- true /* with_thread_opt_out */);
- }
- } // namespace sandbox
|