From 96f6d637ba8ba941b85b8f5d1d15a6f3b1e1c8a0 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Thu, 3 Aug 2023 19:58:34 -0700 Subject: [PATCH 1/4] Add Wdf* APIs required by ebpf-for-windows Add cache-aligned allocations (fixes #31) Signed-off-by: Dave Thaler --- inc/usersim/ex.h | 96 ++++++++++++ inc/usersim/io.h | 8 +- inc/usersim/wdf.h | 24 ++- src/etw.cpp | 1 + src/ex.cpp | 188 +++++++++++++++++++++- src/io.cpp | 8 + src/ke.cpp | 4 +- src/kernel_um.h | 1 + src/leak_detector.cpp | 4 + src/platform.h | 89 ----------- src/platform_user.cpp | 124 +-------------- src/se.cpp | 1 + src/wdf.cpp | 232 ++++++++++++++++++++++++++-- tests/ex_test.cpp | 9 ++ tests/wdf_test.cpp | 28 ++++ usersim_dll_skeleton/dll_skeleton.c | 12 +- 16 files changed, 586 insertions(+), 243 deletions(-) diff --git a/inc/usersim/ex.h b/inc/usersim/ex.h index c0fee2b..cb11664 100644 --- a/inc/usersim/ex.h +++ b/inc/usersim/ex.h @@ -198,6 +198,80 @@ USERSIM_API _Ret_maybenull_ void* ExAllocatePoolWithTagCPP( _In_ __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE pool_type, SIZE_T number_of_bytes, ULONG tag); +/** + * @brief Allocate memory. + * @param[in] pool_type Pool type to use. + * @param[in] size Size of memory to allocate. + * @param[in] tag Pool tag to use. + * @param[in] initialize False to return "uninitialized" memory. + * @returns Pointer to memory block allocated, or null on failure. + */ +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate_with_tag( + _In_ __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE pool_type, + size_t size, + uint32_t tag, + bool initialize); + + /** + * @brief Allocate memory. + * @param[in] size Size of memory to allocate. + * @returns Pointer to memory block allocated, or null on failure. + */ +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate(size_t size); + +/** + * @brief Reallocate memory. + * @param[in] memory Allocation to be reallocated. + * @param[in] old_size Old size of memory to reallocate. + * @param[in] new_size New size of memory to reallocate. + * @returns Pointer to memory block allocated, or null on failure. + */ +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate( + _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size); + +/** + * @brief Reallocate memory with tag. + * @param[in] memory Allocation to be reallocated. + * @param[in] old_size Old size of memory to reallocate. + * @param[in] new_size New size of memory to reallocate. + * @param[in] tag Pool tag to use. + * @returns Pointer to memory block allocated, or null on failure. + */ +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate_with_tag( + _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size, uint32_t tag); + +/** + * @brief Free memory. + * @param[in] memory Allocation to be freed. + */ +void +usersim_free(_Frees_ptr_opt_ void* memory); + +/** + * @brief Allocate memory that has a starting address that is cache aligned. + * @param[in] size Size of memory to allocate + * @returns Pointer to memory block allocated, or null on failure. + */ +USERSIM_API +__drv_allocatesMem(Mem) _Must_inspect_result_ + _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned(size_t size); + +/** + * @brief Allocate memory that has a starting address that is cache aligned with tag. + * @param[in] size Size of memory to allocate + * @param[in] tag Pool tag to use. + * @returns Pointer to memory block allocated, or null on failure. + */ +__drv_allocatesMem(Mem) _Must_inspect_result_ + _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned_with_tag(size_t size, uint32_t tag); + +/** + * @brief Free memory that has a starting address that is cache aligned. + * @param[in] memory Allocation to be freed. + */ +void +usersim_free_cache_aligned(_Frees_ptr_opt_ void* memory); + USERSIM_API _Ret_maybenull_ void* ExAllocatePoolUninitializedCPP(_In_ POOL_TYPE pool_type, _In_ size_t number_of_bytes, _In_ unsigned long tag); @@ -207,4 +281,26 @@ ExRaiseAccessViolationCPP(); USERSIM_API void ExRaiseDatatypeMisalignmentCPP(); +void usersim_initialize_ex(bool leak_detector); +void usersim_clean_up_ex(); + +#ifdef __cplusplus +#include +namespace usersim_helper { + +struct _usersim_free_functor +{ + void + operator()(void* memory) + { + usersim_free(memory); + } +}; + +typedef std::unique_ptr usersim_memory_ptr; + +} // namespace usersim_helper + +#endif + #endif diff --git a/inc/usersim/io.h b/inc/usersim/io.h index 1c403f1..331ebb8 100644 --- a/inc/usersim/io.h +++ b/inc/usersim/io.h @@ -68,7 +68,13 @@ extern "C" IoGetFileObjectGenericMapping(); USERSIM_API - _IRQL_requires_max_(DISPATCH_LEVEL) NTKERNELAPI PEPROCESS IoGetCurrentProcess(VOID); + _IRQL_requires_max_(DISPATCH_LEVEL) PEPROCESS IoGetCurrentProcess(VOID); + + typedef struct _IRP* PIRP; + + USERSIM_API + _IRQL_requires_max_(DISPATCH_LEVEL) VOID + IofCompleteRequest(_In_ PIRP irp, _In_ CCHAR priority_boost); #if defined(__cplusplus) } diff --git a/inc/usersim/wdf.h b/inc/usersim/wdf.h index 76f504a..1335744 100644 --- a/inc/usersim/wdf.h +++ b/inc/usersim/wdf.h @@ -13,7 +13,7 @@ extern "C" #endif typedef HANDLE WDFDEVICE; - typedef struct _wdfdriver WDFDRIVER; + typedef HANDLE WDFDRIVER; typedef struct _WDF_OBJECT_ATTRIBUTES WDF_OBJECT_ATTRIBUTES, *PWDF_OBJECT_ATTRIBUTES; typedef struct _WDFDEVICE_INIT WDFDEVICE_INIT, *PWDFDEVICE_INIT; @@ -21,8 +21,6 @@ extern "C" #define WDF_NO_OBJECT_ATTRIBUTES 0 #define WDF_NO_HANDLE 0 - typedef struct _wdfdriver WDFDRIVER; - typedef struct _driver_object DRIVER_OBJECT, *PDRIVER_OBJECT; typedef NTSTATUS(DRIVER_INITIALIZE)(_In_ PDRIVER_OBJECT driver_object, _In_ PUNICODE_STRING registry_path); @@ -44,10 +42,10 @@ extern "C" ULONG DriverPoolTag; } WDF_DRIVER_CONFIG, *PWDF_DRIVER_CONFIG; - typedef struct _wdfdriver + struct _driver_object { WDF_DRIVER_CONFIG config; - } WDFDRIVER; + }; #define WDF_DRIVER_GLOBALS_NAME_LEN (32) @@ -78,6 +76,22 @@ extern "C" void WDF_DRIVER_CONFIG_INIT(_Out_ PWDF_DRIVER_CONFIG config, _In_opt_ PFN_WDF_DRIVER_DEVICE_ADD evt_driver_device_add); + typedef enum _WDFFUNCENUM + { + WdfControlDeviceInitAllocateTableIndex = 25, + WdfDeviceInitSetDeviceTypeTableIndex = 66, + WdfDeviceInitAssignNameTableIndex = 67, + WdfDeviceInitSetCharacteristicsTableIndex = 70, + WdfDeviceInitSetFileObjectConfigTableIndex = 71, + WdfDeviceInitAssignWdmIrpPreprocessCallbackTableIndex = 73, + WdfDeviceCreateTableIndex = 75, + WdfDeviceCreateSymbolicLinkTableIndex = 80, + WdfDriverCreateTableIndex = 116, + WdfIoQueueCreateTableIndex = 152, + WdfObjectDeleteTableIndex = 208, + WdfFunctionTableNumEntries = 444, + } WDFFUNCENUM; + void usersim_initialize_wdf(); diff --git a/src/etw.cpp b/src/etw.cpp index 3a7ad1b..134e2b0 100644 --- a/src/etw.cpp +++ b/src/etw.cpp @@ -3,6 +3,7 @@ #include "platform.h" #include "usersim/etw.h" +#include "usersim/ex.h" typedef struct { diff --git a/src/ex.cpp b/src/ex.cpp index b0446be..797f07b 100644 --- a/src/ex.cpp +++ b/src/ex.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT #include "fault_injection.h" +#include "leak_detector.h" #include "platform.h" #include "kernel_um.h" #include "usersim/ex.h" @@ -15,6 +16,9 @@ // Ex* functions. +extern "C" size_t usersim_fuzzing_memory_limit = MAXSIZE_T; +usersim_leak_detector_ptr _usersim_leak_detector_ptr; + /*** * @brief This following class implements a mock of the Windows Kernel's rundown reference implementation. * 1) It uses a map to track the number of references to a given EX_RUNDOWN_REF structure. @@ -299,7 +303,7 @@ ExAllocatePoolUninitializedCPP( if (tag == 0) { KeBugCheckExCPP(BAD_POOL_CALLER, 0x9B, pool_type, number_of_bytes, 0); } - return usersim_allocate_with_tag(number_of_bytes, tag, false); + return usersim_allocate_with_tag(pool_type, number_of_bytes, tag, false); } _Ret_maybenull_ void* @@ -318,7 +322,170 @@ ExAllocatePoolWithTagCPP( if (tag == 0) { KeBugCheckExCPP(BAD_POOL_CALLER, 0x9B, pool_type, number_of_bytes, 0); } - return usersim_allocate_with_tag(number_of_bytes, tag, true); + return usersim_allocate_with_tag(pool_type, number_of_bytes, tag, true); +} + +#define USERSIM_CACHE_LINE_SIZE 64 + +typedef struct +{ + POOL_TYPE pool_type; + uint32_t tag; +} usersim_allocation_header_t; + +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* +usersim_allocate_with_tag( + _In_ __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE pool_type, size_t size, uint32_t tag, bool initialize) +{ + if (size == 0) { + KeBugCheckEx(BAD_POOL_CALLER, 0x00, 0, 0, 0); + } + if (size > usersim_fuzzing_memory_limit) { + return nullptr; + } + + if (usersim_fault_injection_inject_fault()) { + return nullptr; + } + + // Allocate space with a usersim_allocation_header_t prepended. + void* memory; + if (pool_type == NonPagedPoolNxCacheAligned) { + // The pointer we return has to be cache aligned so we allocate + // enough extra space to fill a cache line, and put the + // usersim_allocation_header_t at the end of that space. + size_t full_size = USERSIM_CACHE_LINE_SIZE + size; + uint8_t* pointer = (uint8_t*)_aligned_malloc(full_size, USERSIM_CACHE_LINE_SIZE); + if (pointer == nullptr) { + return nullptr; + } + memory = pointer + USERSIM_CACHE_LINE_SIZE; + } else { + size_t full_size = sizeof(usersim_allocation_header_t) + size; + uint8_t* pointer = (uint8_t*)calloc(full_size, 1); + if (pointer == nullptr) { + return nullptr; + } + memory = pointer + sizeof(usersim_allocation_header_t); + } + + // Do any initialization. + auto header = (usersim_allocation_header_t*)((uint8_t*)memory - sizeof(usersim_allocation_header_t)); + header->pool_type = pool_type; + header->tag = tag; + if (!initialize) { + // The calloc call always zero-initializes memory. To test + // returning uninitialized memory, we explicitly fill it with 0xcc. + memset(memory, 0xcc, size); + } + + if (memory && _usersim_leak_detector_ptr) { + _usersim_leak_detector_ptr->register_allocation(reinterpret_cast(memory), size); + } + + return memory; +} + +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* +usersim_reallocate( + _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size) +{ + return usersim_reallocate_with_tag(memory, old_size, new_size, 0); +} + +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* +usersim_reallocate_with_tag( + _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size, uint32_t tag) +{ + UNREFERENCED_PARAMETER(tag); + UNREFERENCED_PARAMETER(old_size); + + if (new_size > usersim_fuzzing_memory_limit) { + return nullptr; + } + + if (usersim_fault_injection_inject_fault()) { + return nullptr; + } + + void* p; + auto header = (usersim_allocation_header_t*)((uint8_t*)memory - sizeof(usersim_allocation_header_t)); + if (header->pool_type == NonPagedPoolNxCacheAligned) { + uint8_t* pointer = ((uint8_t*)memory) - USERSIM_CACHE_LINE_SIZE; + p = _aligned_realloc(pointer, USERSIM_CACHE_LINE_SIZE + new_size, USERSIM_CACHE_LINE_SIZE); + } else { + uint8_t* pointer = ((uint8_t*)memory) - sizeof(usersim_allocation_header_t); + p = realloc(pointer, sizeof(usersim_allocation_header_t) + new_size); + } + + if (p && (new_size > old_size)) { + memset(((char*)p) + old_size, 0, new_size - old_size); + } + + if (_usersim_leak_detector_ptr) { + _usersim_leak_detector_ptr->unregister_allocation(reinterpret_cast(memory)); + _usersim_leak_detector_ptr->register_allocation(reinterpret_cast(p), new_size); + } + + return p; +} + +__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate(size_t size) +{ + return usersim_allocate_with_tag(NonPagedPool, size, 'tset', true); +} + +void +usersim_free(_Frees_ptr_opt_ void* memory) +{ + if (memory == nullptr) { + return; + } + auto header = (usersim_allocation_header_t*)((uint8_t*)memory - sizeof(usersim_allocation_header_t)); + if (_usersim_leak_detector_ptr) { + _usersim_leak_detector_ptr->unregister_allocation(reinterpret_cast(memory)); + } + if (header->pool_type == NonPagedPoolNxCacheAligned) { + uint8_t* pointer = ((uint8_t*)memory) - USERSIM_CACHE_LINE_SIZE; + _aligned_free(pointer); + } else { + uint8_t* pointer = ((uint8_t*)memory) - sizeof(usersim_allocation_header_t); + free(pointer); + } +} + +__drv_allocatesMem(Mem) _Must_inspect_result_ +_Ret_writes_maybenull_(size) void* +usersim_allocate_cache_aligned(size_t size) +{ + if (size > usersim_fuzzing_memory_limit) { + return nullptr; + } + + if (usersim_fault_injection_inject_fault()) { + return nullptr; + } + + void* memory = _aligned_malloc(size, USERSIM_CACHE_LINE_SIZE); + if (memory) { + memset(memory, 0, size); + } + return memory; +} + +__drv_allocatesMem(Mem) _Must_inspect_result_ +_Ret_writes_maybenull_(size) void* +usersim_allocate_cache_aligned_with_tag(size_t size, uint32_t tag) +{ + UNREFERENCED_PARAMETER(tag); + + return usersim_allocate_cache_aligned(size); +} + +void +usersim_free_cache_aligned(_Frees_ptr_opt_ void* memory) +{ + _aligned_free(memory); } _Ret_maybenull_ void* @@ -409,4 +576,21 @@ void ExRaiseDatatypeMisalignment() { ExRaiseDatatypeMisalignmentCPP(); +} + +void +usersim_initialize_ex(bool leak_detector) +{ + if (leak_detector) { + _usersim_leak_detector_ptr = std::make_unique(); + } +} + +void +usersim_clean_up_ex() +{ + if (_usersim_leak_detector_ptr) { + _usersim_leak_detector_ptr->dump_leaks(); + _usersim_leak_detector_ptr.reset(); + } } \ No newline at end of file diff --git a/src/io.cpp b/src/io.cpp index 914f5df..9d9a8ee 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -3,6 +3,7 @@ #include "platform.h" #include "kernel_um.h" +#include "usersim/ex.h" #include "usersim/io.h" // Io* functions. @@ -117,3 +118,10 @@ _IRQL_requires_max_(DISPATCH_LEVEL) NTKERNELAPI PEPROCESS IoGetCurrentProcess(VO { return (PEPROCESS)GetCurrentProcess(); } + +_IRQL_requires_max_(DISPATCH_LEVEL) VOID +IofCompleteRequest(_In_ PIRP irp, _In_ CCHAR priority_boost) +{ + UNREFERENCED_PARAMETER(irp); + UNREFERENCED_PARAMETER(priority_boost); +} \ No newline at end of file diff --git a/src/ke.cpp b/src/ke.cpp index 0767864..51d456d 100644 --- a/src/ke.cpp +++ b/src/ke.cpp @@ -266,7 +266,7 @@ usersim_free_semaphores() for (auto handle : *g_usersim_semaphore_handles) { ::CloseHandle(handle); } - usersim_free(g_usersim_semaphore_handles); + delete g_usersim_semaphore_handles; g_usersim_semaphore_handles = nullptr; } } @@ -731,7 +731,7 @@ usersim_free_threadpool_timers() for (TP_TIMER* threadpool_timer : *g_usersim_threadpool_timers) { CloseThreadpoolTimer(threadpool_timer); } - usersim_free(g_usersim_threadpool_timers); + delete g_usersim_threadpool_timers; g_usersim_threadpool_timers = nullptr; } } diff --git a/src/kernel_um.h b/src/kernel_um.h index d2130c7..b87e2e8 100644 --- a/src/kernel_um.h +++ b/src/kernel_um.h @@ -42,6 +42,7 @@ extern "C" #define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) #define RPC_NT_CALL_FAILED ((NTSTATUS)0xC002001BL) #define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS)0xC000007BL) +#define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS)0xC0000183L) #define STATUS_TOO_MANY_NODES ((NTSTATUS)0xC000020EL) #define STATUS_GENERIC_COMMAND_FAILED ((NTSTATUS)0xC0150026L) #define STATUS_CONTENT_BLOCKED ((NTSTATUS)0xC0000804L) diff --git a/src/leak_detector.cpp b/src/leak_detector.cpp index 8416088..62b827b 100644 --- a/src/leak_detector.cpp +++ b/src/leak_detector.cpp @@ -3,6 +3,7 @@ #include "leak_detector.h" #include "symbol_decoder.h" +#include "usersim/ke.h" #include #include @@ -30,6 +31,9 @@ void _usersim_leak_detector::unregister_allocation(uintptr_t address) { std::unique_lock lock(_mutex); + if (!_allocations.contains(address)) { + KeBugCheck(0); + } _allocations.erase(address); } diff --git a/src/platform.h b/src/platform.h index 8cf1d10..e178fff 100644 --- a/src/platform.h +++ b/src/platform.h @@ -99,76 +99,6 @@ extern "C" void usersim_platform_terminate(); - /** - * @brief Allocate memory. - * @param[in] size Size of memory to allocate. - * @returns Pointer to memory block allocated, or null on failure. - */ - __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate(size_t size); - - /** - * @brief Allocate memory. - * @param[in] size Size of memory to allocate. - * @param[in] tag Pool tag to use. - * @param[in] initialize False to return "uninitialized" memory. - * @returns Pointer to memory block allocated, or null on failure. - */ - __drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_with_tag(size_t size, uint32_t tag, bool initialize); - - /** - * @brief Reallocate memory. - * @param[in] memory Allocation to be reallocated. - * @param[in] old_size Old size of memory to reallocate. - * @param[in] new_size New size of memory to reallocate. - * @returns Pointer to memory block allocated, or null on failure. - */ - __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate( - _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size); - - /** - * @brief Reallocate memory with tag. - * @param[in] memory Allocation to be reallocated. - * @param[in] old_size Old size of memory to reallocate. - * @param[in] new_size New size of memory to reallocate. - * @param[in] tag Pool tag to use. - * @returns Pointer to memory block allocated, or null on failure. - */ - __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate_with_tag( - _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size, uint32_t tag); - - /** - * @brief Free memory. - * @param[in] memory Allocation to be freed. - */ - void - usersim_free(_Frees_ptr_opt_ void* memory); - - /** - * @brief Allocate memory that has a starting address that is cache aligned. - * @param[in] size Size of memory to allocate - * @returns Pointer to memory block allocated, or null on failure. - */ - USERSIM_API - __drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned(size_t size); - - /** - * @brief Allocate memory that has a starting address that is cache aligned with tag. - * @param[in] size Size of memory to allocate - * @param[in] tag Pool tag to use. - * @returns Pointer to memory block allocated, or null on failure. - */ - __drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned_with_tag(size_t size, uint32_t tag); - - /** - * @brief Free memory that has a starting address that is cache aligned. - * @param[in] memory Allocation to be freed. - */ - void - usersim_free_cache_aligned(_Frees_ptr_opt_ void* memory); - typedef enum _usersim_page_protection { USERSIM_PAGE_PROTECT_READ_ONLY, @@ -775,22 +705,3 @@ extern "C" #ifdef __cplusplus } #endif - -#ifdef __cplusplus -#include -namespace usersim_helper { - -struct _usersim_free_functor -{ - void - operator()(void* memory) - { - usersim_free(memory); - } -}; - -typedef std::unique_ptr usersim_memory_ptr; - -} // namespace usersim_helper - -#endif diff --git a/src/platform_user.cpp b/src/platform_user.cpp index 304ff2c..d3128e6 100644 --- a/src/platform_user.cpp +++ b/src/platform_user.cpp @@ -37,12 +37,9 @@ bool _usersim_platform_is_preemptible = true; int32_t _usersim_platform_initiate_count = 0; extern "C" bool usersim_fuzzing_enabled = false; -extern "C" size_t usersim_fuzzing_memory_limit = MAXSIZE_T; static EX_RUNDOWN_REF _usersim_platform_preemptible_work_items_rundown; -usersim_leak_detector_ptr _usersim_leak_detector_ptr; - /** * @brief Environment variable to enable fault injection testing. * @@ -204,9 +201,9 @@ usersim_platform_initiate() try { _usersim_platform_maximum_group_count = GetMaximumProcessorGroupCount(); _usersim_platform_maximum_processor_count = GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS); - auto fault_injection_stack_depth = + bool fault_injection_stack_depth = _get_environment_variable_as_size_t(USERSIM_FAULT_INJECTION_SIMULATION_ENVIRONMENT_VARIABLE_NAME); - auto leak_detector = _get_environment_variable_as_bool(USERSIM_MEMORY_LEAK_DETECTION_ENVIRONMENT_VARIABLE_NAME); + bool leak_detector = _get_environment_variable_as_bool(USERSIM_MEMORY_LEAK_DETECTION_ENVIRONMENT_VARIABLE_NAME); if (fault_injection_stack_depth || leak_detector) { _usersim_symbol_decoder_initialize(); } @@ -218,9 +215,7 @@ usersim_platform_initiate() usersim_fuzzing_enabled = true; } - if (leak_detector) { - _usersim_leak_detector_ptr = std::make_unique(); - } + usersim_initialize_ex(leak_detector); result = usersim_initialize_irql(); if (result != STATUS_SUCCESS) { @@ -269,10 +264,7 @@ usersim_platform_terminate() usersim_clean_up_dpcs(); usersim_clean_up_irql(); _clean_up_thread_pool(); - if (_usersim_leak_detector_ptr) { - _usersim_leak_detector_ptr->dump_leaks(); - _usersim_leak_detector_ptr.reset(); - } + usersim_clean_up_ex(); int32_t count = InterlockedDecrement((volatile long*)&_usersim_platform_initiate_count); if (count < 0) { @@ -294,114 +286,6 @@ usersim_get_code_integrity_state(_Out_ usersim_code_integrity_state_t* state) USERSIM_RETURN_RESULT(STATUS_SUCCESS); } -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate(size_t size) -{ - return usersim_allocate_with_tag(size, 'tset', true); -} - -__drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_with_tag(size_t size, uint32_t tag, bool initialize) -{ - UNREFERENCED_PARAMETER(tag); - if (size == 0) { - KeBugCheckEx(BAD_POOL_CALLER, 0x00, 0, 0, 0); - } - if (size > usersim_fuzzing_memory_limit) { - return nullptr; - } - - if (usersim_fault_injection_inject_fault()) { - return nullptr; - } - - void* memory = calloc(size, 1); - if (!initialize) { - // The calloc call always zero-initializes memory. To test - // returning uninitialized memory, we explicitly fill it with 0xcc. - memset(memory, 0xcc, size); - } - - if (memory && _usersim_leak_detector_ptr) { - _usersim_leak_detector_ptr->register_allocation(reinterpret_cast(memory), size); - } - - return memory; -} - -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate( - _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size) -{ - UNREFERENCED_PARAMETER(old_size); - if (new_size > usersim_fuzzing_memory_limit) { - return nullptr; - } - - if (usersim_fault_injection_inject_fault()) { - return nullptr; - } - - void* p = realloc(memory, new_size); - if (p && (new_size > old_size)) { - memset(((char*)p) + old_size, 0, new_size - old_size); - } - - if (_usersim_leak_detector_ptr) { - _usersim_leak_detector_ptr->unregister_allocation(reinterpret_cast(memory)); - _usersim_leak_detector_ptr->register_allocation(reinterpret_cast(p), new_size); - } - - return p; -} - -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate_with_tag( - _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size, uint32_t tag) -{ - UNREFERENCED_PARAMETER(tag); - - return usersim_reallocate(memory, old_size, new_size); -} - -void -usersim_free(_Frees_ptr_opt_ void* memory) -{ - if (_usersim_leak_detector_ptr) { - _usersim_leak_detector_ptr->unregister_allocation(reinterpret_cast(memory)); - } - free(memory); -} - -__drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned(size_t size) -{ - if (size > usersim_fuzzing_memory_limit) { - return nullptr; - } - - if (usersim_fault_injection_inject_fault()) { - return nullptr; - } - - void* memory = _aligned_malloc(size, USERSIM_CACHE_LINE_SIZE); - if (memory) { - memset(memory, 0, size); - } - return memory; -} - -__drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned_with_tag(size_t size, uint32_t tag) -{ - UNREFERENCED_PARAMETER(tag); - - return usersim_allocate_cache_aligned(size); -} - -void -usersim_free_cache_aligned(_Frees_ptr_opt_ void* memory) -{ - _aligned_free(memory); -} - struct _usersim_ring_descriptor { void* primary_view; diff --git a/src/se.cpp b/src/se.cpp index 59b7ec2..c4ada13 100644 --- a/src/se.cpp +++ b/src/se.cpp @@ -4,6 +4,7 @@ #include "fault_injection.h" #include "kernel_um.h" #include "platform.h" +#include "usersim/ex.h" #include "usersim/se.h" #include "utilities.h" #include diff --git a/src/wdf.cpp b/src/wdf.cpp index 8195a50..1eb609b 100644 --- a/src/wdf.cpp +++ b/src/wdf.cpp @@ -1,10 +1,13 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT +#include "fault_injection.h" #include "framework.h" +#include "platform.h" +#include "usersim/ex.h" #include "usersim/wdf.h" -static WDFDRIVER g_CurrentDriver = {}; +WDF_DRIVER_GLOBALS g_UsersimWdfDriverGlobals = {0}; static NTSTATUS _WdfDriverCreate( @@ -15,14 +18,19 @@ _WdfDriverCreate( _In_ PWDF_DRIVER_CONFIG driver_config, _Out_opt_ WDFDRIVER* driver) { - UNREFERENCED_PARAMETER(driver_globals); - UNREFERENCED_PARAMETER(driver_object); UNREFERENCED_PARAMETER(registry_path); UNREFERENCED_PARAMETER(driver_attributes); - g_CurrentDriver.config = *driver_config; + if (driver_globals != &g_UsersimWdfDriverGlobals) { + return STATUS_INVALID_PARAMETER; + } + if (driver_globals->Driver != nullptr) { + return STATUS_DRIVER_INTERNAL_ERROR; + } + g_UsersimWdfDriverGlobals.Driver = driver_object; + driver_object->config = *driver_config; if (driver != nullptr) { - *driver = g_CurrentDriver; + *driver = driver_object; } return STATUS_SUCCESS; } @@ -30,34 +38,226 @@ _WdfDriverCreate( static NTSTATUS _WdfDeviceCreate( _In_ WDF_DRIVER_GLOBALS* driver_globals, - _Inout_ PWDFDEVICE_INIT* device_init, _In_opt_ PWDF_OBJECT_ATTRIBUTES device_attributes, _Out_ WDFDEVICE* device) + _Inout_ PWDFDEVICE_INIT* device_init, + _In_opt_ PWDF_OBJECT_ATTRIBUTES device_attributes, + _Out_ WDFDEVICE* device) { - UNREFERENCED_PARAMETER(driver_globals); UNREFERENCED_PARAMETER(device_init); UNREFERENCED_PARAMETER(device_attributes); + if (driver_globals != &g_UsersimWdfDriverGlobals) { + return STATUS_INVALID_PARAMETER; + } + if (usersim_fault_injection_inject_fault()) { + return STATUS_INSUFFICIENT_RESOURCES; + } + *device = nullptr; return STATUS_SUCCESS; } -WDF_DRIVER_GLOBALS g_UsersimWdfDriverGlobals = { - .Driver = g_CurrentDriver, -}; +typedef struct _WDF_FILEOBJECT_CONFIG WDF_FILEOBJECT_CONFIG, *PWDF_FILEOBJECT_CONFIG; +typedef struct _FN_WDFDEVICE_WDM_IRP_PREPROCESS FN_WDFDEVICE_WDM_IRP_PREPROCESS, *PFN_WDFDEVICE_WDM_IRP_PREPROCESS; +#define IRP_MJ_MAXIMUM_FUNCTION 0x1b + +typedef struct _WDFDEVICE_INIT +{ + DEVICE_TYPE device_type; + ULONG device_characteristics; + UNICODE_STRING device_name; + PWDF_FILEOBJECT_CONFIG file_object_config; + PWDF_OBJECT_ATTRIBUTES file_object_attributes; + PFN_WDFDEVICE_WDM_IRP_PREPROCESS evt_device_wdm_irp_preprocess; + PUCHAR minor_functions[IRP_MJ_MAXIMUM_FUNCTION]; + ULONG num_minor_functions[IRP_MJ_MAXIMUM_FUNCTION]; +} WDFDEVICE_INIT; + +static +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +PWDFDEVICE_INIT +_WdfControlDeviceInitAllocate( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ WDFDRIVER driver, + _In_ CONST UNICODE_STRING* sddl_string) +{ + UNREFERENCED_PARAMETER(driver_globals); + UNREFERENCED_PARAMETER(driver); + UNREFERENCED_PARAMETER(sddl_string); + + PWDFDEVICE_INIT device_init = (PWDFDEVICE_INIT)usersim_allocate(sizeof(*device_init)); + return device_init; +} + +static +_IRQL_requires_max_(DISPATCH_LEVEL) VOID +_WdfDeviceInitSetDeviceType( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_ DEVICE_TYPE device_type) +{ + UNREFERENCED_PARAMETER(driver_globals); + device_init->device_type = device_type; +} + +static +_IRQL_requires_max_(DISPATCH_LEVEL) VOID +_WdfDeviceInitSetCharacteristics( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_ ULONG device_characteristics, + _In_ BOOLEAN or_in_values) +{ + UNREFERENCED_PARAMETER(driver_globals); + if (!or_in_values) { + device_init->device_characteristics = 0; + } + device_init->device_characteristics |= device_characteristics; +} + +static _Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +_WdfDeviceInitAssignName( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_opt_ PCUNICODE_STRING device_name) +{ + if (driver_globals != &g_UsersimWdfDriverGlobals) { + return STATUS_INVALID_PARAMETER; + } + if (usersim_fault_injection_inject_fault()) { + return STATUS_INSUFFICIENT_RESOURCES; + } + if (device_name != nullptr) { + device_init->device_name = *device_name; + } + return STATUS_SUCCESS; +} -typedef enum _WDFFUNCENUM +static +_IRQL_requires_max_(DISPATCH_LEVEL) VOID +_WdfDeviceInitSetFileObjectConfig( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_ PWDF_FILEOBJECT_CONFIG file_object_config, + _In_opt_ PWDF_OBJECT_ATTRIBUTES file_object_attributes) { - WdfDeviceCreateTableIndex = 75, - WdfDriverCreateTableIndex = 116, - WdfFunctionTableNumEntries = 444, -} WDFFUNCENUM; + UNREFERENCED_PARAMETER(driver_globals); + device_init->file_object_config = file_object_config; + device_init->file_object_attributes = file_object_attributes; +} + +static _Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +_WdfDeviceInitAssignWdmIrpPreprocessCallback( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_ PFN_WDFDEVICE_WDM_IRP_PREPROCESS evt_device_wdm_irp_preprocess, + _In_ UCHAR major_function, + _When_(num_minor_functions > 0, _In_reads_bytes_(num_minor_functions)) _When_(num_minor_functions == 0, _In_opt_) + PUCHAR minor_functions, + _In_ ULONG num_minor_functions) +{ + if (driver_globals != &g_UsersimWdfDriverGlobals) { + return STATUS_INVALID_PARAMETER; + } + if (device_init->minor_functions[major_function] != nullptr) { + return STATUS_INVALID_DEVICE_REQUEST; + } + if (major_function >= IRP_MJ_MAXIMUM_FUNCTION) { + return STATUS_INVALID_PARAMETER; + } + if (usersim_fault_injection_inject_fault()) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + device_init->evt_device_wdm_irp_preprocess = evt_device_wdm_irp_preprocess; + device_init->minor_functions[major_function] = minor_functions; + device_init->num_minor_functions[major_function] = num_minor_functions; + return STATUS_SUCCESS; +} + +static _Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +_WdfDeviceCreateSymbolicLink( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ WDFDEVICE device, + _In_ PCUNICODE_STRING symbolic_link_name) +{ + UNREFERENCED_PARAMETER(device); + UNREFERENCED_PARAMETER(symbolic_link_name); + + if (driver_globals != &g_UsersimWdfDriverGlobals) { + return STATUS_INVALID_PARAMETER; + } + if (usersim_fault_injection_inject_fault()) { + return STATUS_INSUFFICIENT_RESOURCES; + } + return STATUS_SUCCESS; +} + +typedef struct _WDF_IO_QUEUE_CONFIG WDF_IO_QUEUE_CONFIG, *PWDF_IO_QUEUE_CONFIG; +typedef struct _WDFQUEUE +{ + int tbd; +} WDFQUEUE; + +static +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +_WdfIoQueueCreate( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ WDFDEVICE device, + _In_ PWDF_IO_QUEUE_CONFIG config, + _In_opt_ PWDF_OBJECT_ATTRIBUTES queue_attributes, + _Out_opt_ WDFQUEUE* queue) +{ + UNREFERENCED_PARAMETER(device); + UNREFERENCED_PARAMETER(config); + UNREFERENCED_PARAMETER(queue_attributes); + + if (driver_globals != &g_UsersimWdfDriverGlobals) { + return STATUS_INVALID_PARAMETER; + } + if (usersim_fault_injection_inject_fault()) { + return STATUS_INSUFFICIENT_RESOURCES; + } + if (queue != nullptr) { + memset(queue, 0, sizeof(*queue)); + } + return STATUS_SUCCESS; +} + +typedef HANDLE WDFOBJECT; + +_IRQL_requires_max_(DISPATCH_LEVEL) VOID +_WdfObjectDelete(_In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ WDFOBJECT object) +{ + UNREFERENCED_PARAMETER(driver_globals); + UNREFERENCED_PARAMETER(object); +} WDFFUNC g_UsersimWdfFunctions[WdfFunctionTableNumEntries]; void usersim_initialize_wdf() { + g_UsersimWdfFunctions[WdfControlDeviceInitAllocateTableIndex] = (WDFFUNC)_WdfControlDeviceInitAllocate; + g_UsersimWdfFunctions[WdfDeviceInitSetDeviceTypeTableIndex] = (WDFFUNC)_WdfDeviceInitSetDeviceType; + g_UsersimWdfFunctions[WdfDeviceInitAssignNameTableIndex] = (WDFFUNC)_WdfDeviceInitAssignName; + g_UsersimWdfFunctions[WdfDeviceInitSetCharacteristicsTableIndex] = (WDFFUNC)_WdfDeviceInitSetCharacteristics; + g_UsersimWdfFunctions[WdfDeviceInitSetFileObjectConfigTableIndex] = (WDFFUNC)_WdfDeviceInitSetFileObjectConfig; + g_UsersimWdfFunctions[WdfDeviceInitAssignWdmIrpPreprocessCallbackTableIndex] = + (WDFFUNC)_WdfDeviceInitAssignWdmIrpPreprocessCallback; g_UsersimWdfFunctions[WdfDeviceCreateTableIndex] = (WDFFUNC)_WdfDeviceCreate; + g_UsersimWdfFunctions[WdfDeviceCreateSymbolicLinkTableIndex] = (WDFFUNC)_WdfDeviceCreateSymbolicLink; g_UsersimWdfFunctions[WdfDriverCreateTableIndex] = (WDFFUNC)_WdfDriverCreate; + g_UsersimWdfFunctions[WdfIoQueueCreateTableIndex] = (WDFFUNC)_WdfIoQueueCreate; + g_UsersimWdfFunctions[WdfObjectDeleteTableIndex] = (WDFFUNC)_WdfObjectDelete; } extern "C" @@ -69,7 +269,7 @@ extern "C" } WDFDRIVER -WdfGetDriver() { return g_CurrentDriver; } +WdfGetDriver() { return g_UsersimWdfDriverGlobals.Driver; } void WDF_DRIVER_CONFIG_INIT(_Out_ PWDF_DRIVER_CONFIG config, _In_opt_ PFN_WDF_DRIVER_DEVICE_ADD evt_driver_device_add) diff --git a/tests/ex_test.cpp b/tests/ex_test.cpp index 633f7a2..4de3bd9 100644 --- a/tests/ex_test.cpp +++ b/tests/ex_test.cpp @@ -10,12 +10,21 @@ TEST_CASE("ExAllocatePool", "[ex]") { + // Try an allocation that need not be cache aligned. uint64_t* buffer = (uint64_t*)ExAllocatePoolUninitialized(NonPagedPool, 8, 'tset'); REQUIRE(buffer != nullptr); REQUIRE(*buffer != 0); *buffer = 0; ExFreePool(buffer); + // Try an allocation that must be cache aligned. + buffer = (uint64_t*)ExAllocatePoolUninitialized(NonPagedPoolNxCacheAligned, 8, 'tset'); + REQUIRE(buffer != nullptr); + REQUIRE(*buffer != 0); + REQUIRE((((uintptr_t)buffer) % 64) == 0); + *buffer = 0; + ExFreePool(buffer); + buffer = (uint64_t*)ExAllocatePoolWithTag(NonPagedPool, 8, 'tset'); REQUIRE(buffer != nullptr); REQUIRE(*buffer == 0); diff --git a/tests/wdf_test.cpp b/tests/wdf_test.cpp index f93869e..093a62c 100644 --- a/tests/wdf_test.cpp +++ b/tests/wdf_test.cpp @@ -7,6 +7,7 @@ #else #include #endif +#include "usersim/wdf.h" TEST_CASE("DriverEntry", "[wdf]") { @@ -15,3 +16,30 @@ TEST_CASE("DriverEntry", "[wdf]") FreeLibrary(module); } + +extern "C" +{ + __declspec(dllimport) const WDFFUNC* UsersimWdfFunctions; + __declspec(dllimport) PWDF_DRIVER_GLOBALS UsersimWdfDriverGlobals; +} + +TEST_CASE("WdfDriverCreate", "[wdf]") +{ + DRIVER_OBJECT driver_object = {0}; + WDF_DRIVER_CONFIG config; + WDF_DRIVER_CONFIG_INIT(&config, nullptr); + + typedef NTSTATUS(FN_WdfDriverCreate)( + _In_ WDF_DRIVER_GLOBALS* driver_globals, + _In_ PDRIVER_OBJECT driver_object, + _In_ PCUNICODE_STRING registry_path, + _In_opt_ PWDF_OBJECT_ATTRIBUTES driver_attributes, + _In_ PWDF_DRIVER_CONFIG driver_config, + _Out_opt_ WDFDRIVER* driver); + FN_WdfDriverCreate* WdfDriverCreate = (FN_WdfDriverCreate*)UsersimWdfFunctions[WdfDriverCreateTableIndex]; + WDFDRIVER driver; + NTSTATUS status = WdfDriverCreate(UsersimWdfDriverGlobals, &driver_object, nullptr, nullptr, &config, &driver); + REQUIRE(status == STATUS_SUCCESS); + REQUIRE(driver == &driver_object); + UsersimWdfDriverGlobals->Driver = nullptr; +} diff --git a/usersim_dll_skeleton/dll_skeleton.c b/usersim_dll_skeleton/dll_skeleton.c index 40b94ae..0711440 100644 --- a/usersim_dll_skeleton/dll_skeleton.c +++ b/usersim_dll_skeleton/dll_skeleton.c @@ -22,11 +22,6 @@ __declspec(dllimport) const WDFFUNC* UsersimWdfFunctions; PWDF_DRIVER_GLOBALS WdfDriverGlobals = NULL; const WDFFUNC* WdfFunctions_01015 = NULL; - struct _driver_object - { - int dummy; - }; - NTSTATUS UsersimStartDriver() { @@ -41,10 +36,11 @@ const WDFFUNC* WdfFunctions_01015 = NULL; void UsersimStopDriver() { - WDFDRIVER driver = WdfDriverGlobals->Driver; - if (driver.config.EvtDriverUnload != NULL) { - driver.config.EvtDriverUnload(driver); + DRIVER_OBJECT* driver = (DRIVER_OBJECT*)WdfDriverGlobals->Driver; + if (driver->config.EvtDriverUnload != NULL) { + driver->config.EvtDriverUnload(driver); } + WdfDriverGlobals->Driver = NULL; } BOOL APIENTRY From aafe8ba7ac629db9371fcb4eded88c8cdb437f24 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Sat, 5 Aug 2023 09:41:59 -0700 Subject: [PATCH 2/4] Add some WDF tests Also make more kernel functions callable from C code Signed-off-by: Dave Thaler --- inc/usersim/ex.h | 145 ++++++++++++++++++++--------------------- inc/usersim/fwp_test.h | 11 +++- inc/usersim/io.h | 2 +- inc/usersim/rtl.h | 10 +-- inc/usersim/wdf.h | 101 ++++++++++++++++++++++++++-- src/ex.cpp | 1 + src/ndis.h | 35 ++++++---- src/wdf.cpp | 47 ++++++++----- tests/wdf_test.cpp | 114 ++++++++++++++++++++++++++++---- 9 files changed, 339 insertions(+), 127 deletions(-) diff --git a/inc/usersim/ex.h b/inc/usersim/ex.h index cb11664..a78d1a5 100644 --- a/inc/usersim/ex.h +++ b/inc/usersim/ex.h @@ -184,6 +184,77 @@ extern "C" USERSIM_API void ExRaiseDatatypeMisalignment(); + /** + * @brief Allocate memory. + * @param[in] pool_type Pool type to use. + * @param[in] size Size of memory to allocate. + * @param[in] tag Pool tag to use. + * @param[in] initialize False to return "uninitialized" memory. + * @returns Pointer to memory block allocated, or null on failure. + */ + __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate_with_tag( + _In_ __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE pool_type, size_t size, uint32_t tag, bool initialize); + + /** + * @brief Allocate memory. + * @param[in] size Size of memory to allocate. + * @returns Pointer to memory block allocated, or null on failure. + */ + __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate(size_t size); + + /** + * @brief Reallocate memory. + * @param[in] memory Allocation to be reallocated. + * @param[in] old_size Old size of memory to reallocate. + * @param[in] new_size New size of memory to reallocate. + * @returns Pointer to memory block allocated, or null on failure. + */ + __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate( + _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size); + + /** + * @brief Reallocate memory with tag. + * @param[in] memory Allocation to be reallocated. + * @param[in] old_size Old size of memory to reallocate. + * @param[in] new_size New size of memory to reallocate. + * @param[in] tag Pool tag to use. + * @returns Pointer to memory block allocated, or null on failure. + */ + __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate_with_tag( + _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size, uint32_t tag); + + /** + * @brief Free memory. + * @param[in] memory Allocation to be freed. + */ + void + usersim_free(_Frees_ptr_opt_ void* memory); + + /** + * @brief Allocate memory that has a starting address that is cache aligned. + * @param[in] size Size of memory to allocate + * @returns Pointer to memory block allocated, or null on failure. + */ + USERSIM_API + __drv_allocatesMem(Mem) _Must_inspect_result_ + _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned(size_t size); + + /** + * @brief Allocate memory that has a starting address that is cache aligned with tag. + * @param[in] size Size of memory to allocate + * @param[in] tag Pool tag to use. + * @returns Pointer to memory block allocated, or null on failure. + */ + __drv_allocatesMem(Mem) _Must_inspect_result_ + _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned_with_tag(size_t size, uint32_t tag); + + /** + * @brief Free memory that has a starting address that is cache aligned. + * @param[in] memory Allocation to be freed. + */ + void + usersim_free_cache_aligned(_Frees_ptr_opt_ void* memory); + #if defined(__cplusplus) } @@ -198,80 +269,6 @@ USERSIM_API _Ret_maybenull_ void* ExAllocatePoolWithTagCPP( _In_ __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE pool_type, SIZE_T number_of_bytes, ULONG tag); -/** - * @brief Allocate memory. - * @param[in] pool_type Pool type to use. - * @param[in] size Size of memory to allocate. - * @param[in] tag Pool tag to use. - * @param[in] initialize False to return "uninitialized" memory. - * @returns Pointer to memory block allocated, or null on failure. - */ -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate_with_tag( - _In_ __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE pool_type, - size_t size, - uint32_t tag, - bool initialize); - - /** - * @brief Allocate memory. - * @param[in] size Size of memory to allocate. - * @returns Pointer to memory block allocated, or null on failure. - */ -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(size) void* usersim_allocate(size_t size); - -/** - * @brief Reallocate memory. - * @param[in] memory Allocation to be reallocated. - * @param[in] old_size Old size of memory to reallocate. - * @param[in] new_size New size of memory to reallocate. - * @returns Pointer to memory block allocated, or null on failure. - */ -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate( - _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size); - -/** - * @brief Reallocate memory with tag. - * @param[in] memory Allocation to be reallocated. - * @param[in] old_size Old size of memory to reallocate. - * @param[in] new_size New size of memory to reallocate. - * @param[in] tag Pool tag to use. - * @returns Pointer to memory block allocated, or null on failure. - */ -__drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_writes_maybenull_(new_size) void* usersim_reallocate_with_tag( - _In_ _Post_invalid_ void* memory, size_t old_size, size_t new_size, uint32_t tag); - -/** - * @brief Free memory. - * @param[in] memory Allocation to be freed. - */ -void -usersim_free(_Frees_ptr_opt_ void* memory); - -/** - * @brief Allocate memory that has a starting address that is cache aligned. - * @param[in] size Size of memory to allocate - * @returns Pointer to memory block allocated, or null on failure. - */ -USERSIM_API -__drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned(size_t size); - -/** - * @brief Allocate memory that has a starting address that is cache aligned with tag. - * @param[in] size Size of memory to allocate - * @param[in] tag Pool tag to use. - * @returns Pointer to memory block allocated, or null on failure. - */ -__drv_allocatesMem(Mem) _Must_inspect_result_ - _Ret_writes_maybenull_(size) void* usersim_allocate_cache_aligned_with_tag(size_t size, uint32_t tag); - -/** - * @brief Free memory that has a starting address that is cache aligned. - * @param[in] memory Allocation to be freed. - */ -void -usersim_free_cache_aligned(_Frees_ptr_opt_ void* memory); - USERSIM_API _Ret_maybenull_ void* ExAllocatePoolUninitializedCPP(_In_ POOL_TYPE pool_type, _In_ size_t number_of_bytes, _In_ unsigned long tag); diff --git a/inc/usersim/fwp_test.h b/inc/usersim/fwp_test.h index 02b87f6..b062609 100644 --- a/inc/usersim/fwp_test.h +++ b/inc/usersim/fwp_test.h @@ -7,6 +7,11 @@ #include #include +#if defined(__cplusplus) +extern "C" +{ +#endif + typedef struct _fwp_classify_parameters { ADDRESS_FAMILY family; @@ -51,4 +56,8 @@ usersim_fwp_sock_ops_v6(_In_ fwp_classify_parameters_t* parameters); USERSIM_API void usersim_fwp_set_sublayer_guids( - _In_ const GUID& default_sublayer, _In_ const GUID& connect_v4_sublayer, _In_ const GUID& connect_v6_sublayer); \ No newline at end of file + _In_ const GUID& default_sublayer, _In_ const GUID& connect_v4_sublayer, _In_ const GUID& connect_v6_sublayer); + +#if defined(__cplusplus) +} +#endif diff --git a/inc/usersim/io.h b/inc/usersim/io.h index 331ebb8..3b8fa0e 100644 --- a/inc/usersim/io.h +++ b/inc/usersim/io.h @@ -25,7 +25,7 @@ extern "C" typedef struct _DEVICE_OBJECT DEVICE_OBJECT; - typedef struct _DRIVER_OBJECT DRIVER_OBJECT; + typedef struct _DRIVER_OBJECT DRIVER_OBJECT, *PDRIVER_OBJECT; typedef struct _IO_WORKITEM IO_WORKITEM, *PIO_WORKITEM; diff --git a/inc/usersim/rtl.h b/inc/usersim/rtl.h index 3ac8f67..b59e3b3 100644 --- a/inc/usersim/rtl.h +++ b/inc/usersim/rtl.h @@ -145,14 +145,16 @@ extern "C" _Out_ PSTRING destination_string, _In_opt_ __drv_aliasesMem PCSTR source_string); - _IRQL_requires_max_(DISPATCH_LEVEL) _At_(DestinationString->Buffer, _Post_equal_to_(SourceString)) - _At_(DestinationString->Length, _Post_equal_to_(_String_length_(SourceString) * sizeof(WCHAR))) - _At_(DestinationString->MaximumLength, _Post_equal_to_((_String_length_(SourceString) + 1) * sizeof(WCHAR))) + _IRQL_requires_max_(DISPATCH_LEVEL) _At_(destination_string->Buffer, _Post_equal_to_(source_string)) + _At_(destination_string->Length, _Post_equal_to_(_String_length_(source_string) * sizeof(WCHAR))) + _At_(destination_string->MaximumLength, _Post_equal_to_((_String_length_(source_string) + 1) * sizeof(WCHAR))) USERSIM_API VOID NTAPI RtlInitUnicodeString( - _Out_ PCUNICODE_STRING destination_string, + _Out_ PUNICODE_STRING destination_string, _In_opt_z_ __drv_aliasesMem PCWSTR source_string); + typedef struct _object_attributes OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + // Include Rtl* implementations from ntdll.lib. #pragma comment(lib, "ntdll.lib") diff --git a/inc/usersim/wdf.h b/inc/usersim/wdf.h index 1335744..dd6744d 100644 --- a/inc/usersim/wdf.h +++ b/inc/usersim/wdf.h @@ -5,6 +5,7 @@ // implemented in usersim.dll, and can be used by unit tests. #pragma once #include "usersim/common.h" +#include "usersim/io.h" // For IRP #include "usersim/rtl.h" // For UNICODE_STRING #if defined(__cplusplus) @@ -15,14 +16,15 @@ extern "C" typedef HANDLE WDFDEVICE; typedef HANDLE WDFDRIVER; - typedef struct _WDF_OBJECT_ATTRIBUTES WDF_OBJECT_ATTRIBUTES, *PWDF_OBJECT_ATTRIBUTES; + typedef struct _WDF_OBJECT_ATTRIBUTES + { + int SynchronizationScope; + } WDF_OBJECT_ATTRIBUTES, *PWDF_OBJECT_ATTRIBUTES; typedef struct _WDFDEVICE_INIT WDFDEVICE_INIT, *PWDFDEVICE_INIT; #define WDF_NO_OBJECT_ATTRIBUTES 0 #define WDF_NO_HANDLE 0 - typedef struct _driver_object DRIVER_OBJECT, *PDRIVER_OBJECT; - typedef NTSTATUS(DRIVER_INITIALIZE)(_In_ PDRIVER_OBJECT driver_object, _In_ PUNICODE_STRING registry_path); typedef struct _WDFDEVICE_INIT WDFDEVICE_INIT, *PWDFDEVICE_INIT; @@ -42,7 +44,7 @@ extern "C" ULONG DriverPoolTag; } WDF_DRIVER_CONFIG, *PWDF_DRIVER_CONFIG; - struct _driver_object + struct _DRIVER_OBJECT { WDF_DRIVER_CONFIG config; }; @@ -76,9 +78,100 @@ extern "C" void WDF_DRIVER_CONFIG_INIT(_Out_ PWDF_DRIVER_CONFIG config, _In_opt_ PFN_WDF_DRIVER_DEVICE_ADD evt_driver_device_add); + typedef NTSTATUS(WdfDriverCreate_t)( + _In_ WDF_DRIVER_GLOBALS* driver_globals, + _In_ PDRIVER_OBJECT driver_object, + _In_ PCUNICODE_STRING registry_path, + _In_opt_ PWDF_OBJECT_ATTRIBUTES driver_attributes, + _In_ PWDF_DRIVER_CONFIG driver_config, + _Out_opt_ WDFDRIVER* driver); + + typedef NTSTATUS(WdfDeviceCreate_t)( + _In_ WDF_DRIVER_GLOBALS* driver_globals, + _Inout_ PWDFDEVICE_INIT* device_init, + _In_opt_ PWDF_OBJECT_ATTRIBUTES device_attributes, + _Out_ WDFDEVICE* device); + + typedef _IRQL_requires_max_(DISPATCH_LEVEL) + VOID(WdfDeviceInitFree_t)(_In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ PWDFDEVICE_INIT device_init); + + typedef _Must_inspect_result_ _IRQL_requires_max_(PASSIVE_LEVEL) PWDFDEVICE_INIT(WdfControlDeviceInitAllocate_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ WDFDRIVER driver, + _In_ CONST UNICODE_STRING* sddl_string); + + typedef _IRQL_requires_max_(DISPATCH_LEVEL) VOID(WdfDeviceInitSetDeviceType_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + DEVICE_TYPE device_type); + +#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 +#define FILE_DEVICE_SECURE_OPEN 0x00000100 + + typedef _IRQL_requires_max_(DISPATCH_LEVEL) VOID(WdfDeviceInitSetCharacteristics_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + ULONG device_characteristics, + BOOLEAN or_in_values); + + typedef _Must_inspect_result_ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS (WdfDeviceInitAssignName_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_opt_ PCUNICODE_STRING device_name); + + typedef struct _WDF_FILEOBJECT_CONFIG + { + int unused; + } WDF_FILEOBJECT_CONFIG, *PWDF_FILEOBJECT_CONFIG; + + typedef _IRQL_requires_max_(DISPATCH_LEVEL) VOID (WdfDeviceInitSetFileObjectConfig_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_ PWDF_FILEOBJECT_CONFIG file_object_config, + _In_opt_ PWDF_OBJECT_ATTRIBUTES file_object_attributes); + + + typedef NTSTATUS(FN_WDFDEVICE_WDM_IRP_PREPROCESS)(_In_ WDFDEVICE device, _Inout_ IRP* irp); + typedef FN_WDFDEVICE_WDM_IRP_PREPROCESS* PFN_WDFDEVICE_WDM_IRP_PREPROCESS; + +#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a + + typedef _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS (WdfDeviceInitAssignWdmIrpPreprocessCallback_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ PWDFDEVICE_INIT device_init, + _In_ PFN_WDFDEVICE_WDM_IRP_PREPROCESS evt_device_wdm_irp_preprocess, + UCHAR major_function, + _When_(num_minor_functions > 0, _In_reads_bytes_(num_minor_functions)) + _When_(num_minor_functions == 0, _In_opt_) PUCHAR minor_functions, + ULONG num_minor_functions); + + typedef _Must_inspect_result_ _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS (WdfDeviceCreateSymbolicLink_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ WDFDEVICE device, + _In_ PCUNICODE_STRING symbolic_link_name); + + typedef struct _WDF_IO_QUEUE_CONFIG + { + int unused; + } WDF_IO_QUEUE_CONFIG, *PWDF_IO_QUEUE_CONFIG; + typedef HANDLE WDFQUEUE; + + typedef _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS (WdfIoQueueCreate_t)( + _In_ PWDF_DRIVER_GLOBALS driver_globals, + _In_ WDFDEVICE device, + _In_ PWDF_IO_QUEUE_CONFIG config, + _In_opt_ PWDF_OBJECT_ATTRIBUTES queue_attributes, + _Out_opt_ WDFQUEUE* queue); + + typedef HANDLE WDFOBJECT; + + typedef _IRQL_requires_max_(DISPATCH_LEVEL) + VOID(WdfObjectDelete_t)(_In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ WDFOBJECT object); + typedef enum _WDFFUNCENUM { WdfControlDeviceInitAllocateTableIndex = 25, + WdfDeviceInitFreeTableIndex = 54, WdfDeviceInitSetDeviceTypeTableIndex = 66, WdfDeviceInitAssignNameTableIndex = 67, WdfDeviceInitSetCharacteristicsTableIndex = 70, diff --git a/src/ex.cpp b/src/ex.cpp index 797f07b..3c95244 100644 --- a/src/ex.cpp +++ b/src/ex.cpp @@ -354,6 +354,7 @@ usersim_allocate_with_tag( // The pointer we return has to be cache aligned so we allocate // enough extra space to fill a cache line, and put the // usersim_allocation_header_t at the end of that space. + // TODO: move logic into usersim_allocate_cache_aligned_with_tag(). size_t full_size = USERSIM_CACHE_LINE_SIZE + size; uint8_t* pointer = (uint8_t*)_aligned_malloc(full_size, USERSIM_CACHE_LINE_SIZE); if (pointer == nullptr) { diff --git a/src/ndis.h b/src/ndis.h index c27e1aa..2d4f4fd 100644 --- a/src/ndis.h +++ b/src/ndis.h @@ -9,6 +9,11 @@ #include #include +#if defined(__cplusplus) +extern "C" +{ +#endif + #define NET_BUFFER_FIRST_MDL(_NB) ((_NB)->MdlChain) #define NDIS_STATUS_SUCCESS ((NDIS_STATUS)STATUS_SUCCESS) #define NET_BUFFER_LIST_FIRST_NB(_NBL) ((_NBL)->FirstNetBuffer) @@ -43,41 +48,41 @@ typedef struct _NET_BUFFER_LIST_CONTEXT NET_BUFFER_LIST_CONTEXT, *PNET_BUFFER_LI typedef struct _NDIS_GENERIC_OBJECT NDIS_GENERIC_OBJECT, *PNDIS_GENERIC_OBJECT; -__declspec(dllexport) PNDIS_GENERIC_OBJECT +USERSIM_API PNDIS_GENERIC_OBJECT NdisAllocateGenericObject(_In_opt_ DRIVER_OBJECT* driver_object, _In_ unsigned long tag, _In_ uint16_t size); -__declspec(dllexport) NDIS_HANDLE +USERSIM_API NDIS_HANDLE NdisAllocateNetBufferListPool(_In_opt_ NDIS_HANDLE ndis_handle, _In_ NET_BUFFER_LIST_POOL_PARAMETERS const* parameters); -__declspec(dllexport) NET_BUFFER_LIST* +USERSIM_API NET_BUFFER_LIST* NdisAllocateCloneNetBufferList( _In_ NET_BUFFER_LIST* original_net_buffer_list, _In_ NDIS_HANDLE net_buffer_list_pool_handle, _In_ NDIS_HANDLE net_buffer_pool_handle, ULONG allocate_clone_flags); -__declspec(dllexport) void +USERSIM_API void NdisFreeCloneNetBufferList(_In_ NET_BUFFER_LIST* clone_net_buffer_list, ULONG free_clone_flags); -__declspec(dllexport) PNET_BUFFER_LIST +USERSIM_API PNET_BUFFER_LIST NdisAllocateNetBufferList(_In_ NDIS_HANDLE nbl_pool_handle, _In_ USHORT context_size, _In_ USHORT context_backfill); -__declspec(dllexport) _Must_inspect_result_ __drv_allocatesMem(mem) NET_BUFFER* NdisAllocateNetBuffer( +USERSIM_API _Must_inspect_result_ __drv_allocatesMem(mem) NET_BUFFER* NdisAllocateNetBuffer( _In_ NDIS_HANDLE pool_handle, _In_opt_ MDL* mdl_chain, _In_ unsigned long data_offset, _In_ SIZE_T data_length); -__declspec(dllexport) VOID +USERSIM_API VOID NdisFreeNetBuffer(_In_ __drv_freesMem(mem) NET_BUFFER* net_buffer); -__declspec(dllexport) VOID +USERSIM_API VOID NdisFreeNetBufferList(_In_ __drv_freesMem(mem) NET_BUFFER_LIST* net_buffer_list); -__declspec(dllexport) void +USERSIM_API void NdisFreeNetBufferListPool(_In_ __drv_freesMem(mem) NDIS_HANDLE pool_handle); -__declspec(dllexport) void +USERSIM_API void NdisFreeGenericObject(_In_ PNDIS_GENERIC_OBJECT ndis_object); -__declspec(dllexport) void* +USERSIM_API void* NdisGetDataBuffer( _In_ NET_BUFFER* net_buffer, _In_ unsigned long bytes_needed, @@ -85,16 +90,20 @@ NdisGetDataBuffer( _In_ unsigned long align_multiple, _In_ unsigned long align_offset); -__declspec(dllexport) NDIS_STATUS +USERSIM_API NDIS_STATUS NdisRetreatNetBufferDataStart( _In_ NET_BUFFER* net_buffer, _In_ unsigned long data_offset_delta, _In_ unsigned long data_back_fill, _In_opt_ void* allocate_mdl_handler); -__declspec(dllexport) void +USERSIM_API void NdisAdvanceNetBufferDataStart( _In_ NET_BUFFER* net_buffer, _In_ unsigned long data_offset_delta, _In_ BOOLEAN free_mdl, _In_opt_ void* free_mdl_handler); + +#if defined(__cplusplus) +} +#endif \ No newline at end of file diff --git a/src/wdf.cpp b/src/wdf.cpp index 1eb609b..0d71b68 100644 --- a/src/wdf.cpp +++ b/src/wdf.cpp @@ -9,6 +9,19 @@ WDF_DRIVER_GLOBALS g_UsersimWdfDriverGlobals = {0}; +static WdfDriverCreate_t _WdfDriverCreate; +static WdfDeviceCreate_t _WdfDeviceCreate; +static WdfControlDeviceInitAllocate_t _WdfControlDeviceInitAllocate; +static WdfDeviceInitFree_t _WdfDeviceInitFree; +static WdfDeviceInitSetDeviceType_t _WdfDeviceInitSetDeviceType; +static WdfDeviceInitSetCharacteristics_t _WdfDeviceInitSetCharacteristics; +static WdfDeviceInitAssignName_t _WdfDeviceInitAssignName; +static WdfDeviceInitSetFileObjectConfig_t _WdfDeviceInitSetFileObjectConfig; +static WdfDeviceInitAssignWdmIrpPreprocessCallback_t _WdfDeviceInitAssignWdmIrpPreprocessCallback; +static WdfDeviceCreateSymbolicLink_t _WdfDeviceCreateSymbolicLink; +static WdfIoQueueCreate_t _WdfIoQueueCreate; +static WdfObjectDelete_t _WdfObjectDelete; + static NTSTATUS _WdfDriverCreate( _In_ WDF_DRIVER_GLOBALS* driver_globals, @@ -42,7 +55,6 @@ _WdfDeviceCreate( _In_opt_ PWDF_OBJECT_ATTRIBUTES device_attributes, _Out_ WDFDEVICE* device) { - UNREFERENCED_PARAMETER(device_init); UNREFERENCED_PARAMETER(device_attributes); if (driver_globals != &g_UsersimWdfDriverGlobals) { @@ -52,12 +64,10 @@ _WdfDeviceCreate( return STATUS_INSUFFICIENT_RESOURCES; } - *device = nullptr; + *device = *device_init; return STATUS_SUCCESS; } -typedef struct _WDF_FILEOBJECT_CONFIG WDF_FILEOBJECT_CONFIG, *PWDF_FILEOBJECT_CONFIG; -typedef struct _FN_WDFDEVICE_WDM_IRP_PREPROCESS FN_WDFDEVICE_WDM_IRP_PREPROCESS, *PFN_WDFDEVICE_WDM_IRP_PREPROCESS; #define IRP_MJ_MAXIMUM_FUNCTION 0x1b typedef struct _WDFDEVICE_INIT @@ -89,12 +99,19 @@ _WdfControlDeviceInitAllocate( return device_init; } +static _IRQL_requires_max_(DISPATCH_LEVEL) VOID +_WdfDeviceInitFree(_In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ PWDFDEVICE_INIT device_init) +{ + UNREFERENCED_PARAMETER(driver_globals); + usersim_free(device_init); +} + static _IRQL_requires_max_(DISPATCH_LEVEL) VOID _WdfDeviceInitSetDeviceType( _In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ PWDFDEVICE_INIT device_init, - _In_ DEVICE_TYPE device_type) + DEVICE_TYPE device_type) { UNREFERENCED_PARAMETER(driver_globals); device_init->device_type = device_type; @@ -105,8 +122,8 @@ _IRQL_requires_max_(DISPATCH_LEVEL) VOID _WdfDeviceInitSetCharacteristics( _In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ PWDFDEVICE_INIT device_init, - _In_ ULONG device_characteristics, - _In_ BOOLEAN or_in_values) + ULONG device_characteristics, + BOOLEAN or_in_values) { UNREFERENCED_PARAMETER(driver_globals); if (!or_in_values) { @@ -155,10 +172,10 @@ _WdfDeviceInitAssignWdmIrpPreprocessCallback( _In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ PWDFDEVICE_INIT device_init, _In_ PFN_WDFDEVICE_WDM_IRP_PREPROCESS evt_device_wdm_irp_preprocess, - _In_ UCHAR major_function, + UCHAR major_function, _When_(num_minor_functions > 0, _In_reads_bytes_(num_minor_functions)) _When_(num_minor_functions == 0, _In_opt_) PUCHAR minor_functions, - _In_ ULONG num_minor_functions) + ULONG num_minor_functions) { if (driver_globals != &g_UsersimWdfDriverGlobals) { return STATUS_INVALID_PARAMETER; @@ -199,12 +216,6 @@ _WdfDeviceCreateSymbolicLink( return STATUS_SUCCESS; } -typedef struct _WDF_IO_QUEUE_CONFIG WDF_IO_QUEUE_CONFIG, *PWDF_IO_QUEUE_CONFIG; -typedef struct _WDFQUEUE -{ - int tbd; -} WDFQUEUE; - static _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL) @@ -232,13 +243,12 @@ _WdfIoQueueCreate( return STATUS_SUCCESS; } -typedef HANDLE WDFOBJECT; - _IRQL_requires_max_(DISPATCH_LEVEL) VOID _WdfObjectDelete(_In_ PWDF_DRIVER_GLOBALS driver_globals, _In_ WDFOBJECT object) { UNREFERENCED_PARAMETER(driver_globals); - UNREFERENCED_PARAMETER(object); + + usersim_free(object); } WDFFUNC g_UsersimWdfFunctions[WdfFunctionTableNumEntries]; @@ -247,6 +257,7 @@ void usersim_initialize_wdf() { g_UsersimWdfFunctions[WdfControlDeviceInitAllocateTableIndex] = (WDFFUNC)_WdfControlDeviceInitAllocate; + g_UsersimWdfFunctions[WdfDeviceInitFreeTableIndex] = (WDFFUNC)_WdfDeviceInitFree; g_UsersimWdfFunctions[WdfDeviceInitSetDeviceTypeTableIndex] = (WDFFUNC)_WdfDeviceInitSetDeviceType; g_UsersimWdfFunctions[WdfDeviceInitAssignNameTableIndex] = (WDFFUNC)_WdfDeviceInitAssignName; g_UsersimWdfFunctions[WdfDeviceInitSetCharacteristicsTableIndex] = (WDFFUNC)_WdfDeviceInitSetCharacteristics; diff --git a/tests/wdf_test.cpp b/tests/wdf_test.cpp index 093a62c..860d61d 100644 --- a/tests/wdf_test.cpp +++ b/tests/wdf_test.cpp @@ -14,7 +14,9 @@ TEST_CASE("DriverEntry", "[wdf]") HMODULE module = LoadLibraryW(L"sample.dll"); REQUIRE(module != nullptr); - FreeLibrary(module); + if (module) { + FreeLibrary(module); + } } extern "C" @@ -29,17 +31,105 @@ TEST_CASE("WdfDriverCreate", "[wdf]") WDF_DRIVER_CONFIG config; WDF_DRIVER_CONFIG_INIT(&config, nullptr); - typedef NTSTATUS(FN_WdfDriverCreate)( - _In_ WDF_DRIVER_GLOBALS* driver_globals, - _In_ PDRIVER_OBJECT driver_object, - _In_ PCUNICODE_STRING registry_path, - _In_opt_ PWDF_OBJECT_ATTRIBUTES driver_attributes, - _In_ PWDF_DRIVER_CONFIG driver_config, - _Out_opt_ WDFDRIVER* driver); - FN_WdfDriverCreate* WdfDriverCreate = (FN_WdfDriverCreate*)UsersimWdfFunctions[WdfDriverCreateTableIndex]; - WDFDRIVER driver; - NTSTATUS status = WdfDriverCreate(UsersimWdfDriverGlobals, &driver_object, nullptr, nullptr, &config, &driver); + WdfDriverCreate_t* WdfDriverCreate = (WdfDriverCreate_t*)UsersimWdfFunctions[WdfDriverCreateTableIndex]; + WDFDRIVER driver = nullptr; + DECLARE_CONST_UNICODE_STRING(registry_path, L""); + NTSTATUS status = + WdfDriverCreate(UsersimWdfDriverGlobals, &driver_object, ®istry_path, nullptr, &config, &driver); REQUIRE(status == STATUS_SUCCESS); - REQUIRE(driver == &driver_object); + REQUIRE(driver != nullptr); + + // Verify that a duplicate create fails. + status = WdfDriverCreate(UsersimWdfDriverGlobals, &driver_object, ®istry_path, nullptr, &config, &driver); + REQUIRE(status == STATUS_DRIVER_INTERNAL_ERROR); + UsersimWdfDriverGlobals->Driver = nullptr; } + +NTSTATUS +driver_query_volume_information(_In_ WDFDEVICE device, _Inout_ IRP* irp) +{ + UNREFERENCED_PARAMETER(device); + UNREFERENCED_PARAMETER(irp); + return STATUS_SUCCESS; +} + +TEST_CASE("WdfDeviceCreate", "[wdf]") +{ + // Create driver to hold device. + DRIVER_OBJECT driver_object = {0}; + WDF_DRIVER_CONFIG config; + WDF_DRIVER_CONFIG_INIT(&config, nullptr); + WdfDriverCreate_t* WdfDriverCreate = (WdfDriverCreate_t*)UsersimWdfFunctions[WdfDriverCreateTableIndex]; + WDFDRIVER driver = nullptr; + DECLARE_CONST_UNICODE_STRING(registry_path, L""); + NTSTATUS status = WdfDriverCreate(UsersimWdfDriverGlobals, &driver_object, ®istry_path, nullptr, &config, &driver); + REQUIRE(status == STATUS_SUCCESS); + + // Allocate control device object. + WdfControlDeviceInitAllocate_t* WdfControlDeviceInitAllocate = + (WdfControlDeviceInitAllocate_t*)UsersimWdfFunctions[WdfControlDeviceInitAllocateTableIndex]; + DECLARE_CONST_UNICODE_STRING(security_descriptor, L""); + PWDFDEVICE_INIT init = WdfControlDeviceInitAllocate(UsersimWdfDriverGlobals, driver, &security_descriptor); + REQUIRE(init != nullptr); + + // Set device type. + WdfDeviceInitSetDeviceType_t* WdfDeviceInitSetDeviceType = + (WdfDeviceInitSetDeviceType_t*)UsersimWdfFunctions[WdfDeviceInitSetDeviceTypeTableIndex]; + WdfDeviceInitSetDeviceType(UsersimWdfDriverGlobals, init, FILE_DEVICE_NULL); + + // Set device characteristics. + WdfDeviceInitSetCharacteristics_t* WdfDeviceInitSetCharacteristics = + (WdfDeviceInitSetCharacteristics_t*)UsersimWdfFunctions[WdfDeviceInitSetCharacteristicsTableIndex]; + WdfDeviceInitSetCharacteristics(UsersimWdfDriverGlobals, init, FILE_DEVICE_SECURE_OPEN, FALSE); + + // Set device name. + UNICODE_STRING device_name; + RtlInitUnicodeString(&device_name, L"test device name"); + WdfDeviceInitAssignName_t* WdfDeviceInitAssignName = + (WdfDeviceInitAssignName_t*)UsersimWdfFunctions[WdfDeviceInitAssignNameTableIndex]; + status = WdfDeviceInitAssignName(UsersimWdfDriverGlobals, init, &device_name); + REQUIRE(status == STATUS_SUCCESS); + + // Set file object config. + WDF_OBJECT_ATTRIBUTES attributes = {0}; + WDF_FILEOBJECT_CONFIG file_object_config = {0}; + WdfDeviceInitSetFileObjectConfig_t* WdfDeviceInitSetFileObjectConfig = + (WdfDeviceInitSetFileObjectConfig_t*)UsersimWdfFunctions[WdfDeviceInitSetFileObjectConfigTableIndex]; + WdfDeviceInitSetFileObjectConfig(UsersimWdfDriverGlobals, init, &file_object_config, &attributes); + + WdfDeviceInitAssignWdmIrpPreprocessCallback_t* WdfDeviceInitAssignWdmIrpPreprocessCallback = + (WdfDeviceInitAssignWdmIrpPreprocessCallback_t*)UsersimWdfFunctions[WdfDeviceInitAssignWdmIrpPreprocessCallbackTableIndex]; + status = WdfDeviceInitAssignWdmIrpPreprocessCallback( + UsersimWdfDriverGlobals, init, driver_query_volume_information, IRP_MJ_QUERY_VOLUME_INFORMATION, NULL, 0); + REQUIRE(status == STATUS_SUCCESS); + + // Create device. + WDFDEVICE device = nullptr; + WdfDeviceCreate_t* WdfDeviceCreate = (WdfDeviceCreate_t*)UsersimWdfFunctions[WdfDeviceCreateTableIndex]; + status = WdfDeviceCreate(UsersimWdfDriverGlobals, &init, nullptr, &device); + REQUIRE(status == STATUS_SUCCESS); + REQUIRE(device != nullptr); + + // Create symbolic link for control object for user mode. + UNICODE_STRING symbolic_device_name; + RtlInitUnicodeString(&symbolic_device_name, L"symbolic device name"); + WdfDeviceCreateSymbolicLink_t* WdfDeviceCreateSymbolicLink = + (WdfDeviceCreateSymbolicLink_t*)UsersimWdfFunctions[WdfDeviceCreateSymbolicLinkTableIndex]; + status = WdfDeviceCreateSymbolicLink(UsersimWdfDriverGlobals, device, &symbolic_device_name); + REQUIRE(status == STATUS_SUCCESS); + + // Create an I/O queue. + WDF_IO_QUEUE_CONFIG io_queue_configuration = {0}; + WdfIoQueueCreate_t* WdfIoQueueCreate = (WdfIoQueueCreate_t*)UsersimWdfFunctions[WdfIoQueueCreateTableIndex]; +#pragma warning(suppress:28193) // status must be inspected + status = WdfIoQueueCreate( + UsersimWdfDriverGlobals, device, &io_queue_configuration, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); + REQUIRE(status == STATUS_SUCCESS); + + // Free device, which will free the control device object. + WdfObjectDelete_t* WdfObjectDelete = (WdfObjectDelete_t*)UsersimWdfFunctions[WdfObjectDeleteTableIndex]; + WdfObjectDelete(UsersimWdfDriverGlobals, device); + + UsersimWdfDriverGlobals->Driver = nullptr; +} \ No newline at end of file From f1d882246f6a6270a8e54cd3f09506f17efb7cc3 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Sun, 6 Aug 2023 14:12:40 -0700 Subject: [PATCH 3/4] Bug fix Signed-off-by: Dave Thaler --- usersim_dll_skeleton/dll_skeleton.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usersim_dll_skeleton/dll_skeleton.c b/usersim_dll_skeleton/dll_skeleton.c index 0711440..b105795 100644 --- a/usersim_dll_skeleton/dll_skeleton.c +++ b/usersim_dll_skeleton/dll_skeleton.c @@ -21,6 +21,7 @@ __declspec(dllimport) const WDFFUNC* UsersimWdfFunctions; PWDF_DRIVER_GLOBALS WdfDriverGlobals = NULL; const WDFFUNC* WdfFunctions_01015 = NULL; +static DRIVER_OBJECT _driver_object = {0}; NTSTATUS UsersimStartDriver() @@ -28,9 +29,8 @@ const WDFFUNC* WdfFunctions_01015 = NULL; WdfDriverGlobals = UsersimWdfDriverGlobals; WdfFunctions_01015 = UsersimWdfFunctions; - DRIVER_OBJECT driver_object = {0}; UNICODE_STRING registry_path = {0}; - return DriverEntry(&driver_object, ®istry_path); + return DriverEntry(&_driver_object, ®istry_path); } void From beb166acc663577b07217d4f0c59ca2f4efe8534 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Mon, 7 Aug 2023 11:01:54 -0700 Subject: [PATCH 4/4] PR feedback Signed-off-by: Dave Thaler --- src/platform_user.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform_user.cpp b/src/platform_user.cpp index d3128e6..2fc092e 100644 --- a/src/platform_user.cpp +++ b/src/platform_user.cpp @@ -201,7 +201,7 @@ usersim_platform_initiate() try { _usersim_platform_maximum_group_count = GetMaximumProcessorGroupCount(); _usersim_platform_maximum_processor_count = GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS); - bool fault_injection_stack_depth = + size_t fault_injection_stack_depth = _get_environment_variable_as_size_t(USERSIM_FAULT_INJECTION_SIMULATION_ENVIRONMENT_VARIABLE_NAME); bool leak_detector = _get_environment_variable_as_bool(USERSIM_MEMORY_LEAK_DETECTION_ENVIRONMENT_VARIABLE_NAME); if (fault_injection_stack_depth || leak_detector) {