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
This commit is contained in:
Ged Murphy 2017-10-12 15:32:30 +01:00 committed by GitHub
parent 5d0a122ff6
commit 9d15fb9279
16 changed files with 1139 additions and 8 deletions

View file

@ -1,2 +1,2 @@
#add_subdirectory(fltmgr) add_subdirectory(fltmgr)
add_subdirectory(mountmgr) add_subdirectory(mountmgr)

View file

@ -5,6 +5,7 @@ list(APPEND SOURCE
Interface.c Interface.c
Lib.c Lib.c
Messaging.c Messaging.c
Misc.c
Object.c Object.c
${CMAKE_CURRENT_BINARY_DIR}/fltmgr.def ${CMAKE_CURRENT_BINARY_DIR}/fltmgr.def
fltmgr.h) fltmgr.h)

View file

@ -27,7 +27,7 @@ static
NTSTATUS NTSTATUS
SetupContextHeader( SetupContextHeader(
_In_ PFLT_FILTER Filter, _In_ PFLT_FILTER Filter,
_In_ PFLT_CONTEXT_REGISTRATION ContextPtr, _In_ PCFLT_CONTEXT_REGISTRATION ContextPtr,
_Out_ PALLOCATE_CONTEXT_HEADER ContextHeader _Out_ PALLOCATE_CONTEXT_HEADER ContextHeader
); );
@ -43,9 +43,102 @@ NTSTATUS
FltpRegisterContexts(_In_ PFLT_FILTER Filter, FltpRegisterContexts(_In_ PFLT_FILTER Filter,
_In_ const FLT_CONTEXT_REGISTRATION *Context) _In_ const FLT_CONTEXT_REGISTRATION *Context)
{ {
UNREFERENCED_PARAMETER(Filter); PCFLT_CONTEXT_REGISTRATION ContextPtr;
UNREFERENCED_PARAMETER(Context); PALLOCATE_CONTEXT_HEADER ContextHeader, Prev;
return STATUS_NOT_IMPLEMENTED; 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 static
NTSTATUS NTSTATUS
SetupContextHeader(_In_ PFLT_FILTER Filter, SetupContextHeader(_In_ PFLT_FILTER Filter,
_In_ PFLT_CONTEXT_REGISTRATION ContextPtr, _In_ PCFLT_CONTEXT_REGISTRATION ContextPtr,
_Out_ PALLOCATE_CONTEXT_HEADER ContextHeader) _Out_ PALLOCATE_CONTEXT_HEADER ContextHeader)
{ {
return 0; return 0;

View file

@ -17,6 +17,18 @@
/* DATA *********************************************************************/ /* 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; DRIVER_INITIALIZE DriverEntry;
NTSTATUS NTSTATUS
NTAPI NTAPI

View file

@ -125,7 +125,7 @@ FltCreateCommunicationPort(_In_ PFLT_FILTER Filter,
FltObjectDereference(Filter); FltObjectDereference(Filter);
} }
return STATUS_NOT_IMPLEMENTED; return Status;
} }
_IRQL_requires_max_(PASSIVE_LEVEL) _IRQL_requires_max_(PASSIVE_LEVEL)

View file

@ -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;
}

View file

@ -2,4 +2,9 @@
@ stdcall FltRegisterFilter(ptr ptr ptr) @ stdcall FltRegisterFilter(ptr ptr ptr)
@ stdcall FltUnregisterFilter(ptr) @ stdcall FltUnregisterFilter(ptr)
@ stdcall FltCloseCommunicationPort(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)

View file

@ -5,6 +5,7 @@ include_directories(include)
# subdirectories containing special-purpose drivers # subdirectories containing special-purpose drivers
# #
add_subdirectory(example) add_subdirectory(example)
add_subdirectory(fltmgr)
add_subdirectory(hidparse) add_subdirectory(hidparse)
add_subdirectory(kernel32) add_subdirectory(kernel32)
add_subdirectory(ntos_cc) add_subdirectory(ntos_cc)

View file

@ -0,0 +1,3 @@
add_subdirectory(fltmgr_load)
add_subdirectory(fltmgr_create)

View file

@ -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)

View file

@ -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;
}

View file

@ -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)

View file

@ -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;
}

View file

@ -25,6 +25,9 @@
#include <ndk/obfuncs.h> #include <ndk/obfuncs.h>
#include <ndk/sefuncs.h> #include <ndk/sefuncs.h>
#include <ntstrsafe.h> #include <ntstrsafe.h>
#if defined KMT_FILTER_DRIVER
#include <fltkernel.h>
#endif
#elif defined KMT_USER_MODE #elif defined KMT_USER_MODE
#define WIN32_NO_STATUS #define WIN32_NO_STATUS

View file

@ -117,6 +117,29 @@ NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryP
VOID TestUnload(IN PDRIVER_OBJECT DriverObject); VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
#endif /* defined KMT_STANDALONE_DRIVER */ #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 #ifdef KMT_KERNEL_MODE
/* Device Extension layout */ /* Device Extension layout */
typedef struct typedef struct

View file

@ -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;
}