From 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Tue, 17 Mar 2015 19:50:07 -0700 Subject: Initial publish --- .../MetadataManager/MetadataManagerInit.c | 865 +++++++++++++++++++++ 1 file changed, 865 insertions(+) create mode 100644 filesys/miniFilter/MetadataManager/MetadataManagerInit.c (limited to 'filesys/miniFilter/MetadataManager/MetadataManagerInit.c') diff --git a/filesys/miniFilter/MetadataManager/MetadataManagerInit.c b/filesys/miniFilter/MetadataManager/MetadataManagerInit.c new file mode 100644 index 00000000..222159f7 --- /dev/null +++ b/filesys/miniFilter/MetadataManager/MetadataManagerInit.c @@ -0,0 +1,865 @@ +/*++ + +Copyright (c) 1999 - 2003 Microsoft Corporation + +Module Name: + + MetadataManagerInit.c + +Abstract: + + This is the main module of the kernel mode filter driver implementing + filter metadata management. + + +Environment: + + Kernel mode + + +--*/ + +#include "pch.h" + +// +// Global variables +// + +FMM_GLOBAL_DATA Globals; + + +// +// Local constants +// + +#define FMM_UNSUPPORTED_DEVICE_CHARACS FILE_FLOPPY_DISKETTE | \ + FILE_READ_ONLY_DEVICE | \ + FILE_VIRTUAL_VOLUME + +// +// Local function prototypes +// + +DRIVER_INITIALIZE DriverEntry; +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ); + +NTSTATUS +FmmUnload ( + _In_ FLT_FILTER_UNLOAD_FLAGS Flags + ); + +VOID +FmmContextCleanup ( + _In_ PFLT_CONTEXT Context, + _In_ FLT_CONTEXT_TYPE ContextType + ); + +NTSTATUS +FmmInstanceSetup ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType + ); + +NTSTATUS +FmmInstanceQueryTeardown ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags + ); + +VOID +FmmInstanceTeardownStart ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags + ); + +VOID +FmmInstanceTeardownComplete ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags + ); + +#if DBG + +VOID +FmmInitializeDebugLevel ( + _In_ PUNICODE_STRING RegistryPath + ); + +#endif + +// +// Assign text sections for each routine. +// + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) + +#if DBG +#pragma alloc_text(INIT, FmmInitializeDebugLevel) +#endif + +#pragma alloc_text(PAGE, FmmUnload) +#pragma alloc_text(PAGE, FmmContextCleanup) +#pragma alloc_text(PAGE, FmmInstanceSetup) +#pragma alloc_text(PAGE, FmmInstanceQueryTeardown) +#pragma alloc_text(PAGE, FmmInstanceTeardownStart) +#pragma alloc_text(PAGE, FmmInstanceTeardownComplete) +#endif + + +// +// If we need to verify that the metadata file is indeed open whenever +// a create suceeds on the volume, then we need to monitor all creates +// not just DASD creates. + +// If that is not the case, then we are better off telling filter manager +// to show us only DASD creates. That way we can avoid the performance +// penalty of being called for all creates when we only have use for DASD +// creates. +// + + +#if VERIFY_METADATA_OPENED + +#define OPERATION_REGISTRATION_FLAGS_FOR_CREATE (FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO) + +#else + +#define OPERATION_REGISTRATION_FLAGS_FOR_CREATE (FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO | FLTFL_OPERATION_REGISTRATION_SKIP_NON_DASD_IO) + +#endif + + + +// +// Filters callback routines +// + +FLT_OPERATION_REGISTRATION Callbacks[] = { + + { IRP_MJ_CREATE, + OPERATION_REGISTRATION_FLAGS_FOR_CREATE, + FmmPreCreate, + FmmPostCreate }, + + { IRP_MJ_CLEANUP, + FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO | FLTFL_OPERATION_REGISTRATION_SKIP_NON_DASD_IO, + FmmPreCleanup, + FmmPostCleanup }, + + { IRP_MJ_FILE_SYSTEM_CONTROL, + FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO | FLTFL_OPERATION_REGISTRATION_SKIP_NON_DASD_IO, + FmmPreFSControl, + FmmPostFSControl }, + + { IRP_MJ_DEVICE_CONTROL, + FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO, + FmmPreDeviceControl, + FmmPostDeviceControl }, + + { IRP_MJ_SHUTDOWN, + FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO, + FmmPreShutdown, + NULL }, + + { IRP_MJ_PNP, + FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO, + FmmPrePnp, + FmmPostPnp }, + + { IRP_MJ_OPERATION_END } +}; + +const FLT_CONTEXT_REGISTRATION ContextRegistration[] = { + + { FLT_INSTANCE_CONTEXT, + 0, + FmmContextCleanup, + FMM_INSTANCE_CONTEXT_SIZE, + FMM_INSTANCE_CONTEXT_TAG }, + + { FLT_CONTEXT_END } +}; + +// +// Filters registration data structure +// + +FLT_REGISTRATION FilterRegistration = { + + sizeof( FLT_REGISTRATION ), // Size + FLT_REGISTRATION_VERSION, // Version + 0, // Flags + ContextRegistration, // Context + Callbacks, // Operation callbacks + FmmUnload, // Filters unload routine + FmmInstanceSetup, // InstanceSetup routine + FmmInstanceQueryTeardown, // InstanceQueryTeardown routine + FmmInstanceTeardownStart, // InstanceTeardownStart routine + FmmInstanceTeardownComplete, // InstanceTeardownComplete routine + NULL, NULL, NULL // Unused naming support callbacks +}; + +// +// Filter driver initialization and unload routines +// + +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This is the initialization routine for this filter driver. It registers + itself with the filter manager and initializes all its global data structures. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - Unicode string identifying where the parameters for this + driver are located in the registry. + +Return Value: + + Returns STATUS_SUCCESS. + +--*/ +{ + NTSTATUS status; + + // + // Default to NonPagedPoolNx for non paged pool allocations where supported. + // + + ExInitializeDriverRuntime( DrvRtPoolNxOptIn ); + + + RtlZeroMemory( &Globals, sizeof( Globals ) ); + +#if DBG + + // + // Initialize global debug level + // + + FmmInitializeDebugLevel( RegistryPath ); + +#else + + UNREFERENCED_PARAMETER( RegistryPath ); + +#endif + + DebugTrace( DEBUG_TRACE_LOAD_UNLOAD, + ("[Fmm]: Driver being loaded\n") ); + + + + // + // Register with the filter manager + // + + status = FltRegisterFilter( DriverObject, + &FilterRegistration, + &Globals.Filter ); + + if (!NT_SUCCESS( status )) { + + return status; + } + + // + // Start filtering I/O + // + + status = FltStartFiltering( Globals.Filter ); + + if (!NT_SUCCESS( status )) { + + FltUnregisterFilter( Globals.Filter ); + } + + DebugTrace( DEBUG_TRACE_LOAD_UNLOAD, + ("[Fmm]: Driver loaded complete (Status = 0x%08X)\n", + status) ); + + return status; +} + +#if DBG + +VOID +FmmInitializeDebugLevel ( + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This routine tries to read the filter DebugLevel parameter from + the registry. This value will be found in the registry location + indicated by the RegistryPath passed in. + +Arguments: + + RegistryPath - The path key passed to the driver during DriverEntry. + +Return Value: + + None. + +--*/ +{ + OBJECT_ATTRIBUTES attributes; + HANDLE driverRegKey; + NTSTATUS status; + ULONG resultLength; + UNICODE_STRING valueName; + UCHAR buffer[sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + sizeof( LONG )]; + + Globals.DebugLevel = DEBUG_TRACE_ERROR; + + // + // Open the desired registry key + // + + InitializeObjectAttributes( &attributes, + RegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &driverRegKey, + KEY_READ, + &attributes ); + + if (NT_SUCCESS( status )) { + + // + // Read the DebugFlags value from the registry. + // + + RtlInitUnicodeString( &valueName, L"DebugLevel" ); + + status = ZwQueryValueKey( driverRegKey, + &valueName, + KeyValuePartialInformation, + buffer, + sizeof(buffer), + &resultLength ); + + if (NT_SUCCESS( status )) { + + Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); + } + + // + // Close the registry entry + // + + ZwClose( driverRegKey ); + + } + +} + +#endif + +NTSTATUS +FmmUnload ( + _In_ FLT_FILTER_UNLOAD_FLAGS Flags + ) +/*++ + +Routine Description: + + This is the unload routine for this filter driver. This is called + when the minifilter is about to be unloaded. We can fail this unload + request if this is not a mandatory unloaded indicated by the Flags + parameter. + +Arguments: + + Flags - Indicating if this is a mandatory unload. + +Return Value: + + Returns the final status of this operation. + +--*/ +{ + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + DebugTrace( DEBUG_TRACE_LOAD_UNLOAD, + ("[Fmm]: Unloading driver\n") ); + + + FltUnregisterFilter( Globals.Filter ); + Globals.Filter = NULL; + + return STATUS_SUCCESS; +} + +VOID +FmmContextCleanup ( + _In_ PFLT_CONTEXT Context, + _In_ FLT_CONTEXT_TYPE ContextType + ) +{ + PFMM_INSTANCE_CONTEXT instanceContext; + + PAGED_CODE(); + + switch(ContextType) { + + case FLT_INSTANCE_CONTEXT: + + instanceContext = Context; + + DebugTrace( DEBUG_TRACE_INFO, + ("[Fmm]: Cleaning up instance context for volume (Context = %p)\n", + instanceContext) ); + + ExDeleteResourceLite( &instanceContext->MetadataResource ); + + break; + + } + + DebugTrace( DEBUG_TRACE_INFO, + ("[Fmm]: Context cleanup complete.\n") ); + +} + +// +// Instance setup/teardown routines. +// + +NTSTATUS +FmmInstanceSetup ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_SETUP_FLAGS Flags, + _In_ DEVICE_TYPE VolumeDeviceType, + _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType + ) +/*++ + +Routine Description: + + This routine is called whenever a new instance is created on a volume. This + gives us a chance to decide if we need to attach to this volume or not. + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Flags describing the reason for this attach request. + +Return Value: + + STATUS_SUCCESS - attach + STATUS_FLT_DO_NOT_ATTACH - do not attach + +--*/ +{ + PFMM_INSTANCE_CONTEXT instanceContext = NULL; + PDEVICE_OBJECT diskDeviceObject; + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER( VolumeDeviceType ); + + PAGED_CODE(); + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance setup started (Volume = %p, Instance = %p)\n", + FltObjects->Volume, + FltObjects->Instance) ); + + // + // Check if the file system mounted is ntfs or fat + // + // The sample picks NTFS, FAT and ReFS as examples. The metadata + // handling demostrated in the sample can be applied + // to any file system + // + + if (VolumeFilesystemType != FLT_FSTYPE_NTFS && VolumeFilesystemType != FLT_FSTYPE_FAT && VolumeFilesystemType != FLT_FSTYPE_REFS) { + + // + // An unknown file system is mounted which we do not care + // + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Unsupported file system mounted (Volume = %p, Instance = %p)\n", + FltObjects->Volume, + FltObjects->Instance) ); + + status = STATUS_NOT_SUPPORTED; + goto FmmInstanceSetupCleanup; + } + + // + // Get the disk device object and make sure it is a disk device type and does not + // have any of the device characteristics we do not support. + // + // The sample picks the device characteristics to demonstrate how to access and + // check the device characteristics in order to make a decision to attach. The + // metadata handling demostrated in the sample is not limited to the + // characteristics we have used in the sample. + // + + status = FltGetDiskDeviceObject( FltObjects->Volume, &diskDeviceObject ); + + if (!NT_SUCCESS( status )) { + + DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR, + ("[Fmm]: Failed to get device object (Volume = %p, Status = 0x%08X)\n", + FltObjects->Volume, + status) ); + goto FmmInstanceSetupCleanup; + } + + if (diskDeviceObject->DeviceType != FILE_DEVICE_DISK || + FlagOn( diskDeviceObject->Characteristics, FMM_UNSUPPORTED_DEVICE_CHARACS )) { + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Unsupported device type or device characteristics (Volume = %p, Instance = %p DiskDeviceObjectDeviceTYpe = 0x%x, DiskDeviceObjectCharacteristics = 0x%x)\n", + FltObjects->Volume, + FltObjects->Instance, + diskDeviceObject->DeviceType, + diskDeviceObject->Characteristics) ); + + ObDereferenceObject( diskDeviceObject ); + status = STATUS_NOT_SUPPORTED; + goto FmmInstanceSetupCleanup; + } + + ObDereferenceObject( diskDeviceObject ); + + // + // Allocate and initialize the context for this volume + // + + status = FltAllocateContext( FltObjects->Filter, + FLT_INSTANCE_CONTEXT, + FMM_INSTANCE_CONTEXT_SIZE, + NonPagedPool, + &instanceContext ); + + if( !NT_SUCCESS( status )) { + + DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR, + ("[Fmm]: Failed to allocate instance context (Volume = %p, Instance = %p, Status = 0x%08X)\n", + FltObjects->Volume, + FltObjects->Instance, + status) ); + + goto FmmInstanceSetupCleanup; + } + + FLT_ASSERT( instanceContext != NULL ); + + RtlZeroMemory( instanceContext, FMM_INSTANCE_CONTEXT_SIZE ); + + instanceContext->Flags = 0; + instanceContext->Instance = FltObjects->Instance; + instanceContext->FilesystemType = VolumeFilesystemType; + instanceContext->Volume = FltObjects->Volume; + ExInitializeResourceLite( &instanceContext->MetadataResource ); + + + // + // Set the instance context. + // + + status = FltSetInstanceContext( FltObjects->Instance, + FLT_SET_CONTEXT_KEEP_IF_EXISTS, + instanceContext, + NULL ); + + if( !NT_SUCCESS( status )) { + + DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR, + ("[Fmm]: Failed to set instance context (Volume = %p, Instance = %p, Status = 0x%08X)\n", + FltObjects->Volume, + FltObjects->Instance, + status) ); + goto FmmInstanceSetupCleanup; + } + + // + // Acquire exclusive access to the instance context + // + + FmmAcquireResourceExclusive( &instanceContext->MetadataResource ); + + // + // Sanity - the instance context cannot be in a transition state during instance setup + // + + FLT_ASSERT( !FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION) ); + + // + // Open the filter metadata on disk + // + // The sample will attach to volume if it finds its metadata file on the volume. + // If this is a manual attachment then the sample filter will create its metadata + // file and attach to the volume. + // + + status = FmmOpenMetadata( instanceContext, + BooleanFlagOn( Flags, FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT ) ); + + // + // Relinquish exclusive access to the instance context + // + + FmmReleaseResource( &instanceContext->MetadataResource ); + + if (!NT_SUCCESS( status )) { + + goto FmmInstanceSetupCleanup; + } + + +FmmInstanceSetupCleanup: + + // + // If FltAllocateContext suceeded then we MUST release the context, + // irrespective of whether FltSetInstanceContext suceeded or not. + // + // FltAllocateContext increments the ref count by one. + // A successful FltSetInstanceContext increments the ref count by one + // and also associates the context with the file system object + // + // FltReleaseContext decrements the ref count by one. + // + // When FltSetInstanceContext succeeds, calling FltReleaseContext will + // leave the context with a ref count of 1 corresponding to the internal + // reference to the context from the file system structures + // + // When FltSetInstanceContext fails, calling FltReleaseContext will + // leave the context with a ref count of 0 which is correct since + // there is no reference to the context from the file system structures + // + + if ( instanceContext != NULL ) { + + FltReleaseContext( instanceContext ); + } + + + if (NT_SUCCESS( status )) { + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance setup complete (Volume = %p, Instance = %p). Filter will attach to the volume.\n", + FltObjects->Volume, + FltObjects->Instance) ); + } else { + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance setup complete (Volume = %p, Instance = %p). Filter will not attach to the volume.\n", + FltObjects->Volume, + FltObjects->Instance) ); + } + + // + // If this is an automatic attachment (mount, load, etc) and we are not + // attaching to this volume because we do not support attaching to this + // volume, then simply return STATUS_FLT_DO_NOT_ATTACH. If we return + // anything else fltmgr logs an event log indicating failure to attach. + // Since this failure to attach is not really an error, we do not want + // this failure to be logged as an error in the event log. For all other + // error codes besides the ones we consider "normal", if is ok for fltmgr + // to actually log the failure to attach. + // + // If this is a manual attach attempt that we have failed then we want to + // give the user a clear indication of why the attachment failed. Hence in + // this case, we will not override the error status with STATUS_FLT_DO_NOT_ATTACH + // irrespective of the cause of the failure to attach + // + + if (status == STATUS_NOT_SUPPORTED && + !FlagOn( Flags, FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT )) { + + status = STATUS_FLT_DO_NOT_ATTACH; + } + + return status; +} + + +NTSTATUS +FmmInstanceQueryTeardown ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags + ) +/*++ + +Routine Description: + + This is called when an instance is being manually deleted by a + call to FltDetachVolume or FilterDetach thereby giving us a + chance to fail that detach request. + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Indicating where this detach request came from. + +Return Value: + + Returns the status of this operation. + +--*/ +{ + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance query teardown started (Instance = %p)\n", + FltObjects->Instance) ); + + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance query teadown ended (Instance = %p)\n", + FltObjects->Instance) ); + return STATUS_SUCCESS; +} + + +VOID +FmmInstanceTeardownStart ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine is called at the start of instance teardown. + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Reason why this instance is been deleted. + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER( FltObjects ); + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance teardown start started (Instance = %p)\n", + FltObjects->Instance) ); + + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance teardown start ended (Instance = %p)\n", + FltObjects->Instance) ); +} + + +VOID +FmmInstanceTeardownComplete ( + _In_ PCFLT_RELATED_OBJECTS FltObjects, + _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags + ) +/*++ + +Routine Description: + + This routine is called at the end of instance teardown. + +Arguments: + + FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing + opaque handles to this filter, instance and its associated volume. + + Flags - Reason why this instance is been deleted. + +Return Value: + + None. + +--*/ +{ + PFMM_INSTANCE_CONTEXT instanceContext; + NTSTATUS status; + + UNREFERENCED_PARAMETER( Flags ); + + PAGED_CODE(); + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance teardown complete started (Instance = %p)\n", + FltObjects->Instance) ); + + status = FltGetInstanceContext( FltObjects->Instance, + &instanceContext ); + + if (NT_SUCCESS( status )) { + + // + // Acquire exclusive access to the instance context + // + + FmmAcquireResourceExclusive( &instanceContext->MetadataResource ); + + // + // Sanity - the instance context cannot be in a transition state during instance teardown complete + // + + FLT_ASSERT( !FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION) ); + + + if (FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED )) { + + // + // Close the metadata file + // + + FmmCloseMetadata( instanceContext ); + } + + + // + // Relinquish exclusive access to the instance context + // + + FmmReleaseResource( &instanceContext->MetadataResource ); + + FltReleaseContext( instanceContext ); + } + + DebugTrace( DEBUG_TRACE_INSTANCES, + ("[Fmm]: Instance teardown complete ended (Instance = %p)\n", + FltObjects->Instance) ); +} + -- cgit v1.3.1