diff --git a/inc/usersim/common.h b/inc/usersim/common.h index ac95c34..44618f8 100644 --- a/inc/usersim/common.h +++ b/inc/usersim/common.h @@ -8,3 +8,26 @@ #else #define USERSIM_API __declspec(dllimport) #endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Suspend fault injection within usersim.dll. + * + * Calls may be nested and must be balanced by calls to usersim_fault_injection_resume(). + */ +USERSIM_API void +usersim_fault_injection_suspend(); + +/** + * @brief Resume fault injection within usersim.dll after a matching suspension. + */ +USERSIM_API void +usersim_fault_injection_resume(); + +#ifdef __cplusplus +} +#endif diff --git a/src/Source.def b/src/Source.def index c09998c..34545be 100644 --- a/src/Source.def +++ b/src/Source.def @@ -51,3 +51,6 @@ EXPORTS NmrRegisterProvider NmrWaitForClientDeregisterComplete NmrWaitForProviderDeregisterComplete + + usersim_fault_injection_resume + usersim_fault_injection_suspend diff --git a/src/platform_user.cpp b/src/platform_user.cpp index 85e44df..6518196 100644 --- a/src/platform_user.cpp +++ b/src/platform_user.cpp @@ -4,6 +4,7 @@ #include "cxplat.h" #include "cxplat_fault_injection.h" #include "tracelog.h" +#include "usersim/common.h" #include "usersim/ex.h" #include "usersim/ke.h" #include "usersim/mm.h" @@ -45,6 +46,18 @@ static bool _cxplat_initialized = false; // Used to compute the current CPU index. static std::vector _usersim_platform_group_to_index_map; +void +usersim_fault_injection_suspend() +{ + cxplat_fault_injection_suspend(); +} + +void +usersim_fault_injection_resume() +{ + cxplat_fault_injection_resume(); +} + _Must_inspect_result_ usersim_result_t usersim_platform_initiate() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ccf6dd..f26414f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,6 +14,7 @@ FetchContent_MakeAvailable(Catch2) add_executable(usersim_tests etw_test.cpp ex_test.cpp + fault_injection_test.cpp ke_test.cpp mm_test.cpp nmr_test.cpp diff --git a/tests/fault_injection_test.cpp b/tests/fault_injection_test.cpp new file mode 100644 index 0000000..5a10d55 --- /dev/null +++ b/tests/fault_injection_test.cpp @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +#if !defined(CMAKE_NUGET) +#include +#else +#include +#endif + +#include "usersim/common.h" +#include "usersim/ex.h" + +#include + +static bool +_is_fault_injection_enabled() +{ + char value[32] = {}; + size_t required_size = 0; + getenv_s(&required_size, value, sizeof(value), "CXPLAT_FAULT_INJECTION_SIMULATION"); + return required_size > 0 && std::strtoull(value, nullptr, 10) > 0; +} + +TEST_CASE("usersim fault injection suspension", "[fault_injection]") +{ + auto call_fault_injected_usersim_api = []() { + UUID uuid = {}; + return ExUuidCreate(&uuid); + }; + + usersim_fault_injection_suspend(); + usersim_fault_injection_suspend(); + NTSTATUS nested_suspension_status = call_fault_injected_usersim_api(); + + usersim_fault_injection_resume(); + NTSTATUS single_suspension_status = call_fault_injected_usersim_api(); + + usersim_fault_injection_resume(); + NTSTATUS resumed_status = call_fault_injected_usersim_api(); + + REQUIRE(nested_suspension_status == STATUS_SUCCESS); + REQUIRE(single_suspension_status == STATUS_SUCCESS); + REQUIRE(resumed_status == (_is_fault_injection_enabled() ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS)); +} diff --git a/tests/tests.vcxproj b/tests/tests.vcxproj index 8dfc5a9..172aff2 100644 --- a/tests/tests.vcxproj +++ b/tests/tests.vcxproj @@ -74,6 +74,7 @@ +