From 9d15fb927941f29a8855944fa68376b1fec9b77e Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Thu, 12 Oct 2017 15:32:30 +0100 Subject: [PATCH] Start to implement fltmgr tests [WIP] (#52) [FLTMGR] - Partially implement registering contexts - Add a misc file which contains stubs of the APIs needed in the test suite - Export some APIs needed by the test suite [KMTESTS] - Create a File System Mini-filter wrapper to host drivers for the filter manager tests - Add a test file which will be used for testing that mini-filters load correctly - Add a test file which will be used to write tests for IRP_MJ_CREATE requests --- drivers/filters/CMakeLists.txt | 2 +- drivers/filters/fltmgr/CMakeLists.txt | 1 + drivers/filters/fltmgr/Context.c | 103 +++- drivers/filters/fltmgr/Interface.c | 12 + drivers/filters/fltmgr/Messaging.c | 2 +- drivers/filters/fltmgr/Misc.c | 56 ++ drivers/filters/fltmgr/fltmgr.spec | 7 +- modules/rostests/kmtests/CMakeLists.txt | 1 + .../rostests/kmtests/fltmgr/CMakeLists.txt | 3 + .../fltmgr/fltmgr_create/CMakeLists.txt | 14 + .../fltmgr/fltmgr_create/fltmgr_create.c | 147 +++++ .../kmtests/fltmgr/fltmgr_load/CMakeLists.txt | 14 + .../kmtests/fltmgr/fltmgr_load/fltmgr_load.c | 234 ++++++++ .../rostests/kmtests/include/kmt_platform.h | 3 + modules/rostests/kmtests/include/kmt_test.h | 23 + .../kmtests/kmtest_drv/kmtest_fsminifilter.c | 525 ++++++++++++++++++ 16 files changed, 1139 insertions(+), 8 deletions(-) create mode 100644 drivers/filters/fltmgr/Misc.c create mode 100644 modules/rostests/kmtests/fltmgr/CMakeLists.txt create mode 100644 modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt create mode 100644 modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c create mode 100644 modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt create mode 100644 modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c create mode 100644 modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c diff --git a/drivers/filters/CMakeLists.txt b/drivers/filters/CMakeLists.txt index 7b700504095..2d135dd9199 100644 --- a/drivers/filters/CMakeLists.txt +++ b/drivers/filters/CMakeLists.txt @@ -1,2 +1,2 @@ -#add_subdirectory(fltmgr) +add_subdirectory(fltmgr) add_subdirectory(mountmgr) diff --git a/drivers/filters/fltmgr/CMakeLists.txt b/drivers/filters/fltmgr/CMakeLists.txt index ea527186d2c..f3d52e22001 100644 --- a/drivers/filters/fltmgr/CMakeLists.txt +++ b/drivers/filters/fltmgr/CMakeLists.txt @@ -5,6 +5,7 @@ list(APPEND SOURCE Interface.c Lib.c Messaging.c + Misc.c Object.c ${CMAKE_CURRENT_BINARY_DIR}/fltmgr.def fltmgr.h) diff --git a/drivers/filters/fltmgr/Context.c b/drivers/filters/fltmgr/Context.c index ead64cda270..7e6d03c62cf 100644 --- a/drivers/filters/fltmgr/Context.c +++ b/drivers/filters/fltmgr/Context.c @@ -27,7 +27,7 @@ static NTSTATUS SetupContextHeader( _In_ PFLT_FILTER Filter, - _In_ PFLT_CONTEXT_REGISTRATION ContextPtr, + _In_ PCFLT_CONTEXT_REGISTRATION ContextPtr, _Out_ PALLOCATE_CONTEXT_HEADER ContextHeader ); @@ -43,9 +43,102 @@ NTSTATUS FltpRegisterContexts(_In_ PFLT_FILTER Filter, _In_ const FLT_CONTEXT_REGISTRATION *Context) { - UNREFERENCED_PARAMETER(Filter); - UNREFERENCED_PARAMETER(Context); - return STATUS_NOT_IMPLEMENTED; + PCFLT_CONTEXT_REGISTRATION ContextPtr; + PALLOCATE_CONTEXT_HEADER ContextHeader, Prev; + PVOID Buffer; + ULONG BufferSize = 0; + USHORT i; + NTSTATUS Status; + + /* Loop through all entries in the context registration array */ + ContextPtr = Context; + while (ContextPtr) + { + /* Bail if we found the terminator */ + if (ContextPtr->ContextType == FLT_CONTEXT_END) + break; + + /* Make sure we have a valid context */ + if (IsContextTypeValid(ContextPtr->ContextType)) + { + /* Each context is backed by a crtl struct. Reserve space for it */ + BufferSize += sizeof(STREAM_LIST_CTRL); + } + + /* Move to the next entry */ + ContextPtr++; + } + + /* Bail if we found no valid registration requests */ + if (BufferSize == 0) + { + return STATUS_SUCCESS; + } + + /* Allocate the pool that'll hold the context crtl structs */ + Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, FM_TAG_CONTEXT_REGISTA); + if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(Buffer, BufferSize); + + /* Setup our loop data */ + ContextHeader = Buffer; + Prev = NULL; + Status = STATUS_SUCCESS; + + for (i = 0; i < MAX_CONTEXT_TYPES; i++) + { + ContextPtr = (PFLT_CONTEXT_REGISTRATION)Context; + while (ContextPtr) + { + /* We don't support variable sized contents yet */ + FLT_ASSERT(ContextPtr->Size != FLT_VARIABLE_SIZED_CONTEXTS); + + /* Bail if we found the terminator */ + if (ContextPtr->ContextType == FLT_CONTEXT_END) + break; + + /* Size and pooltag are only checked when ContextAllocateCallback is null */ + if (ContextPtr->ContextAllocateCallback == FALSE && ContextPtr->PoolTag == FALSE) + { + Status = STATUS_FLT_INVALID_CONTEXT_REGISTRATION; + goto Quit; + } + + /* Make sure we have a valid context */ + if (IsContextTypeValid(ContextPtr->ContextType)) + { + Status = SetupContextHeader(Filter, ContextPtr, ContextHeader); + if (NT_SUCCESS(Status)) + { + if (Prev) + { + Prev->Next = ContextHeader; + } + + Filter->SupportedContexts[i] = ContextHeader; + } + } + + Prev = ContextHeader; + + /* Move to the next entry */ + ContextPtr++; + } + } + +Quit: + if (NT_SUCCESS(Status)) + { + Filter->SupportedContextsListHead = Buffer; + } + else + { + ExFreePoolWithTag(Buffer, FM_TAG_CONTEXT_REGISTA); + //FIXME: Cleanup anything that SetupContextHeader may have allocated + } + + return Status; } @@ -72,7 +165,7 @@ IsContextTypeValid(_In_ FLT_CONTEXT_TYPE ContextType) static NTSTATUS SetupContextHeader(_In_ PFLT_FILTER Filter, - _In_ PFLT_CONTEXT_REGISTRATION ContextPtr, + _In_ PCFLT_CONTEXT_REGISTRATION ContextPtr, _Out_ PALLOCATE_CONTEXT_HEADER ContextHeader) { return 0; diff --git a/drivers/filters/fltmgr/Interface.c b/drivers/filters/fltmgr/Interface.c index 7854000b8b7..be1288a7c23 100644 --- a/drivers/filters/fltmgr/Interface.c +++ b/drivers/filters/fltmgr/Interface.c @@ -17,6 +17,18 @@ /* DATA *********************************************************************/ +#define VALID_FAST_IO_DISPATCH_HANDLER(_FastIoDispatchPtr, _FieldName) \ + (((_FastIoDispatchPtr) != NULL) && \ + (((_FastIoDispatchPtr)->SizeOfFastIoDispatch) >= \ + (FIELD_OFFSET(FAST_IO_DISPATCH, _FieldName) + sizeof(void *))) && \ + ((_FastIoDispatchPtr)->_FieldName != NULL)) + +#define IS_MY_DEVICE_OBJECT(_devObj) \ + (((_devObj) != NULL) && \ + ((_devObj)->DriverObject == Dispatcher::DriverObject) && \ + ((_devObj)->DeviceExtension != NULL)) + + DRIVER_INITIALIZE DriverEntry; NTSTATUS NTAPI diff --git a/drivers/filters/fltmgr/Messaging.c b/drivers/filters/fltmgr/Messaging.c index e6e4473fab1..97e6a94c9c6 100644 --- a/drivers/filters/fltmgr/Messaging.c +++ b/drivers/filters/fltmgr/Messaging.c @@ -125,7 +125,7 @@ FltCreateCommunicationPort(_In_ PFLT_FILTER Filter, FltObjectDereference(Filter); } - return STATUS_NOT_IMPLEMENTED; + return Status; } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/drivers/filters/fltmgr/Misc.c b/drivers/filters/fltmgr/Misc.c new file mode 100644 index 00000000000..3ef1424d5f6 --- /dev/null +++ b/drivers/filters/fltmgr/Misc.c @@ -0,0 +1,56 @@ +/* + * PROJECT: Filesystem Filter Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/filters/fltmgr/Misc.c + * PURPOSE: Uncataloged functions + * PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "fltmgr.h" +#include "fltmgrint.h" + +#define NDEBUG +#include + + +/* DATA *********************************************************************/ + + + + +/* EXPORTED FUNCTIONS ******************************************************/ + +NTSTATUS +FLTAPI +FltBuildDefaultSecurityDescriptor( + _Outptr_ PSECURITY_DESCRIPTOR *SecurityDescriptor, + _In_ ACCESS_MASK DesiredAccess +) +{ + UNREFERENCED_PARAMETER(SecurityDescriptor); + UNREFERENCED_PARAMETER(DesiredAccess); + return 0; +} + +VOID +FLTAPI +FltFreeSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor +) +{ + UNREFERENCED_PARAMETER(SecurityDescriptor); +} + +NTSTATUS +FLTAPI +FltGetDiskDeviceObject( + _In_ PFLT_VOLUME Volume, + _Outptr_ PDEVICE_OBJECT *DiskDeviceObject +) +{ + UNREFERENCED_PARAMETER(Volume); + UNREFERENCED_PARAMETER(DiskDeviceObject); + return 0; +} \ No newline at end of file diff --git a/drivers/filters/fltmgr/fltmgr.spec b/drivers/filters/fltmgr/fltmgr.spec index 2967a05d7a2..9e18cd59979 100644 --- a/drivers/filters/fltmgr/fltmgr.spec +++ b/drivers/filters/fltmgr/fltmgr.spec @@ -2,4 +2,9 @@ @ stdcall FltRegisterFilter(ptr ptr ptr) @ stdcall FltUnregisterFilter(ptr) @ stdcall FltCloseCommunicationPort(ptr) - + @ stdcall FltStartFiltering(ptr) + @ stdcall FltCreateCommunicationPort(ptr ptr ptr ptr ptr ptr ptr long) + @ stdcall FltBuildDefaultSecurityDescriptor(ptr long) + @ stdcall FltFreeSecurityDescriptor(ptr) + @ stdcall FltGetDiskDeviceObject(ptr ptr) + diff --git a/modules/rostests/kmtests/CMakeLists.txt b/modules/rostests/kmtests/CMakeLists.txt index dfc6c98d0a1..d51ef000c77 100644 --- a/modules/rostests/kmtests/CMakeLists.txt +++ b/modules/rostests/kmtests/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories(include) # subdirectories containing special-purpose drivers # add_subdirectory(example) +add_subdirectory(fltmgr) add_subdirectory(hidparse) add_subdirectory(kernel32) add_subdirectory(ntos_cc) diff --git a/modules/rostests/kmtests/fltmgr/CMakeLists.txt b/modules/rostests/kmtests/fltmgr/CMakeLists.txt new file mode 100644 index 00000000000..fd7a55e6bc0 --- /dev/null +++ b/modules/rostests/kmtests/fltmgr/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_subdirectory(fltmgr_load) +add_subdirectory(fltmgr_create) diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt b/modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt new file mode 100644 index 00000000000..435293967e2 --- /dev/null +++ b/modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt @@ -0,0 +1,14 @@ + +include_directories(../../include) + +list(APPEND FLTMGR_TEST_DRV_SOURCE + ../../kmtest_drv/kmtest_fsminifilter.c + fltmgr_create.c) + +add_library(fltmgr_create SHARED ${FLTMGR_TEST_DRV_SOURCE}) +set_module_type(fltmgr_create kernelmodedriver) +target_link_libraries(fltmgr_create kmtest_printf ${PSEH_LIB}) +add_importlibs(fltmgr_create fltmgr ntoskrnl hal) +add_target_compile_definitions(fltmgr_create KMT_STANDALONE_DRIVER KMT_FILTER_DRIVER NTDDI_VERSION=NTDDI_WS03SP1) +#add_pch(example_drv ../include/kmt_test.h) +add_rostests_file(TARGET fltmgr_create) diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c b/modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c new file mode 100644 index 00000000000..6c28f3ef184 --- /dev/null +++ b/modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c @@ -0,0 +1,147 @@ +/* + * PROJECT: ReactOS kernel-mode tests - Filter Manager + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for checking the create operations + * PROGRAMMER: Ged Murphy + */ + +#include +#include + +//#define NDEBUG +#include + +/* prototypes */ +static +FLT_PREOP_CALLBACK_STATUS +FLTAPI +TestFilterPreOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Outptr_result_maybenull_ PVOID *CompletionContext +); + +static +FLT_POSTOP_CALLBACK_STATUS +FLTAPI +TestFilterPostOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags +); + + +/* Globals */ +static PDRIVER_OBJECT TestDriverObject; + + +CONST FLT_OPERATION_REGISTRATION Callbacks[] = +{ + { IRP_MJ_CREATE, + 0, + TestFilterPreOperation, + TestFilterPostOperation }, + + { IRP_MJ_OPERATION_END } +}; + + +NTSTATUS +TestEntry( + IN PDRIVER_OBJECT DriverObject, + IN PCUNICODE_STRING RegistryPath, + OUT PCWSTR *DeviceName, + IN OUT INT *Flags) +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(RegistryPath); + UNREFERENCED_PARAMETER(Flags); + + DPRINT("Entry!\n"); + + ok_irql(PASSIVE_LEVEL); + TestDriverObject = DriverObject; + + *DeviceName = L"fltmgr_create"; + + trace("Hi, this is the filter manager create test driver\n"); + + (VOID)KmtFilterRegisterCallbacks(Callbacks); + + return Status; +} + +VOID +TestFilterUnload( + IN ULONG Flags) +{ + PAGED_CODE(); + + DPRINT("Unload!\n"); + + ok_irql(PASSIVE_LEVEL); + + trace("Unloading filter manager test driver\n"); +} + +VOID +TestQueryTeardown( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) +{ + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); +} + +NTSTATUS +TestInstanceSetup( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType, + _In_ PUNICODE_STRING VolumeName, + _In_ ULONG SectorSize, + _In_ ULONG ReportedSectorSize +) +{ + trace("Received an attach request for VolumeType 0x%X, FileSystemType %d\n", + VolumeDeviceType, + VolumeFilesystemType); + + return STATUS_FLT_DO_NOT_ATTACH; +} + +static +FLT_PREOP_CALLBACK_STATUS +FLTAPI +TestFilterPreOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Outptr_result_maybenull_ PVOID *CompletionContext) +{ + PFLT_IO_PARAMETER_BLOCK Iopb = Data->Iopb; + + ok_eq_hex(Iopb->MajorFunction, IRP_MJ_CREATE); + + return FLT_PREOP_SUCCESS_NO_CALLBACK; +} + +static +FLT_POSTOP_CALLBACK_STATUS +FLTAPI +TestFilterPostOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags) +{ + PFLT_IO_PARAMETER_BLOCK Iopb = Data->Iopb; + + ok_eq_hex(Iopb->MajorFunction, IRP_MJ_CREATE); + + return FLT_POSTOP_FINISHED_PROCESSING; +} \ No newline at end of file diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt b/modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt new file mode 100644 index 00000000000..7fa022d1545 --- /dev/null +++ b/modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt @@ -0,0 +1,14 @@ + +include_directories(../../include) + +list(APPEND FLTMGR_TEST_DRV_SOURCE + ../../kmtest_drv/kmtest_fsminifilter.c + fltmgr_load.c) + +add_library(fltmgr_load SHARED ${FLTMGR_TEST_DRV_SOURCE}) +set_module_type(fltmgr_load kernelmodedriver) +target_link_libraries(fltmgr_load kmtest_printf ${PSEH_LIB}) +add_importlibs(fltmgr_load fltmgr ntoskrnl hal) +add_target_compile_definitions(fltmgr_load KMT_STANDALONE_DRIVER KMT_FILTER_DRIVER NTDDI_VERSION=NTDDI_WS03SP1) +#add_pch(example_drv ../include/kmt_test.h) +add_rostests_file(TARGET fltmgr_load) diff --git a/modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c b/modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c new file mode 100644 index 00000000000..7b9f5235cb9 --- /dev/null +++ b/modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c @@ -0,0 +1,234 @@ +/* + * PROJECT: ReactOS kernel-mode tests - Filter Manager + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for checking filters load correctly + * PROGRAMMER: Ged Murphy + */ + +#include +#include + +//#define NDEBUG +#include + +/* prototypes */ +NTSTATUS +FLTAPI +TestClientConnect( + _In_ PFLT_PORT ClientPort, + _In_opt_ PVOID ServerPortCookie, + _In_reads_bytes_opt_(SizeOfContext) PVOID ConnectionContext, + _In_ ULONG SizeOfContext, + _Outptr_result_maybenull_ PVOID *ConnectionPortCookie +); + +VOID +FLTAPI +TestClientDisconnect( + _In_opt_ PVOID ConnectionCookie +); + +NTSTATUS +FLTAPI +TestMessageHandler( + _In_opt_ PVOID ConnectionCookie, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_to_opt_(OutputBufferLength, *ReturnOutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength, + _Out_ PULONG ReturnOutputBufferLength +); + + +/* Globals */ +static PDRIVER_OBJECT TestDriverObject; + + + +/** + * @name TestEntry + * + * Test entry point. + * This is called by DriverEntry as early as possible, but with ResultBuffer + * initialized, so that test macros work correctly + * + * @param DriverObject + * Driver Object. + * This is guaranteed not to have been touched by DriverEntry before + * the call to TestEntry + * @param RegistryPath + * Driver Registry Path + * This is guaranteed not to have been touched by DriverEntry before + * the call to TestEntry + * @param DeviceName + * Pointer to receive a test-specific name for the device to create + * @param Flags + * Pointer to a flags variable instructing DriverEntry how to proceed. + * See the KMT_TESTENTRY_FLAGS enumeration for possible values + * Initialized to zero on entry + * + * @return Status. + * DriverEntry will fail if this is a failure status + */ +NTSTATUS +TestEntry( + IN PDRIVER_OBJECT DriverObject, + IN PCUNICODE_STRING RegistryPath, + OUT PCWSTR *DeviceName, + IN OUT INT *Flags) +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(RegistryPath); + UNREFERENCED_PARAMETER(Flags); + + DPRINT("Entry!\n"); + + ok_irql(PASSIVE_LEVEL); + TestDriverObject = DriverObject; + + *DeviceName = L"fltmgr_load"; + + trace("Hi, this is the filter manager load test driver\n"); + + KmtFilterRegisterComms(TestClientConnect, TestClientDisconnect, TestMessageHandler, 1); + + return Status; +} + +/** + * @name TestUnload + * + * Test unload routine. + * This is called by the driver's Unload routine as early as possible, with + * ResultBuffer and the test device object still valid, so that test macros + * work correctly + * + * @param DriverObject + * Driver Object. + * This is guaranteed not to have been touched by Unload before the call + * to TestEntry + * + * @return Status + */ +VOID +TestFilterUnload( + IN ULONG Flags) +{ + PAGED_CODE(); + + DPRINT("Unload!\n"); + + ok_irql(PASSIVE_LEVEL); + + trace("Unloading filter manager load test driver\n"); +} + + +/** +* @name TestInstanceSetup +* +* Test volume attach routine. +* This is called by the driver's InstanceSetupCallback routine in response to +* a new volume attaching. +* +* @param FltObjects +* Filter Object Pointers +* Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers +* for the objects related to the current operation +* @param Flags +* Bitmask of flags that indicate why the instance is being attached +* @param VolumeDeviceType +* Device type of the file system volume +* @param VolumeFilesystemType +* File system type of the volume +* @param VolumeName +* Unicode string containing the name of the volume. +* The string is only valid within the context of this function +* @param SectorSize +* Adjusts the sector size to a minimum of 0x200, which is more reliable +* @param ReportedSectorSize +* Sector size of the volume as reported by the filter manager +* +* @return Status. +* Return STATUS_SUCCESS to attach or STATUS_FLT_DO_NOT_ATTACH to ignore +*/ +NTSTATUS +TestInstanceSetup( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType, + _In_ PUNICODE_STRING VolumeName, + _In_ ULONG SectorSize, + _In_ ULONG ReportedSectorSize +) +{ + trace("Received an attach request for VolumeType 0x%X, FileSystemType %d\n", + VolumeDeviceType, + VolumeFilesystemType); + + /* We're not interested in attaching to any volumes in this test */ + return STATUS_FLT_DO_NOT_ATTACH; +} + +/** +* @name TestQueryTeardown +* +* Test volume attach routine. +* This is called by the driver's InstanceSetupCallback routine in response to +* a new volume attaching. +* +* @param FltObjects +* Filter Object Pointers +* Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers +* for the objects related to the current operation +* @param Flags +* Flag that indicates why the minifilter driver instance is being torn down +* +*/ +VOID +TestQueryTeardown( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) +{ + trace("Received a teardown request, Flags %lu\n", Flags); + + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); +} + +NTSTATUS +FLTAPI +TestClientConnect( + _In_ PFLT_PORT ClientPort, + _In_opt_ PVOID ServerPortCookie, + _In_reads_bytes_opt_(SizeOfContext) PVOID ConnectionContext, + _In_ ULONG SizeOfContext, + _Outptr_result_maybenull_ PVOID *ConnectionPortCookie) +{ + return 0; +} + +VOID +FLTAPI +TestClientDisconnect( + _In_opt_ PVOID ConnectionCookie) +{ + +} + +NTSTATUS +FLTAPI +TestMessageHandler( + _In_opt_ PVOID ConnectionCookie, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_to_opt_(OutputBufferLength, *ReturnOutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength, + _Out_ PULONG ReturnOutputBufferLength) +{ + return 0; +} diff --git a/modules/rostests/kmtests/include/kmt_platform.h b/modules/rostests/kmtests/include/kmt_platform.h index 4efdc583bbc..9e732c397a9 100644 --- a/modules/rostests/kmtests/include/kmt_platform.h +++ b/modules/rostests/kmtests/include/kmt_platform.h @@ -25,6 +25,9 @@ #include #include #include +#if defined KMT_FILTER_DRIVER +#include +#endif #elif defined KMT_USER_MODE #define WIN32_NO_STATUS diff --git a/modules/rostests/kmtests/include/kmt_test.h b/modules/rostests/kmtests/include/kmt_test.h index b2de5bc19ac..59416761404 100644 --- a/modules/rostests/kmtests/include/kmt_test.h +++ b/modules/rostests/kmtests/include/kmt_test.h @@ -117,6 +117,29 @@ NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryP VOID TestUnload(IN PDRIVER_OBJECT DriverObject); #endif /* defined KMT_STANDALONE_DRIVER */ +#ifdef KMT_FILTER_DRIVER +#ifndef KMT_KERNEL_MODE +#define KMT_KERNEL_MODE +#endif + +NTSTATUS KmtFilterRegisterCallbacks(_In_ CONST FLT_OPERATION_REGISTRATION *OperationRegistration); + +typedef enum +{ + TESTENTRY_NO_REGISTER_FILTER = 1, + TESTENTRY_NO_CREATE_COMMS_PORT = 2, + TESTENTRY_NO_START_FILTERING = 4, +} KMT_MINIFILTER_FLAGS; + +VOID TestFilterUnload(_In_ ULONG Flags); +NTSTATUS TestInstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType, _In_ PUNICODE_STRING VolumeName, _In_ ULONG RealSectorSize, _In_ ULONG SectorSize); +VOID TestQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags); + +NTSTATUS KmtFilterRegisterComms(_In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback, _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback, _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback, _In_ LONG MaxClientConnections); + +#endif/* defined KMT_FILTER_DRIVER */ + + #ifdef KMT_KERNEL_MODE /* Device Extension layout */ typedef struct diff --git a/modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c b/modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c new file mode 100644 index 00000000000..2de7f3b1592 --- /dev/null +++ b/modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c @@ -0,0 +1,525 @@ +/* + * PROJECT: ReactOS kernel-mode tests - Filter Manager + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: FS Mini-filter wrapper to host the filter manager tests + * PROGRAMMER: Ged Murphy + */ + +#include +#include +#include + +#define KMT_DEFINE_TEST_FUNCTIONS +#include + +#define NDEBUG +#include + +#include + +#define KMTEST_FILTER_POOL_TAG 'fTMK' + + +typedef struct _FILTER_DATA +{ + PDRIVER_OBJECT DriverObject; + FLT_REGISTRATION FilterRegistration; + PFLT_FILTER Filter; + PFLT_PORT ServerPort; + +} FILTER_DATA, *PFILTER_DATA; + + +/* Prototypes */ +DRIVER_INITIALIZE DriverEntry; + +/* Globals */ +static PDRIVER_OBJECT TestDriverObject; +static FILTER_DATA FilterData; +static PFLT_OPERATION_REGISTRATION Callbacks = NULL; +static PFLT_CONTEXT_REGISTRATION Contexts = NULL; + +static PFLT_CONNECT_NOTIFY FilterConnect = NULL; +static PFLT_DISCONNECT_NOTIFY FilterDisconnect = NULL; +static PFLT_MESSAGE_NOTIFY FilterMessage = NULL; +static LONG MaxConnections = 0; + +NTSTATUS +FLTAPI +FilterUnload( + _In_ FLT_FILTER_UNLOAD_FLAGS Flags +); + +NTSTATUS +FLTAPI +FilterInstanceSetup( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType +); + +NTSTATUS +FLTAPI +FilterQueryTeardown( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags +); + +FLT_PREOP_CALLBACK_STATUS +FLTAPI +FilterPreOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Outptr_result_maybenull_ PVOID *CompletionContext +); + +FLT_POSTOP_CALLBACK_STATUS +FLTAPI +FilterPostOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags +); + + + +FLT_REGISTRATION FilterRegistration = +{ + sizeof(FLT_REGISTRATION), // Size + FLT_REGISTRATION_VERSION, // Version + 0, // Flags + NULL, // ContextRegistration + NULL, // OperationRegistration + FilterUnload, // FilterUnloadCallback + FilterInstanceSetup, // InstanceSetupCallback + FilterQueryTeardown, // InstanceQueryTeardownCallback + NULL, // InstanceTeardownStartCallback + NULL, // InstanceTeardownCompleteCallback + NULL, // AmFilterGenerateFileNameCallback + NULL, // AmFilterNormalizeNameComponentCallback + NULL, // NormalizeContextCleanupCallback +#if FLT_MGR_LONGHORN + NULL, // TransactionNotificationCallback + NULL, // AmFilterNormalizeNameComponentExCallback +#endif +}; + + + +/* Filter Interface Routines ****************************/ + +/** + * @name DriverEntry + * + * Driver entry point. + * + * @param DriverObject + * Driver Object + * @param RegistryPath + * Driver Registry Path + * + * @return Status + */ +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + NTSTATUS Status = STATUS_SUCCESS; + OBJECT_ATTRIBUTES ObjectAttributes; + PSECURITY_DESCRIPTOR SecurityDescriptor; + UNICODE_STRING DeviceName; + WCHAR DeviceNameBuffer[128] = L"\\Device\\Kmtest-"; + PCWSTR DeviceNameSuffix; + INT Flags = 0; + PKPRCB Prcb; + + PAGED_CODE(); + //__debugbreak(); + DPRINT("DriverEntry\n"); + + RtlZeroMemory(&FilterData, sizeof(FILTER_DATA)); + + Prcb = KeGetCurrentPrcb(); + KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0; + KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0; + TestDriverObject = DriverObject; + + + /* call TestEntry */ + RtlInitUnicodeString(&DeviceName, DeviceNameBuffer); + DeviceName.MaximumLength = sizeof DeviceNameBuffer; + TestEntry(DriverObject, RegistryPath, &DeviceNameSuffix, &Flags); + + RtlAppendUnicodeToString(&DeviceName, DeviceNameSuffix); + + /* Register with the filter manager */ + if (!(Flags & TESTENTRY_NO_REGISTER_FILTER)) + { + Status = FltRegisterFilter(DriverObject, + &FilterRegistration, + &FilterData.Filter); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to register the filter driver %wZ\n", &DeviceName); + goto cleanup; + } + } + + if (!(Flags & TESTENTRY_NO_CREATE_COMMS_PORT)) + { + /* Create a security descriptor */ + Status = FltBuildDefaultSecurityDescriptor(&SecurityDescriptor, + FLT_PORT_ALL_ACCESS); + if (!NT_SUCCESS(Status)) + { + goto cleanup; + } + + /* Initialize the security descriptor object */ + InitializeObjectAttributes(&ObjectAttributes, + &DeviceName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + SecurityDescriptor); + + + /* Create the usermode communication port */ + Status = FltCreateCommunicationPort(FilterData.Filter, + &FilterData.ServerPort, + &ObjectAttributes, + NULL, + FilterConnect, + FilterDisconnect, + FilterMessage, + MaxConnections); + + /* Free the security descriptor */ + FltFreeSecurityDescriptor(SecurityDescriptor); + + if (!NT_SUCCESS(Status)) + { + goto cleanup; + } + } + + if (!(Flags & TESTENTRY_NO_START_FILTERING)) + { + /* Start filtering the requests */ + Status = FltStartFiltering(FilterData.Filter); + } + +cleanup: + if (!NT_SUCCESS(Status)) + { + if (FilterData.ServerPort) + { + FltCloseCommunicationPort(FilterData.ServerPort); + } + if (FilterData.Filter) + { + FltUnregisterFilter(FilterData.Filter); + } + } + + return Status; +} + +/** + * @name DriverUnload + * + * Driver cleanup funtion. + * + * @param Flags + * Flags describing the unload request + */ +NTSTATUS +FLTAPI +FilterUnload( + _In_ FLT_FILTER_UNLOAD_FLAGS Flags) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(Flags); + + DPRINT("DriverUnload\n"); + + TestFilterUnload(Flags); + + /* Close the port and unregister the filter */ + if (FilterData.ServerPort) + { + FltCloseCommunicationPort(FilterData.ServerPort); + FilterData.ServerPort = NULL; + } + if (FilterData.Filter) + { + FltUnregisterFilter(FilterData.Filter); + FilterData.Filter = NULL; + } + + if (Callbacks) + { + ExFreePoolWithTag(Callbacks, KMTEST_FILTER_POOL_TAG); + Callbacks = NULL; + } + + return STATUS_SUCCESS; +} + + +/** + * @name FilterInstanceSetup + * + * Volume attach routine + * + * @param FltObjects + * Filter Object Pointers + * Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers + * for the objects related to the current operation + * @param Flags + * Bitmask of flags that indicate why the instance is being attached + * @param VolumeDeviceType + * Device type of the file system volume + * @param VolumeFilesystemType + * File system type of the volume + * + * @return Status. + * Return STATUS_SUCCESS to attach or STATUS_FLT_DO_NOT_ATTACH to ignore + */ +NTSTATUS +FLTAPI +FilterInstanceSetup( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType) +{ +#if 0 + UCHAR VolPropBuffer[sizeof(FLT_VOLUME_PROPERTIES) + 512]; + PFLT_VOLUME_PROPERTIES VolumeProperties = (PFLT_VOLUME_PROPERTIES)VolPropBuffer; +#endif + PDEVICE_OBJECT DeviceObject = NULL; + UNICODE_STRING VolumeName; + ULONG ReportedSectorSize = 0; + ULONG SectorSize = 0; + NTSTATUS Status; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); + + RtlInitUnicodeString(&VolumeName, NULL); +#if 0 // FltGetVolumeProperties is not yet implemented + /* Get the properties of this volume */ + Status = FltGetVolumeProperties(Volume, + VolumeProperties, + sizeof(VolPropBuffer), + &LengthReturned); + if (NT_SUCCESS(Status)) + { + FLT_ASSERT((VolumeProperties->SectorSize == 0) || (VolumeProperties->SectorSize >= MIN_SECTOR_SIZE)); + SectorSize = max(VolumeProperties->SectorSize, MIN_SECTOR_SIZE); + ReportedSectorSize = VolumeProperties->SectorSize; + } + else + { + DPRINT1("Failed to get the volume properties : 0x%X", Status); + return Status; + } +#endif + /* Get the storage device object we want a name for */ + Status = FltGetDiskDeviceObject(FltObjects->Volume, &DeviceObject); + if (NT_SUCCESS(Status)) + { + /* Get the dos device name */ + Status = IoVolumeDeviceToDosName(DeviceObject, &VolumeName); + if (NT_SUCCESS(Status)) + { + DPRINT("VolumeDeviceType %lu, VolumeFilesystemType %lu, Real SectSize=0x%04x, Reported SectSize=0x%04x, Name=\"%wZ\"", + VolumeDeviceType, + VolumeFilesystemType, + SectorSize, + ReportedSectorSize, + &VolumeName); + + Status = TestInstanceSetup(FltObjects, + Flags, + VolumeDeviceType, + VolumeFilesystemType, + &VolumeName, + SectorSize, + ReportedSectorSize); + + /* The buffer was allocated by the IoMgr */ + ExFreePool(VolumeName.Buffer); + } + } + + return Status; +} + + +/** + * @name FilterQueryTeardown + * + * Volume detatch routine + * + * @param FltObjects + * Filter Object Pointers + * Pointer to an FLT_RELATED_OBJECTS structure that contains opaque pointers + * for the objects related to the current operation + * @param Flags + * Flag that indicates why the minifilter driver instance is being torn down + * + */ +NTSTATUS +FLTAPI +FilterQueryTeardown( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) +{ + PAGED_CODE(); + + TestQueryTeardown(FltObjects, Flags); + + /* We always allow a volume to detach */ + return STATUS_SUCCESS; +} + + +/* Public Routines **************************************/ + +NTSTATUS +KmtFilterRegisterCallbacks( + _In_ CONST FLT_OPERATION_REGISTRATION *OperationRegistration) +{ + ULONG Count = 0; + INT i; + + if (Callbacks) + { + return STATUS_ALREADY_REGISTERED; + } + + /* Count how many IRPs being registered */ + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + { + if (OperationRegistration[i].MajorFunction == IRP_MJ_OPERATION_END) + break; + Count++; + } + + /* Allocate enough pool to hold a copy of the array */ + Callbacks = ExAllocatePoolWithTag(NonPagedPool, + sizeof(FLT_OPERATION_REGISTRATION) * (Count + 1), + KMTEST_FILTER_POOL_TAG); + if (Callbacks == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the array, but using the our own pre/post callbacks */ + for (i = 0; i < Count; i++) + { + Callbacks[i].MajorFunction = OperationRegistration[i].MajorFunction; + Callbacks[i].Flags = OperationRegistration[i].Flags; + Callbacks[i].PreOperation = FilterPreOperation; + Callbacks[i].PostOperation = FilterPostOperation; + } + + /* Terminate the array */ + Callbacks[Count].MajorFunction = IRP_MJ_OPERATION_END; + + return STATUS_SUCCESS; +} + +NTSTATUS +KmtFilterRegisterContexts( + _In_ PFLT_CONTEXT_REGISTRATION ContextRegistration, + _In_ PVOID Callback) +{ + UNREFERENCED_PARAMETER(ContextRegistration); + UNREFERENCED_PARAMETER(Callback); + UNREFERENCED_PARAMETER(Contexts); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +KmtFilterRegisterComms( + _In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback, + _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback, + _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback, + _In_ LONG MaxClientConnections) +{ + FilterConnect = ConnectNotifyCallback; + FilterDisconnect = DisconnectNotifyCallback; + FilterMessage = MessageNotifyCallback; + MaxConnections = MaxClientConnections; + + return STATUS_SUCCESS; +} + + +/* Private Routines ******************************************/ + +FLT_PREOP_CALLBACK_STATUS +FLTAPI +FilterPreOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _Outptr_result_maybenull_ PVOID *CompletionContext) +{ + FLT_PREOP_CALLBACK_STATUS Status; + UCHAR MajorFunction; + INT i; + + Status = FLT_PREOP_SUCCESS_NO_CALLBACK; + MajorFunction = Data->Iopb->MajorFunction; + + for (i = 0; i < sizeof(Callbacks) / sizeof(Callbacks[0]); i++) + { + if (MajorFunction == Callbacks[i].MajorFunction) + { + // Call their pre-callback + Status = Callbacks[i].PreOperation(Data, + FltObjects, + CompletionContext); + } + } + + return Status; +} + +FLT_POSTOP_CALLBACK_STATUS +FLTAPI +FilterPostOperation( + _Inout_ PFLT_CALLBACK_DATA Data, + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_opt_ PVOID CompletionContext, + _In_ FLT_POST_OPERATION_FLAGS Flags) +{ + FLT_POSTOP_CALLBACK_STATUS Status; + UCHAR MajorFunction; + INT i; + + Status = FLT_POSTOP_FINISHED_PROCESSING; + MajorFunction = Data->Iopb->MajorFunction; + + for (i = 0; i < sizeof(Callbacks) / sizeof(Callbacks[0]); i++) + { + if (MajorFunction == Callbacks[i].MajorFunction) + { + // Call their post-callback + Status = Callbacks[i].PostOperation(Data, + FltObjects, + CompletionContext, + Flags); + } + } + + return Status; +}