Start to implement fltmgr tests [WIP] (#52)
authorGed Murphy <gedmurphy@gmail.com>
Thu, 12 Oct 2017 14:32:30 +0000 (15:32 +0100)
committerGitHub <noreply@github.com>
Thu, 12 Oct 2017 14:32:30 +0000 (15:32 +0100)
[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

16 files changed:
drivers/filters/CMakeLists.txt
drivers/filters/fltmgr/CMakeLists.txt
drivers/filters/fltmgr/Context.c
drivers/filters/fltmgr/Interface.c
drivers/filters/fltmgr/Messaging.c
drivers/filters/fltmgr/Misc.c [new file with mode: 0644]
drivers/filters/fltmgr/fltmgr.spec
modules/rostests/kmtests/CMakeLists.txt
modules/rostests/kmtests/fltmgr/CMakeLists.txt [new file with mode: 0644]
modules/rostests/kmtests/fltmgr/fltmgr_create/CMakeLists.txt [new file with mode: 0644]
modules/rostests/kmtests/fltmgr/fltmgr_create/fltmgr_create.c [new file with mode: 0644]
modules/rostests/kmtests/fltmgr/fltmgr_load/CMakeLists.txt [new file with mode: 0644]
modules/rostests/kmtests/fltmgr/fltmgr_load/fltmgr_load.c [new file with mode: 0644]
modules/rostests/kmtests/include/kmt_platform.h
modules/rostests/kmtests/include/kmt_test.h
modules/rostests/kmtests/kmtest_drv/kmtest_fsminifilter.c [new file with mode: 0644]

index 7b70050..2d135dd 100644 (file)
@@ -1,2 +1,2 @@
-#add_subdirectory(fltmgr)
+add_subdirectory(fltmgr)
 add_subdirectory(mountmgr)
index ea52718..f3d52e2 100644 (file)
@@ -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)
index ead64cd..7e6d03c 100644 (file)
@@ -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;
index 7854000..be1288a 100644 (file)
 
 /* 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
index e6e4473..97e6a94 100644 (file)
@@ -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 (file)
index 0000000..3ef1424
--- /dev/null
@@ -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 <debug.h>
+
+
+/* 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
index 2967a05..9e18cd5 100644 (file)
@@ -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)
+
index dfc6c98..d51ef00 100644 (file)
@@ -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 (file)
index 0000000..fd7a55e
--- /dev/null
@@ -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 (file)
index 0000000..4352939
--- /dev/null
@@ -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 (file)
index 0000000..6c28f3e
--- /dev/null
@@ -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 <gedmurphy@reactos.org>
+ */
+
+#include <kmt_test.h>
+#include <fltkernel.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+/* 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 (file)
index 0000000..7fa022d
--- /dev/null
@@ -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 (file)
index 0000000..7b9f523
--- /dev/null
@@ -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 <gedmurphy@reactos.org>
+ */
+
+#include <kmt_test.h>
+#include <fltkernel.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+/* 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;
+}
index 4efdc58..9e732c3 100644 (file)
@@ -25,6 +25,9 @@
 #include <ndk/obfuncs.h>
 #include <ndk/sefuncs.h>
 #include <ntstrsafe.h>
+#if defined KMT_FILTER_DRIVER
+#include <fltkernel.h>
+#endif
 
 #elif defined KMT_USER_MODE
 #define WIN32_NO_STATUS
index b2de5bc..5941676 100644 (file)
@@ -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 (file)
index 0000000..2de7f3b
--- /dev/null
@@ -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 <ged.murphy@reactos.org>
+ */
+
+#include <ntifs.h>
+#include <ndk/ketypes.h>
+#include <fltkernel.h>
+
+#define KMT_DEFINE_TEST_FUNCTIONS
+#include <kmt_test.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include <kmt_public.h>
+
+#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;
+}