diff --git a/filesys/miniFilter/MetadataManager/MetadataManagerInit.c b/filesys/miniFilter/MetadataManager/MetadataManagerInit.c index 222159f7c..dbedd3a89 100644 --- a/filesys/miniFilter/MetadataManager/MetadataManagerInit.c +++ b/filesys/miniFilter/MetadataManager/MetadataManagerInit.c @@ -86,8 +86,31 @@ FmmInstanceTeardownComplete ( #if DBG +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +FmmGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +FmmOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + VOID FmmInitializeDebugLevel ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -101,6 +124,8 @@ FmmInitializeDebugLevel ( #pragma alloc_text(INIT, DriverEntry) #if DBG +#pragma alloc_text(INIT, FmmGetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, FmmOpenServiceParametersKey) #pragma alloc_text(INIT, FmmInitializeDebugLevel) #endif @@ -115,11 +140,11 @@ FmmInitializeDebugLevel ( // // 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 +// 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 +// 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. // @@ -241,7 +266,7 @@ Return Value: // // Default to NonPagedPoolNx for non paged pool allocations where supported. // - + ExInitializeDriverRuntime( DrvRtPoolNxOptIn ); @@ -253,7 +278,7 @@ Return Value: // Initialize global debug level // - FmmInitializeDebugLevel( RegistryPath ); + FmmInitializeDebugLevel( DriverObject, RegistryPath ); #else @@ -299,8 +324,147 @@ Return Value: #if DBG +PFN_IoOpenDriverRegistryKey +FmmGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +FmmOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible + // + + pIoOpenDriverRegistryKey = FmmGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API + // + + status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + + } else { + + // + // Open specified service root key + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + + // + // Open the parameters key relative to service key path + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + } + + // + // Return value to caller + // + + *ServiceParametersKey = ParametersKey; + +cleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return status; + +} + VOID FmmInitializeDebugLevel ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -313,6 +477,9 @@ Routine Description: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -321,8 +488,7 @@ Return Value: --*/ { - OBJECT_ATTRIBUTES attributes; - HANDLE driverRegKey; + HANDLE driverRegKey = NULL; NTSTATUS status; ULONG resultLength; UNICODE_STRING valueName; @@ -331,47 +497,46 @@ Return Value: Globals.DebugLevel = DEBUG_TRACE_ERROR; // - // Open the desired registry key + // Open service parameters key to query values from. // - InitializeObjectAttributes( &attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); + status = FmmOpenServiceParametersKey( DriverObject, + RegistryPath, + &driverRegKey ); - status = ZwOpenKey( &driverRegKey, - KEY_READ, - &attributes ); + if (!NT_SUCCESS( status )) { - if (NT_SUCCESS( status )) { + driverRegKey = NULL; + goto cleanup; + } - // - // Read the DebugFlags value from the registry. - // + // + // Read the DebugFlags value from the registry. + // - RtlInitUnicodeString( &valueName, L"DebugLevel" ); + RtlInitUnicodeString( &valueName, L"DebugLevel" ); - status = ZwQueryValueKey( driverRegKey, - &valueName, - KeyValuePartialInformation, - buffer, - sizeof(buffer), - &resultLength ); + status = ZwQueryValueKey( driverRegKey, + &valueName, + KeyValuePartialInformation, + buffer, + sizeof(buffer), + &resultLength ); - if (NT_SUCCESS( status )) { + if (NT_SUCCESS( status )) { - Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); - } - - // - // Close the registry entry - // - - ZwClose( driverRegKey ); - + Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); } +cleanup: + + // + // Close the registry entry + // + + if (driverRegKey != NULL) { + ZwClose( driverRegKey ); + } } #endif @@ -678,22 +843,22 @@ Return Value: } // - // 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 + // 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 + // 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 && + if (status == STATUS_NOT_SUPPORTED && !FlagOn( Flags, FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT )) { status = STATUS_FLT_DO_NOT_ATTACH; diff --git a/filesys/miniFilter/MetadataManager/fmm.inf b/filesys/miniFilter/MetadataManager/fmm.inf index caf4bc8fc..ad231a8c1 100644 Binary files a/filesys/miniFilter/MetadataManager/fmm.inf and b/filesys/miniFilter/MetadataManager/fmm.inf differ diff --git a/filesys/miniFilter/NameChanger/NameChanger.inf b/filesys/miniFilter/NameChanger/NameChanger.inf index 36b99019b..7c0b2364c 100644 Binary files a/filesys/miniFilter/NameChanger/NameChanger.inf and b/filesys/miniFilter/NameChanger/NameChanger.inf differ diff --git a/filesys/miniFilter/NameChanger/nc.c b/filesys/miniFilter/NameChanger/nc.c index 9bcdc0944..c59742e53 100644 --- a/filesys/miniFilter/NameChanger/nc.c +++ b/filesys/miniFilter/NameChanger/nc.c @@ -988,7 +988,7 @@ Return Value: NcCompatInit( ); - Status = NcInitializeMapping( RegistryPath ); + Status = NcInitializeMapping( DriverObject, RegistryPath ); if (!NT_SUCCESS( Status )) { return Status; } diff --git a/filesys/miniFilter/NameChanger/nc.h b/filesys/miniFilter/NameChanger/nc.h index c2509faa9..47d582b44 100644 --- a/filesys/miniFilter/NameChanger/nc.h +++ b/filesys/miniFilter/NameChanger/nc.h @@ -59,7 +59,7 @@ // // Typedefs for dynamically imported routines -// +// typedef NTSTATUS @@ -277,27 +277,27 @@ typedef struct _NC_DIR_NOT_IO_CACHE { // Stores the state of the cache. // If the pointer is NULL, there is nothing in cache. // - + NC_CACHE_ENTRY Cache; // // If ReadyToIssue is TRUE, then its safe to fire off the request. // - + BOOLEAN ReadyToIssue; // // Io is a pointer to the callback data. // When ReadyToUse new io can be issued. // - + PFLT_CALLBACK_DATA Io; // // SystemBuffer is a pointer to a system buffer which will // be used to issue the IO. // - + char * SystemBuffer; ULONG SystemBufferLength; @@ -479,7 +479,7 @@ extern NC_GLOBAL_DATA NcGlobalData; // // Function declarations -// +// // // The following functions exist in nchelper.c @@ -487,18 +487,18 @@ extern NC_GLOBAL_DATA NcGlobalData; _When_(Data == NULL, _Pre_satisfies_(FileObject != NULL && Instance != NULL)) _When_(FileObject == NULL || Instance == NULL, _Pre_satisfies_(Data != NULL)) -NTSTATUS +NTSTATUS NcGetFileNameInformation( _In_opt_ PFLT_CALLBACK_DATA Data, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PFLT_INSTANCE Instance, _In_ FLT_FILE_NAME_OPTIONS NameOptions, - _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation + _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation ); NTSTATUS NcAllocateEResource( - _Out_ PERESOURCE * OutputLock + _Out_ PERESOURCE * OutputLock ); VOID @@ -600,8 +600,9 @@ NcBuildMapping ( // The following functions exist in ncinit.c // -NTSTATUS +NTSTATUS NcInitializeMapping( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -642,7 +643,7 @@ NcParseFinalComponent ( // NTSTATUS -NcStreamHandleContextAllocAndAttach( +NcStreamHandleContextAllocAndAttach( _In_ PFLT_FILTER Filter, _In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, @@ -709,7 +710,7 @@ NcDetermineStructureOffsets ( _In_ FILE_INFORMATION_CLASS Information ); -VOID +VOID NcCalculateDirectoryNotificationOffsets ( PDIRECTORY_CONTROL_OFFSETS Offsets ); @@ -762,7 +763,7 @@ NcSetNextEntryOffset ( _In_ CONST PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ BOOLEAN ForceLast); -VOID +VOID NcSetFileName ( _In_ PVOID Entry, _In_ PWSTR NewName, @@ -771,7 +772,7 @@ NcSetFileName ( _In_ BOOLEAN ForceLast ); -VOID +VOID NcSetShortName ( _In_ PVOID Entry, _In_ PWSTR NewShortName, @@ -800,7 +801,7 @@ NcEnumerateDirectorySetupInjection ( ); VOID -NcEnumerateDirectoryReset ( +NcEnumerateDirectoryReset ( _Inout_ PNC_DIR_QRY_CONTEXT dirCtx ); @@ -818,9 +819,9 @@ NcPopulateCacheEntry ( _Out_ PNC_CACHE_ENTRY Cache ); -PNC_CACHE_ENTRY -NcDirEnumSelectNextEntry ( - _Inout_ PNC_DIR_QRY_CONTEXT Context, +PNC_CACHE_ENTRY +NcDirEnumSelectNextEntry ( + _Inout_ PNC_DIR_QRY_CONTEXT Context, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, _In_ BOOLEAN IgnoreCase ); @@ -828,7 +829,7 @@ NcDirEnumSelectNextEntry ( BOOLEAN NcSkipName ( _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, - _In_ PNC_DIR_QRY_CONTEXT Context, + _In_ PNC_DIR_QRY_CONTEXT Context, _In_ NC_PATH_OVERLAP RealOverlap, _In_ PNC_MAPPING Mapping, _In_ BOOLEAN IgnoreCase @@ -836,22 +837,22 @@ NcSkipName ( _Success_(*Copied) ULONG -NcCopyDirEnumEntry ( - _Out_ PVOID UserBuffer, - _In_ ULONG UserOffset, - _In_ ULONG UserSize, +NcCopyDirEnumEntry ( + _Out_ PVOID UserBuffer, + _In_ ULONG UserOffset, + _In_ ULONG UserSize, _Inout_ PNC_CACHE_ENTRY Entry, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, - _Out_ PBOOLEAN Copied + _Out_ PBOOLEAN Copied ); NTSTATUS NcStreamHandleContextDirEnumCreate ( - _Out_ PNC_DIR_QRY_CONTEXT Context + _Out_ PNC_DIR_QRY_CONTEXT Context ); NTSTATUS -NcStreamHandleContextEnumSetup ( +NcStreamHandleContextEnumSetup ( _Inout_ PNC_DIR_QRY_CONTEXT DirContext, _In_ PNC_INSTANCE_CONTEXT InstanceContext, _In_ PDIRECTORY_CONTROL_OFFSETS Offsets, @@ -861,9 +862,9 @@ NcStreamHandleContextEnumSetup ( _Out_ PBOOLEAN FirstUsage ); -VOID +VOID NcStreamHandleContextEnumClose ( - _In_ PNC_DIR_QRY_CONTEXT DirContext + _In_ PNC_DIR_QRY_CONTEXT DirContext ); // @@ -885,19 +886,19 @@ NcPostNotifyDirectory ( _In_ FLT_POST_OPERATION_FLAGS Flags ); -NTSTATUS -NcStreamHandleContextNotCreate ( +NTSTATUS +NcStreamHandleContextNotCreate ( _Out_ PNC_DIR_NOT_CONTEXT Context ); -VOID +VOID NcStreamHandleContextNotCleanup( - _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext + _In_ PNC_STREAM_HANDLE_CONTEXT HandleContext ); -VOID +VOID NcStreamHandleContextNotClose ( - _In_ PNC_DIR_NOT_CONTEXT DirContext + _In_ PNC_DIR_NOT_CONTEXT DirContext ); // @@ -970,10 +971,10 @@ NcPostEnumUsnData ( NTSTATUS NcStreamHandleContextFindBySidCreate ( - _Out_ PNC_FIND_BY_SID_CONTEXT Context + _Out_ PNC_FIND_BY_SID_CONTEXT Context ); -VOID +VOID NcStreamHandleContextFindBySidClose ( _In_ PNC_FIND_BY_SID_CONTEXT Context ); diff --git a/filesys/miniFilter/NameChanger/ncinit.c b/filesys/miniFilter/NameChanger/ncinit.c index d34dc0f06..7d125498a 100644 --- a/filesys/miniFilter/NameChanger/ncinit.c +++ b/filesys/miniFilter/NameChanger/ncinit.c @@ -15,7 +15,31 @@ NcIs8DOT3Compatible ( _In_opt_ PUNICODE_STRING LongName ); +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +NcGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +NcOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + #ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, NcGetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, NcOpenServiceParametersKey) #pragma alloc_text(INIT, NcInitializeMapping) #pragma alloc_text(INIT, NcLoadRegistryString) #pragma alloc_text(INIT, NcIs8DOT3Compatible) @@ -278,8 +302,147 @@ NcIs8DOT3Compatible ( } +PFN_IoOpenDriverRegistryKey +NcGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +NcOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible + // + + pIoOpenDriverRegistryKey = NcGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API + // + + status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + + } else { + + // + // Open specified service root key + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + + // + // Open the parameters key relative to service key path + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + } + + // + // Return value to caller + // + + *ServiceParametersKey = ParametersKey; + +cleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return status; + +} + NTSTATUS NcInitializeMapping( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -292,6 +455,9 @@ Routine Descrition: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -301,7 +467,6 @@ Return Value: --*/ { NTSTATUS Status; - OBJECT_ATTRIBUTES Attributes; HANDLE DriverRegKey = NULL; UNICODE_STRING TempPath = EMPTY_UNICODE_STRING; USHORT Index; @@ -311,22 +476,16 @@ Return Value: RtlZeroMemory( &NcGlobalData, sizeof( NcGlobalData )); // - // Open the mapping registry key. + // Open service parameters key to query values from. // - InitializeObjectAttributes( &Attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); - - Status = ZwOpenKey( &DriverRegKey, - KEY_READ, - &Attributes ); + Status = NcOpenServiceParametersKey( DriverObject, + RegistryPath, + &DriverRegKey ); if (!NT_SUCCESS( Status )) { - FLT_ASSERT( DriverRegKey == NULL ); + DriverRegKey = NULL; goto NcInitializeMappingCleanup; } diff --git a/filesys/miniFilter/avscan/avscan.inf b/filesys/miniFilter/avscan/avscan.inf index 26fb6c22c..27091ee39 100644 Binary files a/filesys/miniFilter/avscan/avscan.inf and b/filesys/miniFilter/avscan/avscan.inf differ diff --git a/filesys/miniFilter/avscan/filter/avscan.c b/filesys/miniFilter/avscan/filter/avscan.c index 82e1045cd..3c96fd087 100644 --- a/filesys/miniFilter/avscan/filter/avscan.c +++ b/filesys/miniFilter/avscan/filter/avscan.c @@ -9,9 +9,9 @@ Module Name: Abstract: This is the main module of the avscan mini-filter driver. - This filter demonstrates how to implement a transaction-aware + This filter demonstrates how to implement a transaction-aware anti-virus filter. - + Av prefix denotes "Anti-virus" module. Environment: @@ -22,7 +22,7 @@ Module Name: #include #include "avscan.h" - + /************************************************************************* Local Function Prototypes *************************************************************************/ @@ -34,8 +34,32 @@ DriverEntry ( _In_ PUNICODE_STRING RegistryPath ); -NTSTATUS -AvSetConfiguration ( +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +AvGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +AvOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + + +NTSTATUS +AvSetConfiguration ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -112,20 +136,20 @@ AvKtmNotificationCallback ( _In_ PFLT_CONTEXT TransactionContext, _In_ ULONG TransactionNotification ); - + NTSTATUS AvScanAbortCallbackAsync ( _Unreferenced_parameter_ PFLT_INSTANCE Instance, _In_ PFLT_CONTEXT Context, _Unreferenced_parameter_ PFLT_CALLBACK_DATA Data ); - + // // Local routines // BOOLEAN -AvOperationsModifyingFile ( +AvOperationsModifyingFile ( _In_ PFLT_CALLBACK_DATA Data ); @@ -134,14 +158,14 @@ AvQueryTransactionOutcome( _In_ PKTRANSACTION Transaction, _Out_ PULONG TxOutcome ); - + NTSTATUS AvProcessPreviousTransaction ( _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PAV_STREAM_CONTEXT StreamContext ); - -NTSTATUS + +NTSTATUS AvProcessTransactionOutcome ( _Inout_ PAV_TRANSACTION_CONTEXT TransactionContext, _In_ ULONG TransactionOutcome @@ -154,9 +178,9 @@ AvLoadFileStateFromCache ( _Out_ LONG volatile* State, _Out_ PLONGLONG VolumeRevision, _Out_ PLONGLONG CacheRevision, - _Out_ PLONGLONG FileRevision + _Out_ PLONGLONG FileRevision ); - + NTSTATUS AvSyncCache ( _In_ PFLT_INSTANCE Instance, @@ -168,12 +192,12 @@ AvIsPrefetchEcpPresent ( _In_ PFLT_FILTER Filter, _In_ PFLT_CALLBACK_DATA Data ); - + BOOLEAN AvIsStreamAlternate ( _Inout_ PFLT_CALLBACK_DATA Data ); - + NTSTATUS AvScan ( _Inout_ PFLT_CALLBACK_DATA Data, @@ -183,24 +207,26 @@ AvScan ( _In_ BOOLEAN IsInTxWriter, _Inout_ PAV_STREAM_CONTEXT StreamContext ); - + VOID AvDoCancelScanAndRelease ( _In_ PAV_SCAN_CONTEXT ScanContext, _In_ PAV_SECTION_CONTEXT SectionContext ); - + NTSTATUS -AvSendUnloadingToUser ( +AvSendUnloadingToUser ( VOID - ); - + ); + // // Assign text sections for each routine. // #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(INIT, AvGetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, AvOpenServiceParametersKey) #pragma alloc_text(INIT, AvSetConfiguration) #pragma alloc_text(PAGE, AvUnload) #pragma alloc_text(PAGE, AvInstanceQueryTeardown) @@ -225,7 +251,7 @@ AvSendUnloadingToUser ( #pragma alloc_text(PAGE, AvDoCancelScanAndRelease) #pragma alloc_text(PAGE, AvSendAbortToUser) #pragma alloc_text(PAGE, AvSendUnloadingToUser) -#endif +#endif // // operation registration @@ -251,7 +277,7 @@ CONST FLT_OPERATION_REGISTRATION Callbacks[] = { 0, AvPreOperationCallback, NULL }, - + { IRP_MJ_FILE_SYSTEM_CONTROL, 0, AvPreFsControl, @@ -330,7 +356,7 @@ Return Value: NTSTATUS status; PAV_INSTANCE_CONTEXT instanceContext = NULL; BOOLEAN isOnCsv = FALSE; - + UNREFERENCED_PARAMETER( Flags ); PAGED_CODE(); @@ -348,13 +374,13 @@ Return Value: } // - // Determine if the filter is attaching to the hidden NTFS volume - // that corresponds to a CSV volume. If so do not attach. Note - // that it would be feasible for the filter to attach to this + // Determine if the filter is attaching to the hidden NTFS volume + // that corresponds to a CSV volume. If so do not attach. Note + // that it would be feasible for the filter to attach to this // volume as part of a distrubuted filter implementation but that // is beyond the scope of this sample. // - + if (VolumeFilesystemType == FLT_FSTYPE_NTFS) { isOnCsv = AvIsVolumeOnCsvDisk( FltObjects->Volume ); if (isOnCsv) { @@ -362,7 +388,7 @@ Return Value: return STATUS_FLT_DO_NOT_ATTACH; } } - + status = FltAllocateContext( Globals.Filter, FLT_INSTANCE_CONTEXT, AV_INSTANCE_CONTEXT_SIZE, @@ -373,46 +399,46 @@ Return Value: AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvInstanceSetup: allocate instance context failed. status = 0x%x\n", status) ); - + return STATUS_FLT_DO_NOT_ATTACH; } // // Setup instance context // - + RtlZeroMemory(instanceContext, AV_INSTANCE_CONTEXT_SIZE); instanceContext->Volume = FltObjects->Volume; instanceContext->Instance = FltObjects->Instance; instanceContext->VolumeFSType = VolumeFilesystemType; instanceContext->IsOnCsvMDS = isOnCsv; - + // // There will be a file state cache table for each NTFS volume instance. - // As for other file systems, file id is not unique, and thus we do - // not have cache for other kinds of file systems. Since the cache - // table is not mandatory to implement an anti-virus filter, we + // As for other file systems, file id is not unique, and thus we do + // not have cache for other kinds of file systems. Since the cache + // table is not mandatory to implement an anti-virus filter, we // only have the volatile cache for NTFS, CSVFS and REFS. // - // It is worth mentioning that the table is potentially very large. - // We use an AVL tree to improve insertion and query times. We do not - // set an upper bound for the size of the tree which is not optimal. + // It is worth mentioning that the table is potentially very large. + // We use an AVL tree to improve insertion and query times. We do not + // set an upper bound for the size of the tree which is not optimal. // Consider limiting the size of the tree for a production filter. // - + if (FS_SUPPORTS_FILE_STATE_CACHE( VolumeFilesystemType )) { - + // // Initialize file state cache in the instance context. // ExInitializeResourceLite( &instanceContext->Resource ); - + RtlInitializeGenericTable( &instanceContext->FileStateCacheTable, AvCompareEntry, AvAllocateGenericTableEntry, AvFreeGenericTableEntry, - NULL ); + NULL ); } status = FltSetInstanceContext( FltObjects->Instance, @@ -435,22 +461,22 @@ Return Value: } // - // Register this instance as a datascan filter. If this call - // fails the underlying filesystem does not support using + // Register this instance as a datascan filter. If this call + // fails the underlying filesystem does not support using // the filter manager datascan API. Currently only the // the namedpipe and mailslot file systems are unsupported. - // - + // + status = FltRegisterForDataScan( FltObjects->Instance ); if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvInstanceSetup: FltRegisterForDataScan failed. status = 0x%x\n", status) ); return STATUS_FLT_DO_NOT_ATTACH; } - + return STATUS_SUCCESS; } @@ -525,36 +551,36 @@ Return Value: PLIST_ENTRY next; PAV_SCAN_CONTEXT scanCtx = NULL; PAV_INSTANCE_CONTEXT instanceContext = NULL; - + UNREFERENCED_PARAMETER( Flags ); PAGED_CODE(); - + AV_DBG_PRINT( AVDBG_TRACE_DEBUG, ("[AV] AvInstanceTeardownStart: Entered\n") ); - + status = FltGetInstanceContext( FltObjects->Instance, &instanceContext ); - + if (!NT_SUCCESS( status )) { AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvInstanceTeardownStart: FltGetInstanceContext failed. status = 0x%x\n", status) ); return; } - + // // Search the scan context from the global list. // - + AvAcquireResourceExclusive( &Globals.ScanCtxListLock ); - + LIST_FOR_EACH_SAFE( scan, next, &Globals.ScanCtxListHead ) { - + scanCtx = CONTAINING_RECORD( scan, AV_SCAN_CONTEXT, List ); - + if (scanCtx->FilterInstance != FltObjects->Instance) { - + continue; } @@ -564,45 +590,45 @@ Return Value: status = AvSendAbortToUser(scanCtx->ScanThreadId, scanCtx->ScanId); - + // - // If we fail to send message to the user, then we - // do the cancel and cleanup by ourself; otherwise, - // the listening thread will call back to cleanup and + // If we fail to send message to the user, then we + // do the cancel and cleanup by ourself; otherwise, + // the listening thread will call back to cleanup and // I/O request thred will tear down the scan context. // - + if (!NT_SUCCESS( status ) || status == STATUS_TIMEOUT) { AvFinalizeScanAndSection(scanCtx); } } - + AvReleaseResource( &Globals.ScanCtxListLock ); - + // // Clean up the cache table if the volume supports one. // - + if (FS_SUPPORTS_FILE_STATE_CACHE( instanceContext->VolumeFSType )) { PAV_GENERIC_TABLE_ENTRY entry = NULL; AvAcquireResourceExclusive( &instanceContext->Resource ); - + while (!RtlIsGenericTableEmpty( &instanceContext->FileStateCacheTable ) ) { entry = RtlGetElementGenericTable(&instanceContext->FileStateCacheTable, 0); AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, - ("[AV] AvInstanceTeardownStart: %I64x,%I64x requesting deletion, state:%d\n", + ("[AV] AvInstanceTeardownStart: %I64x,%I64x requesting deletion, state:%d\n", entry->FileId.FileId64.UpperZeroes, entry->FileId.FileId64.Value, entry->InfectedState) ); RtlDeleteElementGenericTable(&instanceContext->FileStateCacheTable, entry); } - + AvReleaseResource( &instanceContext->Resource ); } - + FltReleaseContext( instanceContext ); - + FltDeleteInstanceContext( FltObjects->Instance, NULL ); } @@ -673,15 +699,13 @@ Return Value: NTSTATUS status = STATUS_SUCCESS; PSECURITY_DESCRIPTOR sd = NULL; - UNREFERENCED_PARAMETER( RegistryPath ); - AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] DriverEntry: Entered\n") ); // // Set default global configuration // - + RtlZeroMemory( &Globals, sizeof(Globals) ); InitializeListHead( &Globals.ScanCtxListHead ); ExInitializeResourceLite( &Globals.ScanCtxListLock ); @@ -691,7 +715,7 @@ Return Value: Globals.NetworkScanTimeout = 60000; #if DBG - + Globals.DebugLevel = 0xffffffff; // AVDBG_TRACE_ERROR | AVDBG_TRACE_DEBUG; #endif @@ -702,7 +726,7 @@ Return Value: // Set the filter configuration based on registry keys // - status = AvSetConfiguration( RegistryPath ); + status = AvSetConfiguration( DriverObject, RegistryPath ); if (!NT_SUCCESS( status )) { @@ -710,7 +734,7 @@ Return Value: ("[AV]: DriverEntry: SetConfiguration FAILED. status = 0x%x\n", status) ); leave; - } + } // // Register with FltMgr to tell it our callback routines @@ -721,19 +745,19 @@ Return Value: &Globals.Filter ); if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] DriverEntry: FltRegisterFilter FAILED. status = 0x%x\n", status) ); leave; } - + // // Builds a default security descriptor for use with FltCreateCommunicationPort. // - + status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS ); - + if (!NT_SUCCESS( status )) { @@ -744,34 +768,34 @@ Return Value: // // Prepare ports between kernel and user. // - + status = AvPrepareServerPort( sd, AvConnectForScan ); - + if (!NT_SUCCESS( status )) { AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] DriverEntry: AvPrepareServerPort Scan Port FAILED. status = 0x%x\n", status) ); leave; } - + status = AvPrepareServerPort( sd, AvConnectForAbort ); - + if (!NT_SUCCESS( status )) { AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] DriverEntry: AvPrepareServerPort Abort Port FAILED. status = 0x%x\n", status) ); leave; } - + status = AvPrepareServerPort( sd, AvConnectForQuery ); - + if (!NT_SUCCESS( status )) { AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] DriverEntry: AvPrepareServerPort Query Port FAILED. status = 0x%x\n", status) ); leave; } - + // // Start filtering i/o // @@ -784,16 +808,16 @@ Return Value: ("[AV] DriverEntry: FltStartFiltering FAILED. status = 0x%x\n", status) ); leave; } - + } finally { - + if ( sd != NULL ) { - + FltFreeSecurityDescriptor( sd ); } - + if (!NT_SUCCESS( status ) ) { - + if (NULL != Globals.ScanServerPort) { FltCloseCommunicationPort( Globals.ScanServerPort ); @@ -807,13 +831,13 @@ Return Value: FltCloseCommunicationPort( Globals.QueryServerPort ); } if (NULL != Globals.Filter) { - + FltUnregisterFilter( Globals.Filter ); Globals.Filter = NULL; } - ExDeleteResourceLite( &Globals.ScanCtxListLock ); - } + ExDeleteResourceLite( &Globals.ScanCtxListLock ); + } } return status; @@ -848,20 +872,20 @@ Return Value: AV_DBG_PRINT( AVDBG_TRACE_DEBUG, ("[AV] AvUnload: Entered\n") ); - + // // Traverse the scan context list, and cancel the scan if it exists. // - + AvAcquireResourceExclusive( &Globals.ScanCtxListLock ); Globals.Unloading = TRUE; AvReleaseResource( &Globals.ScanCtxListLock ); - + // - // This function will wait for the user to abort the outstanding scan and - // close the section + // This function will wait for the user to abort the outstanding scan and + // close the section // - + AvSendUnloadingToUser(); FltCloseCommunicationPort( Globals.ScanServerPort ); @@ -872,7 +896,7 @@ Return Value: Globals.QueryServerPort = NULL; FltUnregisterFilter( Globals.Filter ); // This will typically trigger instance tear down. Globals.Filter = NULL; - + ExDeleteResourceLite( &Globals.ScanCtxListLock ); return STATUS_SUCCESS; @@ -884,7 +908,7 @@ Return Value: *************************************************************************/ BOOLEAN -AvOperationsModifyingFile ( +AvOperationsModifyingFile ( _In_ PFLT_CALLBACK_DATA Data ) /*++ @@ -905,14 +929,14 @@ Return Value: --*/ { PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; - + PAGED_CODE(); switch(iopb->MajorFunction) { - + case IRP_MJ_WRITE: return TRUE; - + case IRP_MJ_FILE_SYSTEM_CONTROL: switch ( iopb->Parameters.FileSystemControl.Common.FsControlCode ) { case FSCTL_OFFLOAD_WRITE: @@ -922,7 +946,7 @@ Return Value: default: break; } break; - + case IRP_MJ_SET_INFORMATION: switch ( iopb->Parameters.SetFileInformation.FileInformationClass ) { case FileEndOfFileInformation: @@ -947,11 +971,11 @@ AvQueryTransactionOutcome( Routine Description: This is a helper function that qeury the KTM that how trasnaction was ended. - + Arguments: Transaction - Pointer to transaction object. - + TxOutcome - Output. Specifies the type of transaction outcome. Return Value: @@ -962,9 +986,9 @@ Return Value: HANDLE transactionHandle; NTSTATUS status; TRANSACTION_BASIC_INFORMATION txBasicInfo = {0}; - + PAGED_CODE(); - + status = ObOpenObjectByPointer( Transaction, OBJ_KERNEL_HANDLE, NULL, @@ -972,9 +996,9 @@ Return Value: *TmTransactionObjectType, KernelMode, &transactionHandle ); - + if (!NT_SUCCESS(status)) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvQueryTransactionOutcome: ObOpenObjectByPointer failed.\n") ); return status; @@ -986,18 +1010,18 @@ Return Value: sizeof(TRANSACTION_BASIC_INFORMATION), NULL ); if (!NT_SUCCESS(status)) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvQueryTransactionOutcome: ObOpenObjectByPointer failed.\n") ); goto Cleanup; } - + *TxOutcome = txBasicInfo.Outcome; - + Cleanup: ZwClose(transactionHandle); - + return status; } @@ -1012,46 +1036,46 @@ AvPropagateFileState( Routine Description: An inline function that propagate the TxState to State in stream context. - + Arguments: StreamContext - The stream context to be propagated. - + TransactionOutcome - TRANSACTION_OUTCOME enumeration indicating how transaction was ended. - + Return Value: None. - + --*/ { // // Only when the transaction was committed will we propagate the state. // - + if (TransactionOutcome == TransactionOutcomeCommitted) { - + AV_FILE_INFECTED_STATE oldTxState = InterlockedExchange( &StreamContext->TxState, AvFileModified ); switch (oldTxState) { case AvFileModified: case AvFileInfected: case AvFileNotInfected: - + // // Propagate the file state from TxState to State. // - + InterlockedExchange( &StreamContext->State, oldTxState ); break; case AvFileScanning: - + // // It is possible at KTM callback, file Tx state is still in scanning. - // All we can do here is to be conservative, that is to assume that + // All we can do here is to be conservative, that is to assume that // this commit did involve the modification of the file. // - + InterlockedExchange( &StreamContext->State, AvFileModified ); break; default: @@ -1059,15 +1083,15 @@ Return Value: break; } } - + // // Either cleanup or commited, we need to reset TxState to be default state. // - + SET_FILE_TX_MODIFIED( StreamContext ); } -NTSTATUS +NTSTATUS AvProcessTransactionOutcome ( _Inout_ PAV_TRANSACTION_CONTEXT TransactionContext, _In_ ULONG TransactionOutcome @@ -1076,21 +1100,21 @@ AvProcessTransactionOutcome ( Routine Description: - This is a helper function that process transaction commitment or rollback - + This is a helper function that process transaction commitment or rollback + Arguments: TransactionContext - Pointer to the minifilter driver's transaction context set at PostCreate. - + TransactionOutcome - Specifies the type of notifications. Should be either TransactionOutcomeCommitted or TransactionOutcomeAborted Return Value: - STATUS_SUCCESS - Returning this status value indicates that the minifilter + STATUS_SUCCESS - Returning this status value indicates that the minifilter driver is finished with the transaction. This is a success code. - + --*/ { PLIST_ENTRY scan; @@ -1099,7 +1123,7 @@ Return Value: PAV_TRANSACTION_CONTEXT oldTxCtx = NULL; PAGED_CODE(); - + // // Tranversing the stream context list, and // sync the TxState -> State. @@ -1107,21 +1131,21 @@ Return Value: // Either commit or rollback, we need to cleanup the list // Tear down stream context list inside transactionContext // - + AvAcquireResourceExclusive( TransactionContext->Resource ); - + LIST_FOR_EACH_SAFE( scan, next, &TransactionContext->ScListHead ) { - + streamContext = CONTAINING_RECORD( scan, AV_STREAM_CONTEXT, ListInTransaction ); oldTxCtx = InterlockedCompareExchangePointer( &streamContext->TxContext, NULL, TransactionContext ); if (oldTxCtx == TransactionContext) { - + // // The exchange pointer was successful // RemoveEntryList ( scan ); - + AV_DBG_PRINT( AVDBG_TRACE_DEBUG, ("[AV] AvProcessTransactionOutcome: Requesting deletion of entry in transaction context: %I64x,%I64x, modified: %d\n", streamContext->FileId.FileId64.UpperZeroes, @@ -1134,7 +1158,7 @@ Return Value: } SetFlag( TransactionContext->Flags, AV_TXCTX_LISTDRAINED ); AvReleaseResource( TransactionContext->Resource ); - + return STATUS_SUCCESS; } @@ -1145,20 +1169,20 @@ AvLoadFileStateFromCache ( _Out_ LONG volatile *State, _Out_ PLONGLONG VolumeRevision, _Out_ PLONGLONG CacheRevision, - _Out_ PLONGLONG FileRevision + _Out_ PLONGLONG FileRevision ) /*++ Routine Description: - This routine lookups the file state in the cache table. + This routine lookups the file state in the cache table. Arguments: Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL. - + FileID - The ID to lookup in the cache - + State - The cached state for the file Return Value: @@ -1171,7 +1195,7 @@ Return Value: PAV_INSTANCE_CONTEXT instanceContext = NULL; AV_GENERIC_TABLE_ENTRY query = {0}; PAV_GENERIC_TABLE_ENTRY entry = NULL; - + PAGED_CODE(); // @@ -1195,8 +1219,8 @@ Return Value: goto Cleanup; } - RtlCopyMemory( &query.FileId, FileId, sizeof(query.FileId) ); - + RtlCopyMemory( &query.FileId, FileId, sizeof(query.FileId) ); + AvAcquireResourceShared( &instanceContext->Resource ); entry = RtlLookupElementGenericTable( &instanceContext->FileStateCacheTable, @@ -1234,9 +1258,9 @@ Routine Description: Arguments: Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL. - + StreamContext - The stream context of the target file. - + Return Value: Returns the final status of this operation. @@ -1274,7 +1298,7 @@ Return Value: } // - // If originally, we failed to get the file id, + // If originally, we failed to get the file id, // then we do not cache it. // @@ -1286,7 +1310,7 @@ Return Value: // If the file system is NTFS, CSVFS or REFS, overwrite the entry in the // cache table if exists // - + RtlCopyMemory( &entry.FileId, &StreamContext->FileId, sizeof(entry.FileId) ); AvAcquireResourceExclusive( &instanceContext->Resource ); @@ -1302,9 +1326,9 @@ Return Value: // // - // It is possible that after entering the following else-if - // branch, thread A modifies the file, and before thread A - // closes the handle, thread B opens the same file. This + // It is possible that after entering the following else-if + // branch, thread A modifies the file, and before thread A + // closes the handle, thread B opens the same file. This // is fine because in such a case, the streamcontext exists // AvLoadFileStateFromCache would return the state in stream // context. Thus, thread B will need to scan the file. @@ -1327,7 +1351,7 @@ Return Value: Cleanup: FltReleaseContext( instanceContext ); - return status; + return status; } BOOLEAN @@ -1340,13 +1364,13 @@ AvIsPrefetchEcpPresent ( Routine Description: This local function will return if this data stream is alternate or not. - It by default returns FALSE if it fails to retrieve the name information + It by default returns FALSE if it fails to retrieve the name information from the file system. - + Arguments: Data - Pointer to the filter callbackData that is passed to us. - + Return Value: TRUE - This data stream is alternate. @@ -1357,13 +1381,13 @@ Return Value: NTSTATUS status; PECP_LIST ecpList; PVOID ecpContext; - + PAGED_CODE(); status = FltGetEcpListFromCallbackData( Filter, Data, &ecpList ); if (NT_SUCCESS(status) && (ecpList != NULL)) { - + status = FltFindExtraCreateParameter( Filter, ecpList, &GUID_ECP_PREFETCH_OPEN, @@ -1373,7 +1397,7 @@ Return Value: if (NT_SUCCESS(status)) { if (!FltIsEcpFromUserMode( Filter, ecpContext )) { - return TRUE; + return TRUE; } } } @@ -1390,13 +1414,13 @@ AvIsStreamAlternate( Routine Description: This local function will return if this data stream is alternate or not. - It by default returns FALSE if it fails to retrieve the name information + It by default returns FALSE if it fails to retrieve the name information from the file system. - + Arguments: Data - Pointer to the filter callbackData that is passed to us. - + Return Value: TRUE - This data stream is alternate. @@ -1409,32 +1433,32 @@ Return Value: PFLT_FILE_NAME_INFORMATION nameInfo = NULL; PAGED_CODE(); - + status = FltGetFileNameInformation( Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &nameInfo ); - + if (!NT_SUCCESS(status)) { - + goto Cleanup; } status = FltParseFileNameInformation( nameInfo ); if (!NT_SUCCESS(status)) { - + goto Cleanup; } AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, - ("[Av]: Dir: %wZ, FinalComponent: %wZ, Stream: %wZ, sLen: %d\n", + ("[Av]: Dir: %wZ, FinalComponent: %wZ, Stream: %wZ, sLen: %d\n", nameInfo->ParentDir, nameInfo->FinalComponent, nameInfo->Stream, nameInfo->Stream.Length) ); - + alternate = (nameInfo->Stream.Length > 0); - + Cleanup: if (nameInfo != NULL) { @@ -1466,13 +1490,13 @@ Routine Description: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. - + ScanMode - Can either be AvUserMode or AvKernelMode. - + IOMajorFunctionAtScan - Major function of an IRP. - + StreamContext - The stream context of the target file. - + Return Value: Returns the final status of this operation. @@ -1485,20 +1509,20 @@ Return Value: LONGLONG fileSize; FLT_VOLUME_PROPERTIES volumeProperties; ULONG volumePropertiesLength; - + PAGED_CODE(); - + // // Skip the empty file. // - + status = AvGetFileSize( FltObjects->Instance, - FltObjects->FileObject, + FltObjects->FileObject, &fileSize ); - if (NT_SUCCESS( status ) && + if (NT_SUCCESS( status ) && (0 == fileSize)) { - + AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[Av]: AvScan: Skip the EMPTY file.\n") ); @@ -1511,9 +1535,9 @@ Return Value: // We could cause deadlocks if the thread were suspended once // we have started scanning so enter a critical region. // - + FsRtlEnterFileSystem(); - + // // Wait here for an existing scan on the stream to complete. // We wait indefinitely since scans themselves will timeout. @@ -1531,7 +1555,7 @@ Return Value: // if (IS_FILE_NEED_SCAN( StreamContext )){ - + if (ScanMode == AvUserMode) { status = FltGetVolumeProperties( FltObjects->Volume, @@ -1541,21 +1565,21 @@ Return Value: if (!NT_SUCCESS(status)) { volumeProperties.DeviceType = FILE_DEVICE_NETWORK; } - + // - // If the scan mode is user mode, the section context will + // If the scan mode is user mode, the section context will // be created as needed (at MessageNotification callback). // - // Setting the file state will be done at + // Setting the file state will be done at // MessageNotification callback as well. // - + status = AvScanInUser( Data, FltObjects, IOMajorFunctionAtScan, IsInTxWriter, volumeProperties.DeviceType ); - + if (!NT_SUCCESS( status ) || status == STATUS_TIMEOUT) { AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, @@ -1564,37 +1588,37 @@ Return Value: } else { - status = AvScanInKernel( FltObjects, + status = AvScanInKernel( FltObjects, IOMajorFunctionAtScan, IsInTxWriter, StreamContext ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] AvScan: failed to scan the file.\n") ); } } - + } // // Signal ScanSynchronizationEvent to release any con-current scan of the stream, - // - KeSetEvent( StreamContext->ScanSynchronizationEvent, 0, FALSE ); + // + KeSetEvent( StreamContext->ScanSynchronizationEvent, 0, FALSE ); } else if (IOMajorFunctionAtScan == IRP_MJ_CREATE) { // - // I/O requesting thread if waiting on synchronization event is cancelled, + // I/O requesting thread if waiting on synchronization event is cancelled, // we need to clean up the file object too. // AvCancelFileOpen(Data, FltObjects, status); } - + FsRtlExitFileSystem(); - + return status; } @@ -1612,7 +1636,7 @@ Routine Description: Arguments: ScanContext - The scan context. - + SectionContext - The section context associated with the scan context. Return Value: @@ -1623,9 +1647,9 @@ Return Value: { NTSTATUS status; PAV_STREAM_CONTEXT streamContext = NULL; - + PAGED_CODE(); - + AvFinalizeSectionContext( SectionContext ); status = FltGetStreamContext( ScanContext->FilterInstance, @@ -1633,21 +1657,21 @@ Return Value: &streamContext ); if (NT_SUCCESS( status )) { - + KeSetEvent( streamContext->ScanSynchronizationEvent, 0, FALSE ); FltReleaseContext( streamContext ); } - + // // Release I/O request thread. // - + KeSetEvent( &ScanContext->ScanCompleteNotification, 0, FALSE ); return; } NTSTATUS -AvSendAbortToUser ( +AvSendAbortToUser ( _In_ ULONG ScanThreadId, _In_ LONGLONG ScanId ) @@ -1656,7 +1680,7 @@ AvSendAbortToUser ( Routine Description: This routine sends an abortion message to the user scan thread. - The cancel callback is asynchronous and thus we send which + The cancel callback is asynchronous and thus we send which scan id to abort; otherwise the worker thread in the user may abort the 'next' scan task. @@ -1676,19 +1700,19 @@ Return Value: ULONG replyLength = 0; LARGE_INTEGER timeout = {0}; AV_SCANNER_NOTIFICATION notification = {0}; - + PAGED_CODE(); - + notification.Message = AvMsgAbortScanning; notification.ScanThreadId = ScanThreadId; notification.ScanId = ScanId; - + timeout.QuadPart = -((LONGLONG)10) * (LONGLONG)1000 * (LONGLONG)1000; // 1s - + // // Tell the user-scanner to abort the scan. // - + status = FltSendMessage( Globals.Filter, &Globals.AbortClientPort, ¬ification, @@ -1697,11 +1721,11 @@ Return Value: &replyLength, &timeout ); - - if (!NT_SUCCESS( status ) || + + if (!NT_SUCCESS( status ) || (status == STATUS_TIMEOUT)) { - - if ((status != STATUS_PORT_DISCONNECTED) && + + if ((status != STATUS_PORT_DISCONNECTED) && (status != STATUS_TIMEOUT)) { AV_DBG_PRINT( AVDBG_TRACE_ERROR, @@ -1714,7 +1738,7 @@ Return Value: } NTSTATUS -AvSendUnloadingToUser ( +AvSendUnloadingToUser ( VOID ) /*++ @@ -1737,19 +1761,19 @@ Return Value: NTSTATUS status = STATUS_SUCCESS; ULONG replyLength = sizeof(ULONG); AV_SCANNER_NOTIFICATION notification = {0}; - + PAGED_CODE(); - + notification.Message = AvMsgFilterUnloading; - + // // Tell the user-scanner that we are unloading the filter. // and waits for its reply. // - + AV_DBG_PRINT( AVDBG_TRACE_DEBUG, ("[Av]: AvSendUnloadingToUser: BEFORE...\n") ); - + status = FltSendMessage( Globals.Filter, &Globals.AbortClientPort, ¬ification, @@ -1757,17 +1781,17 @@ Return Value: &abortThreadId, &replyLength, NULL ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[Av]: AvSendUnloadingToUser: Failed to FltSendMessage.\n, 0x%08x\n", status) ); } - + AV_DBG_PRINT( AVDBG_TRACE_DEBUG, ("[Av]: AvSendUnloadingToUser: After...\n") ); - + return status; } @@ -1785,8 +1809,8 @@ AvPreOperationCallback ( Routine Description: - This routine is the registered callback routine for filtering - the "write" operation, i.e. the operations that have potentials + This routine is the registered callback routine for filtering + the "write" operation, i.e. the operations that have potentials to modify the file. This is non-pageable because it could be called on the paging path @@ -1799,7 +1823,7 @@ Routine Description: opaque handles to this filter, instance, its associated volume and file object. - CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or + CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to the corresponding post-operation callback routine. Otherwise, it must be NULL. @@ -1813,21 +1837,21 @@ Return Value: PAV_STREAM_CONTEXT streamContext = NULL; PAV_STREAMHANDLE_CONTEXT streamHandleContext = NULL; ULONG flags; - + UNREFERENCED_PARAMETER( CompletionContext ); AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] AvPreOperationCallback: Entered\n") ); if (!AvOperationsModifyingFile(Data)) { - + return FLT_PREOP_SUCCESS_NO_CALLBACK; } // // Skip prefetcher handles to avoid deadlocks // - + status = FltGetStreamHandleContext( FltObjects->Instance, FltObjects->FileObject, &streamHandleContext ); @@ -1836,20 +1860,20 @@ Return Value: flags = streamHandleContext->Flags; FltReleaseContext( streamHandleContext ); - + if (FlagOn( flags, AV_FLAG_PREFETCH )) { return FLT_PREOP_SUCCESS_NO_CALLBACK; - } + } } status = FltGetStreamContext( FltObjects->Instance, FltObjects->FileObject, &streamContext ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, - ("[AV] AvPreOperationCallback: get stream context failed. rq: %d\n", + ("[AV] AvPreOperationCallback: get stream context failed. rq: %d\n", Data->Iopb->MajorFunction) ); return FLT_PREOP_SUCCESS_NO_CALLBACK; @@ -1858,10 +1882,10 @@ Return Value: // // If this operation is performed in a transacted writer view. // - + if ((streamContext->TxContext != NULL) && (FltObjects->Transaction != NULL)) { - + #if DBG PAV_TRANSACTION_CONTEXT transactionContext = NULL; @@ -1870,32 +1894,32 @@ Return Value: &transactionContext ); FLT_ASSERTMSG( "Transaction context should not fail, because it is supposed to be created at post create.\n", NT_SUCCESS( statusTx )); - FLT_ASSERTMSG( "The file's TxCtx should be identical with the target TxCtx.\n", + FLT_ASSERTMSG( "The file's TxCtx should be identical with the target TxCtx.\n", streamContext->TxContext == transactionContext); if (NT_SUCCESS( statusTx )) { FltReleaseContext( transactionContext ); } - + #endif // DBG - + // - // Instead of updating State, we update TxState here, + // Instead of updating State, we update TxState here, // because the file is part of a transaction writer // - + SET_FILE_TX_MODIFIED( streamContext ); - + } else { - + // // Consider an optimization for the case where another thread // is already scanning the file as it is being modified here. // - + SET_FILE_MODIFIED( streamContext ); } - + FltReleaseContext( streamContext ); return FLT_PREOP_SUCCESS_NO_CALLBACK; @@ -1922,7 +1946,7 @@ Routine Description: opaque handles to this filter, instance, its associated volume and file object. - CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or + CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to the corresponding post-operation callback routine. Otherwise, it must be NULL. @@ -1934,15 +1958,15 @@ Return Value: { PAGED_CODE(); - + if (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode == FSCTL_TXFS_SAVEPOINT_INFORMATION ) { - - // + + // // We explicitly fail the request of save point here since we // are deprecating savepoint support for the OS version targeted - // for this filter. + // for this filter. // - + Data->IoStatus.Status = STATUS_NOT_SUPPORTED; return FLT_PREOP_COMPLETE; } @@ -1960,7 +1984,7 @@ AvPreCreate ( Routine Description: This routine is the pre-create completion routine. - + Arguments: @@ -1970,7 +1994,7 @@ Routine Description: opaque handles to this filter, instance, its associated volume and file object. - CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or + CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to the corresponding post-operation callback routine. Otherwise, it must be NULL. @@ -1985,33 +2009,33 @@ Return Value: ULONG_PTR stackHigh; PFILE_OBJECT FileObject = Data->Iopb->TargetFileObject; AV_STREAMHANDLE_CONTEXT streamHandleContext; - - + + PAGED_CODE(); AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] AvPreCreate: Entered\n") ); streamHandleContext.Flags = 0; - + // // Stack file objects are never scanned. // IoGetStackLimits( &stackLow, &stackHigh ); - if (((ULONG_PTR)FileObject > stackLow) && + if (((ULONG_PTR)FileObject > stackLow) && ((ULONG_PTR)FileObject < stackHigh)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } - + // // Directory opens don't need to be scanned. // if (FlagOn( Data->Iopb->Parameters.Create.Options, FILE_DIRECTORY_FILE )) { - + return FLT_PREOP_SUCCESS_NO_CALLBACK; } @@ -2020,27 +2044,27 @@ Return Value: // if ( FlagOn( Data->Iopb->OperationFlags, SL_OPEN_TARGET_DIRECTORY )) { - + return FLT_PREOP_SUCCESS_NO_CALLBACK; } - + // // Skip paging files. // if (FlagOn( Data->Iopb->OperationFlags, SL_OPEN_PAGING_FILE )) { - + return FLT_PREOP_SUCCESS_NO_CALLBACK; } // - // Skip scanning DASD opens + // Skip scanning DASD opens // - + if (FlagOn( FltObjects->FileObject->Flags, FO_VOLUME_OPEN )) { - return FLT_PREOP_SUCCESS_NO_CALLBACK; - } + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } // // Skip scanning any files being opened by CSVFS for its downlevel @@ -2049,10 +2073,10 @@ Return Value: // if (AvIsCsvDlEcpPresent( FltObjects->Filter, Data ) ) { - return FLT_PREOP_SUCCESS_NO_CALLBACK; + return FLT_PREOP_SUCCESS_NO_CALLBACK; } - + // // Flag prefetch handles so they can be skipped. Performing IO // using a prefetch fileobject could lead to a deadlock. @@ -2060,7 +2084,7 @@ Return Value: if (AvIsPrefetchEcpPresent( FltObjects->Filter, Data )) { - SetFlag( streamHandleContext.Flags, AV_FLAG_PREFETCH ); + SetFlag( streamHandleContext.Flags, AV_FLAG_PREFETCH ); } *CompletionContext = (PVOID)streamHandleContext.Flags; @@ -2069,17 +2093,17 @@ Return Value: // Perform any CSVFS pre create processing // AvPreCreateCsvfs( Data, FltObjects ); - + // // return status can be safely ignored // - + // - // Return FLT_PREOP_SYNCHRONIZE at PreCreate to ensure PostCreate - // is in the same thread at passive level. + // Return FLT_PREOP_SYNCHRONIZE at PreCreate to ensure PostCreate + // is in the same thread at passive level. // EResource can't be acquired at DPC. // - + return FLT_PREOP_SYNCHRONIZE; } @@ -2093,8 +2117,8 @@ AvProcessPreviousTransaction ( Routine Description: - This routine is transaction related implementation, and is expected to be - invoked at post-create. Note that this function will enlist the newly + This routine is transaction related implementation, and is expected to be + invoked at post-create. Note that this function will enlist the newly allocated transaction context via FltEnlistInTransaction if it needs to. Arguments: @@ -2114,45 +2138,45 @@ Return Value: NTSTATUS status = STATUS_SUCCESS; PAV_TRANSACTION_CONTEXT oldTxCtx = NULL; PAV_TRANSACTION_CONTEXT transactionContext = NULL; - + PAGED_CODE(); - if (FltObjects->Transaction != NULL ) { - + if (FltObjects->Transaction != NULL ) { + // // Get transaction context // status = AvFindOrCreateTransactionContext( FltObjects, &transactionContext ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvProcessPreviousTransaction: AvFindOrCreateTransactionContext FAILED\n") ); transactionContext = NULL; goto Cleanup; } - + // // Enlist it if haven't. // - + if (! FlagOn(transactionContext->Flags, AV_TXCTX_ENLISTED) ) { // - // You can also consider to register TRANSACTION_NOTIFY_PREPARE, + // You can also consider to register TRANSACTION_NOTIFY_PREPARE, // and scan the file at TRANSACTION_NOTIFY_PREPARE callback if it was modified. // - + status = FltEnlistInTransaction( FltObjects->Instance, FltObjects->Transaction, transactionContext, TRANSACTION_NOTIFY_COMMIT_FINALIZE | TRANSACTION_NOTIFY_ROLLBACK ); - + if (!NT_SUCCESS( status ) && (status != STATUS_FLT_ALREADY_ENLISTED)) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvProcessPreviousTransaction: FltEnlistInTransaction FAILED!!!!\n") ); goto Cleanup; @@ -2181,113 +2205,113 @@ Return Value: // oldTxCtx : NULL // transCtx : NULL // - + // // Synchronize the replacement of StreamContext->TxContext with KTM callback. // - + oldTxCtx = InterlockedExchangePointer( &StreamContext->TxContext, transactionContext ); - + if (oldTxCtx != transactionContext) { // case 1,2,3 - + // - // txOutcome is by default set as committed because we are conservative about - // propagating the file state if AvQueryTransactionOutcome failed, it may cause + // txOutcome is by default set as committed because we are conservative about + // propagating the file state if AvQueryTransactionOutcome failed, it may cause // redundant scan but will not overlook infected file anyway. // - + ULONG txOutcome = TransactionOutcomeCommitted; if ( oldTxCtx == NULL ) { // case 1 - + // This file was not linked in a transaction context yet, and is about to. // // Increment TxContext's reference count because stream context has a reference to it. // - + FltReferenceContext ( transactionContext ); - + // // Before insertion into the FcList in transaction context, we increment stream context's ref count // - + AvAcquireResourceExclusive( transactionContext->Resource ); - + if (!FlagOn(transactionContext->Flags, AV_TXCTX_LISTDRAINED)) { - + FltReferenceContext ( StreamContext ); // Q InsertTailList( &transactionContext->ScListHead, &StreamContext->ListInTransaction ); } - + AvReleaseResource( transactionContext->Resource ); - + goto Cleanup; } // case 2,3 - + // - // We have to query transaction outcome in order to know how we + // We have to query transaction outcome in order to know how we // can process the previously outstanding transaction context. // - + status = AvQueryTransactionOutcome( oldTxCtx->Transaction, &txOutcome ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvProcessPreviousTransaction: AvQueryTransactionOutcome FAILED!!!!\n") ); - + // - // We have exchanged the pointer anyway, if we cannot query its outcome, + // We have exchanged the pointer anyway, if we cannot query its outcome, // we have to go through. // } - + AvAcquireResourceExclusive( oldTxCtx->Resource ); RemoveEntryList ( &StreamContext->ListInTransaction ); AvReleaseResource( oldTxCtx->Resource ); - + AvPropagateFileState ( StreamContext, txOutcome ); - + if ( transactionContext ) { // case 3 - + FltReferenceContext( transactionContext ); - + AvAcquireResourceExclusive( transactionContext->Resource ); if (!FlagOn(transactionContext->Flags, AV_TXCTX_LISTDRAINED)) { - + InsertTailList( &transactionContext->ScListHead, &StreamContext->ListInTransaction ); } else { - + FltReleaseContext( StreamContext ); } - + AvReleaseResource( transactionContext->Resource ); - + } else { // case 2 - + FltReleaseContext ( StreamContext ); // Release reference count at Q } - + // case 2,3 - + FltReleaseContext( oldTxCtx ); // Release reference count in stream context originally. - + } - + // // We don't care about case 4, 5. // - + Cleanup: if (transactionContext) { - + FltReleaseContext( transactionContext ); // Release the ref count grabbed at AvFindOrCreateTransactionContext(...) } @@ -2307,8 +2331,8 @@ Routine Description: This routine is the post-create completion routine. In this routine, stream context and/or transaction context shall be created if not exits. - - Note that we only allocate and set the stream context to filter manager + + Note that we only allocate and set the stream context to filter manager at post create. Arguments: @@ -2332,7 +2356,7 @@ Return Value: NTSTATUS status = Data->IoStatus.Status; BOOLEAN isDir = FALSE; BOOLEAN isTxWriter = FALSE; - + PAV_STREAM_CONTEXT streamContext = NULL; PAV_STREAM_CONTEXT oldStreamContext = NULL; PAV_STREAMHANDLE_CONTEXT streamHandleContext = NULL; @@ -2340,15 +2364,15 @@ Return Value: BOOLEAN updateRevisionNumbers; LONGLONG VolumeRevision, CacheRevision, FileRevision; - + UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( Flags ); - + PAGED_CODE(); - + if (!NT_SUCCESS( status ) || (status == STATUS_REPARSE)) { - + // // File Creation may fail. // @@ -2358,7 +2382,7 @@ Return Value: return FLT_POSTOP_FINISHED_PROCESSING; } - + // // After creation, skip it if it is directory. // @@ -2366,29 +2390,29 @@ Return Value: status = FltIsDirectory( FltObjects->FileObject, FltObjects->Instance, &isDir ); - + // // If FltIsDirectory failed, we do not know if it is a directoy, // we let it go through because if it is a directory, it will fail // at section creation anyway. // - + if ( NT_SUCCESS( status ) && isDir ) { - + return FLT_POSTOP_FINISHED_PROCESSING; } // // We skip the encrypted file open without FILE_WRITE_DATA and FILE_READ_DATA - // This is because if application calls OpenEncryptedFileRaw(...) for backup, - // it won't have to decrypt the file. In such case, if we scan it, we will hit + // This is because if application calls OpenEncryptedFileRaw(...) for backup, + // it won't have to decrypt the file. In such case, if we scan it, we will hit // an assertion error in NTFS because it does not have the encryption context. // Thus, we have to skip the encrypted file not open for read/write. // - - if (!(FlagOn(desiredAccess, FILE_WRITE_DATA)) && + + if (!(FlagOn(desiredAccess, FILE_WRITE_DATA)) && !(FlagOn(desiredAccess, FILE_READ_DATA)) ) { - + BOOLEAN encrypted = FALSE; status = AvGetFileEncrypted( FltObjects->Instance, FltObjects->FileObject, @@ -2399,18 +2423,18 @@ Return Value: ("[AV] AvPostCreate: AvGetFileEncrypted FAILED!! \n0x%x\n", status) ); } if (encrypted) { - + return FLT_POSTOP_FINISHED_PROCESSING; } } - + // - // In this sample, we skip the alternate data stream. However, you may decide + // In this sample, we skip the alternate data stream. However, you may decide // to scan it and modify accordingly. // - + if (AvIsStreamAlternate( Data )) { - + return FLT_POSTOP_FINISHED_PROCESSING; } @@ -2422,20 +2446,20 @@ Return Value: if (FlagOn((ULONG_PTR)CompletionContext, AV_FLAG_PREFETCH)) { if (!FltSupportsStreamHandleContexts( FltObjects->FileObject )) { - + return FLT_POSTOP_FINISHED_PROCESSING; } - status = AvCreateStreamHandleContext( FltObjects->Filter, + status = AvCreateStreamHandleContext( FltObjects->Filter, &streamHandleContext ); if (!NT_SUCCESS(status)) { - - return FLT_POSTOP_FINISHED_PROCESSING; + + return FLT_POSTOP_FINISHED_PROCESSING; } SetFlag( streamHandleContext->Flags, AV_FLAG_PREFETCH ); - + status = FltSetStreamHandleContext( FltObjects->Instance, FltObjects->FileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, @@ -2445,84 +2469,84 @@ Return Value: FltReleaseContext( streamHandleContext ); if (!NT_SUCCESS(status)) { - + // // Shouldn't find the handle already set // - + ASSERT( status != STATUS_FLT_CONTEXT_ALREADY_DEFINED ); } - return FLT_POSTOP_FINISHED_PROCESSING; + return FLT_POSTOP_FINISHED_PROCESSING; } - + // // Find or create a stream context // status = FltGetStreamContext( FltObjects->Instance, FltObjects->FileObject, - &streamContext ); + &streamContext ); if (status == STATUS_NOT_FOUND) { - + // // Create a stream context // - + status = AvCreateStreamContext( FltObjects->Filter, &streamContext ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[Av]: Failed to create stream context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, FltObjects->FileObject, FltObjects->Instance) ); - + return FLT_POSTOP_FINISHED_PROCESSING; } - + // // Attempt to get the stream infected state from our cache - // - + // + status = AvGetFileId( FltObjects->Instance, FltObjects->FileObject, &streamContext->FileId ); - + if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[Av]: Failed to get file id with status 0x%x. (FileObject = %p, Instance = %p)\n", status, FltObjects->FileObject, FltObjects->Instance) ); - + // // File id is optional and therefore should not affect the scan logic. // - + AV_SET_INVALID_FILE_REFERENCE( streamContext->FileId ) - + } else { // - // This function will load the file infected state from the + // This function will load the file infected state from the // cache if the fileID is valid. Even if this function fails, // we still have to move on because the cache is optional. // - AvLoadFileStateFromCache( FltObjects->Instance, + AvLoadFileStateFromCache( FltObjects->Instance, &streamContext->FileId, &streamContext->State, &streamContext->VolumeRevision, &streamContext->CacheRevision, - &streamContext->FileRevision ); + &streamContext->FileRevision ); } - + // // Set the new context we just allocated on the file object // - + status = FltSetStreamContext( FltObjects->Instance, FltObjects->FileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, @@ -2537,7 +2561,7 @@ Return Value: // Race condition. Someone has set a context after we queried it. // Use the already set context instead // - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[Av]: Race: Stream context already defined. Retaining old stream context %p (FileObject = %p, Instance = %p)\n", oldStreamContext, @@ -2558,50 +2582,50 @@ Return Value: goto Cleanup; } } - + } else if (!NT_SUCCESS(status)) { // // We will get here if stream contexts are not supported // - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[Av]: Failed to get stream context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, FltObjects->FileObject, FltObjects->Instance) ); - + return FLT_POSTOP_FINISHED_PROCESSING; } - + // // If successfully opened a file with the desired access matching - // the "exclusive write" from a TxF point of view, we can guarantee that - // if previous transaction context exists, it must have been comitted + // the "exclusive write" from a TxF point of view, we can guarantee that + // if previous transaction context exists, it must have been comitted // or rollbacked. // - + if (FlagOn( Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess, FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY ) ) { - + // // Either this file is opened in a transaction context or not, // we need to process the previous transaction if it exists. // AvProcessPreviousTransaction(...) handles these cases. // - + status = AvProcessPreviousTransaction ( FltObjects, streamContext ); if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvPostCreate: AvProcessTransaction FAILED!! \n") ); goto Cleanup; } - + isTxWriter = (FltObjects->Transaction != NULL); } @@ -2620,9 +2644,9 @@ Return Value: // - + if (IS_FILE_NEED_SCAN( streamContext )) { - + status = AvScan( Data, FltObjects, AvUserMode, @@ -2631,7 +2655,7 @@ Return Value: streamContext ); if (!NT_SUCCESS( status ) || (STATUS_TIMEOUT == status)) { - + AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] AvPostCreate: AvScan FAILED!! \n") ); @@ -2648,7 +2672,7 @@ Return Value: streamContext->VolumeRevision = VolumeRevision; streamContext->CacheRevision = CacheRevision; streamContext->FileRevision = FileRevision; - + AV_DBG_PRINT( AVDBG_TRACE_DEBUG, ("[Av]: AvPostCreate: RevisionNumbers updated to %I64x:%I64x:%I64x\n", VolumeRevision, @@ -2656,30 +2680,30 @@ Return Value: FileRevision) ); } - + if (IS_FILE_INFECTED( streamContext )) { - + // // If the file is infected, deny the access. // AvCancelFileOpen(Data, FltObjects, STATUS_VIRUS_INFECTED); // - // If the scan timed-out or scan was failed, we let the create succeed, + // If the scan timed-out or scan was failed, we let the create succeed, // and it may cause security hole; // // Alternatively, you can add a state called AvFileScanFailure or equivalent, - // add a condition here and fail the create. This option will have better - // protection from viruses, but the apps will see the failures due to a + // add a condition here and fail the create. This option will have better + // protection from viruses, but the apps will see the failures due to a // lengthy scan or scan failure. It's a trade-off. // goto Cleanup; } - + Cleanup: - + FltReleaseContext( streamContext ); - + return FLT_POSTOP_FINISHED_PROCESSING; } @@ -2694,7 +2718,7 @@ AvPreCleanup ( Routine Description: Pre-cleanup callback. Make the stream context persistent in the volatile cache. - If the file is transacted, it will be synced at KTM notification callback + If the file is transacted, it will be synced at KTM notification callback if committed. Arguments: @@ -2705,7 +2729,7 @@ Routine Description: opaque handles to this filter, instance, its associated volume and file object. - CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or + CompletionContext - If this callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK or FLT_PREOP_SYNCHRONIZE, this parameter is an optional context pointer to be passed to the corresponding post-operation callback routine. Otherwise, it must be NULL. @@ -2714,7 +2738,7 @@ Return Value: The return value is the status of the operation. --*/ -{ +{ NTSTATUS status; BOOLEAN encrypted = FALSE; PAV_STREAM_CONTEXT streamContext = NULL; @@ -2724,15 +2748,15 @@ Return Value: BOOLEAN updateRevisionNumbers; LONGLONG VolumeRevision, CacheRevision, FileRevision; - + UNREFERENCED_PARAMETER( CompletionContext ); - + PAGED_CODE(); // // Skip scan on prefetcher handles to avoid deadlocks // - + status = FltGetStreamHandleContext( FltObjects->Instance, FltObjects->FileObject, &streamHandleContext ); @@ -2743,8 +2767,8 @@ Return Value: // // Because the Memory Manager can cache the file object // and use it for other applications performing mapped I/O, - // whenever a Cleanup operation is seen on a prefetcher - // file object, that file object should no longer be + // whenever a Cleanup operation is seen on a prefetcher + // file object, that file object should no longer be // considered prefetcher-opened. // @@ -2756,7 +2780,7 @@ Return Value: NULL ); FltReleaseContext( streamHandleContext ); - + return FLT_PREOP_SUCCESS_NO_CALLBACK; } @@ -2769,7 +2793,7 @@ Return Value: IoGetStackLimits( &stackLow, &stackHigh ); - if (((ULONG_PTR)FltObjects->FileObject > stackLow) && + if (((ULONG_PTR)FltObjects->FileObject > stackLow) && ((ULONG_PTR)FltObjects->FileObject < stackHigh)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; @@ -2797,7 +2821,7 @@ Return Value: FltObjects->FileObject, &encrypted ); if (!NT_SUCCESS( status )) { - + AV_DBG_PRINT( AVDBG_TRACE_ERROR, ("[AV] AvPreCleanup: AvGetFileEncrypted FAILED!! \n") ); @@ -2805,7 +2829,7 @@ Return Value: } if (encrypted) { - + goto Cleanup; } @@ -2819,16 +2843,16 @@ Return Value: // // For applications, the typical calling sequence is, close the file handle - // and commit/rollback the changes. We skip the scan here for - // transacted writer because we do not know if the change will be - // rollbacked or not. If it eventually commits, it will be scanned - // at next create anyway. However, if it rollbacks, the scan here will + // and commit/rollback the changes. We skip the scan here for + // transacted writer because we do not know if the change will be + // rollbacked or not. If it eventually commits, it will be scanned + // at next create anyway. However, if it rollbacks, the scan here will // be redundant. // - if ((streamContext->TxContext == NULL) && + if ((streamContext->TxContext == NULL) && IS_FILE_MODIFIED( streamContext )) { - + status = AvScan( Data, FltObjects, AvUserMode, @@ -2837,7 +2861,7 @@ Return Value: streamContext ); if (!NT_SUCCESS( status ) || STATUS_TIMEOUT == status) { - + AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] AvPreCleanup: AvScan FAILED!! \n") ); @@ -2870,7 +2894,7 @@ Return Value: // We only insert the entry when the file is clean or infected. // - if (!IS_FILE_MODIFIED( streamContext ) || + if (!IS_FILE_MODIFIED( streamContext ) || IS_FILE_INFECTED( streamContext )) { if (!NT_SUCCESS ( AvSyncCache( FltObjects->Instance, streamContext ))) { @@ -2897,7 +2921,7 @@ Routine Description: The registered routine of type PFLT_TRANSACTION_NOTIFICATION_CALLBACK in FLT_REGISTRATION structure. - + Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing @@ -2906,17 +2930,17 @@ Routine Description: TransactionContext - Pointer to the minifilter driver's transaction context set at PostCreate. - - TransactionNotification - Specifies the type of notifications that the + + TransactionNotification - Specifies the type of notifications that the filter manager is sending to the minifilter driver. Return Value: - STATUS_SUCCESS - Returning this status value indicates that the minifilter + STATUS_SUCCESS - Returning this status value indicates that the minifilter driver is finished with the transaction. This is a success code. - - STATUS_PENDING - Returning this status value indicates that the minifilter - driver is not yet finished with the transaction. This is a success code. + + STATUS_PENDING - Returning this status value indicates that the minifilter + driver is not yet finished with the transaction. This is a success code. --*/ { @@ -2925,20 +2949,20 @@ Return Value: PAGED_CODE(); UNREFERENCED_PARAMETER( FltObjects ); - + FLT_ASSERTMSG("[AV] AvKtmNotificationCallback: The expected type of notifications registered at FltEnlistInTransaction(...).\n", FlagOn( TransactionNotification, (TRANSACTION_NOTIFY_COMMIT_FINALIZE | TRANSACTION_NOTIFY_ROLLBACK) ) ); AV_DBG_PRINT( AVDBG_TRACE_ROUTINES, ("[AV] AvKtmNotificationCallback: Entered\n") ); - + if (NULL != transactionContext) { if ( FlagOn( TransactionNotification, TRANSACTION_NOTIFY_COMMIT_FINALIZE ) ) { - + return AvProcessTransactionOutcome( TransactionContext, TransactionOutcomeCommitted ); - + } else { return AvProcessTransactionOutcome( TransactionContext, TransactionOutcomeAborted ); @@ -2959,8 +2983,8 @@ AvScanAbortCallbackAsync ( Routine Description: This routine is the registered cancel callback function in FLT_REGISTRATION. - It would be invoked by the file system if it decides to abort the scan. - As its name suggests, this function is asynchrounous, so the caller is not + It would be invoked by the file system if it decides to abort the scan. + As its name suggests, this function is asynchrounous, so the caller is not blocked. Note: This routine may be called before FltCreateSectionForDataScan returns. @@ -2971,9 +2995,9 @@ Routine Description: Arguments: Instance - Opaque filter pointer for the caller. This parameter is required and cannot be NULL. - + Context - The section context. - + Data - Pointer to the filter callbackData that is passed to us. Return Value: @@ -3003,34 +3027,173 @@ Return Value: sectionCtx->CancelableOnConflictingIo) ); // - // Send abort signal only when the scanning + // Send abort signal only when the scanning // happens in cancelable context (such as pre-cleanup). // if (sectionCtx->CancelableOnConflictingIo) { // - // The only reason of scan context being NULL is that + // The only reason of scan context being NULL is that // the section context is about to close anyway. // Please see AvCloseSectionForDataScan(...) // scanCtx = InterlockedExchangePointer( §ionCtx->ScanContext, NULL ); if (scanCtx == NULL) { - + return STATUS_SUCCESS; } - + sectionCtx->Aborted = TRUE; AvSendAbortToUser( scanCtx->ScanThreadId, scanCtx->ScanId ); - + } return STATUS_SUCCESS; } -NTSTATUS -AvSetConfiguration ( +PFN_IoOpenDriverRegistryKey +AvGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +AvOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS Status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible + // + + pIoOpenDriverRegistryKey = AvGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API + // + + Status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( Status )) { + + goto OpenServiceParametersKeyCleanup; + } + + } else { + + // + // Open specified service root key + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + Status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + goto OpenServiceParametersKeyCleanup; + } + + // + // Open the parameters key relative to service key path + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + Status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + goto OpenServiceParametersKeyCleanup; + } + } + + // + // Return value to caller + // + + *ServiceParametersKey = ParametersKey; + +OpenServiceParametersKeyCleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return Status; + +} + +NTSTATUS +AvSetConfiguration ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -3041,6 +3204,9 @@ Routine Descrition: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -3051,8 +3217,7 @@ Return Value: --*/ { NTSTATUS status; - OBJECT_ATTRIBUTES attributes; - HANDLE driverRegKey = NULL; + HANDLE settingsKey = NULL; UNICODE_STRING valueName; UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; @@ -3060,25 +3225,18 @@ Return Value: ULONG resultLength; // - // Open the SimRep registry key. + // Open service parameters key to query values from // - InitializeObjectAttributes( &attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); - - status = ZwOpenKey( &driverRegKey, - KEY_READ, - &attributes ); + status = AvOpenServiceParametersKey( DriverObject, + RegistryPath, + &settingsKey ); if (!NT_SUCCESS( status )) { goto Cleanup; } - #if DBG // @@ -3086,8 +3244,8 @@ Return Value: // RtlInitUnicodeString( &valueName, L"DebugLevel" ); - - status = ZwQueryValueKey( driverRegKey, + + status = ZwQueryValueKey( settingsKey, &valueName, KeyValuePartialInformation, value, @@ -3107,16 +3265,16 @@ Return Value: RtlInitUnicodeString( &valueName, L"LocalScanTimeout" ); - status = ZwQueryValueKey( driverRegKey, + status = ZwQueryValueKey( settingsKey, &valueName, KeyValuePartialInformation, value, - valueLength, + valueLength, &resultLength ); if (NT_SUCCESS( status )) { - Globals.LocalScanTimeout = (LONGLONG)(*(PULONG)value->Data); + Globals.LocalScanTimeout = (LONGLONG)(*(PULONG)value->Data); } // @@ -3125,25 +3283,25 @@ Return Value: RtlInitUnicodeString( &valueName, L"NetworkScanTimeout" ); - status = ZwQueryValueKey( driverRegKey, + status = ZwQueryValueKey( settingsKey, &valueName, KeyValuePartialInformation, value, - valueLength, + valueLength, &resultLength ); if (NT_SUCCESS( status )) { - Globals.NetworkScanTimeout = (LONGLONG)(*(PULONG)value->Data); + Globals.NetworkScanTimeout = (LONGLONG)(*(PULONG)value->Data); } status = STATUS_SUCCESS; Cleanup: - if (driverRegKey != NULL) { + if (settingsKey != NULL) { - ZwClose( driverRegKey ); + ZwClose( settingsKey ); } return status; diff --git a/filesys/miniFilter/avscan/filter/avscan.vcxproj b/filesys/miniFilter/avscan/filter/avscan.vcxproj index 5552329cb..fa6122b52 100644 --- a/filesys/miniFilter/avscan/filter/avscan.vcxproj +++ b/filesys/miniFilter/avscan/filter/avscan.vcxproj @@ -188,6 +188,10 @@ + + true + Document + diff --git a/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters b/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters index 6254a2458..399cecc72 100644 --- a/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters +++ b/filesys/miniFilter/avscan/filter/avscan.vcxproj.Filters @@ -43,4 +43,38 @@ Resource Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Driver Files + + \ No newline at end of file diff --git a/filesys/miniFilter/cancelSafe/cancelSafe.c b/filesys/miniFilter/cancelSafe/cancelSafe.c index 4c9e76337..9942a3d31 100644 --- a/filesys/miniFilter/cancelSafe/cancelSafe.c +++ b/filesys/miniFilter/cancelSafe/cancelSafe.c @@ -185,8 +185,31 @@ InstanceTeardownComplete ( _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags ); +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +GetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +OpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + NTSTATUS SetConfiguration ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -269,6 +292,8 @@ PreReadEmptyQueueAndComplete( #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(INIT, GetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, OpenServiceParametersKey) #pragma alloc_text(INIT, SetConfiguration) #pragma alloc_text(PAGE, Unload) #pragma alloc_text(PAGE, FreeGlobals) @@ -394,7 +419,7 @@ Return Value: // Modify the configuration based on values in the registry // - Status = SetConfiguration( RegistryPath ); + Status = SetConfiguration( DriverObject, RegistryPath ); if (!NT_SUCCESS( Status )) { @@ -456,9 +481,147 @@ Return Value: return Status; } +PFN_IoOpenDriverRegistryKey +GetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +OpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS Status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible. + // + + pIoOpenDriverRegistryKey = GetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API. + // + + Status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( Status )) { + + goto OpenServiceParametersKeyCleanup; + } + + } else { + + // + // Open specified service root key. + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + Status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + goto OpenServiceParametersKeyCleanup; + } + + // + // Open the parameters key relative to service key path. + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + Status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + goto OpenServiceParametersKeyCleanup; + } + } + + // + // Return value to caller. + // + + *ServiceParametersKey = ParametersKey; + +OpenServiceParametersKeyCleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return Status; + +} NTSTATUS SetConfiguration ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -470,6 +633,9 @@ Routine Description: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -480,10 +646,8 @@ Return Value: --*/ { NTSTATUS Status; - OBJECT_ATTRIBUTES Attributes; HANDLE DriverRegKey = NULL; UNICODE_STRING ValueName; - BOOLEAN CloseHandle = FALSE; UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + CSQ_MAX_PATH_LENGTH * sizeof(WCHAR)]; PKEY_VALUE_PARTIAL_INFORMATION Value = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer; ULONG ValueLength = sizeof(Buffer); @@ -491,28 +655,21 @@ Return Value: ULONG Length; // - // Open the driver registry key. + // Open service parameters key to query values from. // - InitializeObjectAttributes( &Attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); - - Status = ZwOpenKey( &DriverRegKey, - KEY_READ, - &Attributes ); + Status = OpenServiceParametersKey( DriverObject, + RegistryPath, + &DriverRegKey ); if (!NT_SUCCESS( Status )) { + DriverRegKey = NULL; goto SetConfigurationCleanup; } - CloseHandle = TRUE; - // - // Query the debug level + // Query the debug level. // RtlInitUnicodeString( &ValueName, CSQ_KEY_NAME_DEBUG_LEVEL ); @@ -529,12 +686,10 @@ Return Value: Globals.DebugLevel = *(PULONG)(Value->Data); } - // - // Query the queue time delay + // Query the queue time delay. // - RtlInitUnicodeString( &ValueName, CSQ_KEY_NAME_DELAY ); Status = ZwQueryValueKey( DriverRegKey, @@ -557,7 +712,7 @@ Return Value: } // - // Query the mapping path + // Query the mapping path. // RtlInitUnicodeString( &ValueName, CSQ_KEY_NAME_PATH ); @@ -632,7 +787,7 @@ Return Value: SetConfigurationCleanup: - if (CloseHandle) { + if (DriverRegKey != NULL) { ZwClose( DriverRegKey ); } diff --git a/filesys/miniFilter/cancelSafe/cancelSafe.inf b/filesys/miniFilter/cancelSafe/cancelSafe.inf index d526b3dc4..69d0ccf10 100644 Binary files a/filesys/miniFilter/cancelSafe/cancelSafe.inf and b/filesys/miniFilter/cancelSafe/cancelSafe.inf differ diff --git a/filesys/miniFilter/cdo/CdoInit.c b/filesys/miniFilter/cdo/CdoInit.c index fa6e37aa8..f913f6fbb 100644 --- a/filesys/miniFilter/cdo/CdoInit.c +++ b/filesys/miniFilter/cdo/CdoInit.c @@ -48,8 +48,31 @@ CdoInstanceSetup ( #if DBG +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +CdoGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +CdoOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + VOID CdoInitializeDebugLevel ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -75,6 +98,8 @@ CDO_GLOBAL_DATA Globals; #pragma alloc_text(INIT, DriverEntry) #if DBG +#pragma alloc_text(INIT, CdoGetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, CdoOpenServiceParametersKey) #pragma alloc_text(INIT, CdoInitializeDebugLevel) #endif @@ -90,12 +115,12 @@ DriverEntry( ) { NTSTATUS status; - - + + // // This defines what we want to filter with FltMgr // - + CONST FLT_REGISTRATION filterRegistration = { sizeof( FLT_REGISTRATION ), // Size FLT_REGISTRATION_VERSION, // Version @@ -109,22 +134,22 @@ DriverEntry( NULL, // InstanceTeardownComplete NULL,NULL // NameProvider callbacks }; - + RtlZeroMemory( &Globals, sizeof( Globals ) ); #if DBG - + // // Initialize global debug level // - CdoInitializeDebugLevel( RegistryPath ); + CdoInitializeDebugLevel( DriverObject, RegistryPath ); #else UNREFERENCED_PARAMETER( RegistryPath ); - + #endif DebugTrace( DEBUG_TRACE_LOAD_UNLOAD, @@ -132,14 +157,14 @@ DriverEntry( // // Initialize the resource - // + // ExInitializeResourceLite( &Globals.Resource ); // // Record the driver object // - + Globals.FilterDriverObject = DriverObject; // @@ -167,7 +192,7 @@ DriverEntry( FltUnregisterFilter( Globals.Filter ); ExDeleteResourceLite( &Globals.Resource ); return status; - } + } // // Start filtering i/o @@ -188,30 +213,171 @@ DriverEntry( #if DBG +PFN_IoOpenDriverRegistryKey +CdoGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +CdoOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS Status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible. + // + + pIoOpenDriverRegistryKey = CdoGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API. + // + + Status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( Status )) { + + goto cleanup; + } + + } else { + + // + // Open specified service root key. + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + Status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + goto cleanup; + } + + // + // Open the parameters key relative to service key path. + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + Status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( Status )) { + + goto cleanup; + } + } + + // + // Return value to caller. + // + + *ServiceParametersKey = ParametersKey; + +cleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return Status; + +} + VOID CdoInitializeDebugLevel ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ Routine Description: - This routine tries to read the filter DebugLevel parameter from + 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: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. - + Return Value: None. --*/ { - OBJECT_ATTRIBUTES attributes; - HANDLE driverRegKey; + HANDLE driverRegKey = NULL; NTSTATUS status; ULONG resultLength; UNICODE_STRING valueName; @@ -220,45 +386,46 @@ Return Value: Globals.DebugLevel = DEBUG_TRACE_ERROR; // - // Open the desired registry key + // Open service parameters key to query values from. // - InitializeObjectAttributes( &attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); + status = CdoOpenServiceParametersKey( DriverObject, + RegistryPath, + &driverRegKey ); - status = ZwOpenKey( &driverRegKey, - KEY_READ, - &attributes ); + if (!NT_SUCCESS( status )) { - if (NT_SUCCESS( status )) { + driverRegKey = NULL; + goto cleanup; + } - // - // Read the DebugFlags value from the registry. - // + // + // Read the DebugFlags value from the registry. + // - RtlInitUnicodeString( &valueName, L"DebugLevel" ); - - status = ZwQueryValueKey( driverRegKey, - &valueName, - KeyValuePartialInformation, - buffer, - sizeof(buffer), - &resultLength ); + RtlInitUnicodeString( &valueName, L"DebugLevel" ); - if (NT_SUCCESS( status )) { + status = ZwQueryValueKey( driverRegKey, + &valueName, + KeyValuePartialInformation, + buffer, + sizeof(buffer), + &resultLength ); - Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); - } + if (NT_SUCCESS( status )) { + + Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); } +cleanup: + // // Close the registry entry // - ZwClose( driverRegKey ); + if (driverRegKey != NULL) { + ZwClose( driverRegKey ); + } } #endif @@ -274,7 +441,7 @@ 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 + request if this is not a mandatory unloaded indicated by the Flags parameter. Arguments: @@ -299,7 +466,7 @@ Return Value: // If the CDO is still referenced and the unload is not mandatry // then fail the unload // - + CdoAcquireResourceShared( &Globals.Resource ); if (FlagOn( Globals.Flags, GLOBAL_DATA_F_CDO_OPEN_REF) && @@ -356,7 +523,7 @@ Routine Description: Return Value: - STATUS_FLT_DO_NOT_ATTACH - do not attach because we do not want to + STATUS_FLT_DO_NOT_ATTACH - do not attach because we do not want to attach to any volume --*/ diff --git a/filesys/miniFilter/cdo/cdo.inf b/filesys/miniFilter/cdo/cdo.inf index c51cae2c9..cdac24d9a 100644 Binary files a/filesys/miniFilter/cdo/cdo.inf and b/filesys/miniFilter/cdo/cdo.inf differ diff --git a/filesys/miniFilter/change/change.inf b/filesys/miniFilter/change/change.inf index 86a7b868d..e7da42501 100644 Binary files a/filesys/miniFilter/change/change.inf and b/filesys/miniFilter/change/change.inf differ diff --git a/filesys/miniFilter/ctx/CtxInit.c b/filesys/miniFilter/ctx/CtxInit.c index 2654b9f99..e1e2576ac 100644 --- a/filesys/miniFilter/ctx/CtxInit.c +++ b/filesys/miniFilter/ctx/CtxInit.c @@ -78,8 +78,31 @@ CtxInstanceTeardownComplete ( #if DBG +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +CtxGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +CtxOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + VOID CtxInitializeDebugLevel ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -93,6 +116,8 @@ CtxInitializeDebugLevel ( #pragma alloc_text(INIT, DriverEntry) #if DBG +#pragma alloc_text(INIT, CtxGetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, CtxOpenServiceParametersKey) #pragma alloc_text(INIT, CtxInitializeDebugLevel) #endif @@ -217,7 +242,7 @@ Return Value: // // Default to NonPagedPoolNx for non paged pool allocations where supported. // - + ExInitializeDriverRuntime( DrvRtPoolNxOptIn ); RtlZeroMemory( &Globals, sizeof( Globals ) ); @@ -228,7 +253,7 @@ Return Value: // Initialize global debug level // - CtxInitializeDebugLevel( RegistryPath ); + CtxInitializeDebugLevel( DriverObject, RegistryPath ); #else @@ -274,8 +299,147 @@ Return Value: #if DBG +PFN_IoOpenDriverRegistryKey +CtxGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +CtxOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible + // + + pIoOpenDriverRegistryKey = CtxGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API + // + + status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + + } else { + + // + // Open specified service root key + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + + // + // Open the parameters key relative to service key path + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto cleanup; + } + } + + // + // Return value to caller + // + + *ServiceParametersKey = ParametersKey; + +cleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return status; + +} + VOID CtxInitializeDebugLevel ( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -288,6 +452,9 @@ Routine Description: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -296,8 +463,7 @@ Return Value: --*/ { - OBJECT_ATTRIBUTES attributes; - HANDLE driverRegKey; + HANDLE driverRegKey = NULL; NTSTATUS status; ULONG resultLength; UNICODE_STRING valueName; @@ -306,47 +472,46 @@ Return Value: Globals.DebugLevel = DEBUG_TRACE_ERROR; // - // Open the desired registry key + // Open service parameters key to query values from. // - InitializeObjectAttributes( &attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); + status = CtxOpenServiceParametersKey( DriverObject, + RegistryPath, + &driverRegKey ); - status = ZwOpenKey( &driverRegKey, - KEY_READ, - &attributes ); + if (!NT_SUCCESS( status )) { - if (NT_SUCCESS( status )) { + driverRegKey = NULL; + goto cleanup; + } - // - // Read the DebugFlags value from the registry. - // + // + // Read the DebugFlags value from the registry. + // - RtlInitUnicodeString( &valueName, L"DebugLevel" ); + RtlInitUnicodeString( &valueName, L"DebugLevel" ); - status = ZwQueryValueKey( driverRegKey, - &valueName, - KeyValuePartialInformation, - buffer, - sizeof(buffer), - &resultLength ); + status = ZwQueryValueKey( driverRegKey, + &valueName, + KeyValuePartialInformation, + buffer, + sizeof(buffer), + &resultLength ); - if (NT_SUCCESS( status )) { + if (NT_SUCCESS( status )) { - Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); - } + Globals.DebugLevel = *((PULONG) &(((PKEY_VALUE_PARTIAL_INFORMATION) buffer)->Data)); + } - // - // Close the registry entry - // +cleanup: - ZwClose( driverRegKey ); + // + // Close the registry entry + // + if (driverRegKey != NULL) { + ZwClose( driverRegKey ); } - } #endif diff --git a/filesys/miniFilter/ctx/ctx.inf b/filesys/miniFilter/ctx/ctx.inf index 39e935afb..8edaf764d 100644 Binary files a/filesys/miniFilter/ctx/ctx.inf and b/filesys/miniFilter/ctx/ctx.inf differ diff --git a/filesys/miniFilter/delete/delete.inf b/filesys/miniFilter/delete/delete.inf index b9a572fe2..da348874e 100644 Binary files a/filesys/miniFilter/delete/delete.inf and b/filesys/miniFilter/delete/delete.inf differ diff --git a/filesys/miniFilter/minispy/filter/minispy.vcxproj b/filesys/miniFilter/minispy/filter/minispy.vcxproj index 04cec7fef..ce4cb7375 100644 --- a/filesys/miniFilter/minispy/filter/minispy.vcxproj +++ b/filesys/miniFilter/minispy/filter/minispy.vcxproj @@ -196,6 +196,7 @@ + diff --git a/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters b/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters index e01847506..aaaa7c147 100644 --- a/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters +++ b/filesys/miniFilter/minispy/filter/minispy.vcxproj.Filters @@ -34,4 +34,14 @@ Resource Files + + + Header Files + + + + + Driver Files + + \ No newline at end of file diff --git a/filesys/miniFilter/minispy/minispy.inf b/filesys/miniFilter/minispy/minispy.inf index c210097cd..60eb86840 100644 Binary files a/filesys/miniFilter/minispy/minispy.inf and b/filesys/miniFilter/minispy/minispy.inf differ diff --git a/filesys/miniFilter/nullFilter/nullFilter.inf b/filesys/miniFilter/nullFilter/nullFilter.inf index 0e710e2d8..c04e9f062 100644 Binary files a/filesys/miniFilter/nullFilter/nullFilter.inf and b/filesys/miniFilter/nullFilter/nullFilter.inf differ diff --git a/filesys/miniFilter/passThrough/passThrough.inf b/filesys/miniFilter/passThrough/passThrough.inf index 6db4d0d07..129a2ab64 100644 Binary files a/filesys/miniFilter/passThrough/passThrough.inf and b/filesys/miniFilter/passThrough/passThrough.inf differ diff --git a/filesys/miniFilter/scanner/filter/scanner.c b/filesys/miniFilter/scanner/filter/scanner.c index 318941d1c..ec911f638 100644 --- a/filesys/miniFilter/scanner/filter/scanner.c +++ b/filesys/miniFilter/scanner/filter/scanner.c @@ -54,8 +54,31 @@ UNICODE_STRING ScannedExtensionDefault = RTL_CONSTANT_STRING( L"doc" ); // Function prototypes // +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +ScannerGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +ScannerOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + NTSTATUS ScannerInitializeScannedExtensions( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -105,6 +128,8 @@ ScannerpCheckExtension ( #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) + #pragma alloc_text(INIT, ScannerGetIoOpenDriverRegistryKey) + #pragma alloc_text(INIT, ScannerOpenServiceParametersKey) #pragma alloc_text(INIT, ScannerInitializeScannedExtensions) #pragma alloc_text(PAGE, ScannerInstanceSetup) #pragma alloc_text(PAGE, ScannerPreCreate) @@ -242,7 +267,7 @@ Return Value: // Obtain the extensions to scan from the registry // - status = ScannerInitializeScannedExtensions( RegistryPath ); + status = ScannerInitializeScannedExtensions( DriverObject, RegistryPath ); if (!NT_SUCCESS( status )) { @@ -312,8 +337,147 @@ Return Value: } +PFN_IoOpenDriverRegistryKey +ScannerGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +ScannerOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible + // + + pIoOpenDriverRegistryKey = ScannerGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API + // + + status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( status )) { + + goto ScannerOpenServiceParametersKeyCleanup; + } + + } else { + + // + // Open specified service root key + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto ScannerOpenServiceParametersKeyCleanup; + } + + // + // Open the parameters key relative to service key path + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto ScannerOpenServiceParametersKeyCleanup; + } + } + + // + // Return value to caller + // + + *ServiceParametersKey = ParametersKey; + +ScannerOpenServiceParametersKeyCleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return status; + +} + NTSTATUS ScannerInitializeScannedExtensions( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -325,6 +489,9 @@ Routine Descrition: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -335,12 +502,10 @@ Return Value: --*/ { NTSTATUS status; - OBJECT_ATTRIBUTES attributes; HANDLE driverRegKey = NULL; UNICODE_STRING valueName; PKEY_VALUE_PARTIAL_INFORMATION valueBuffer = NULL; ULONG valueLength = 0; - BOOLEAN closeHandle = FALSE; PWCHAR ch; SIZE_T length; ULONG count; @@ -352,26 +517,19 @@ Return Value: ScannedExtensionCount = 0; // - // Open the driver registry key. + // Open service parameters key to query values from. // - InitializeObjectAttributes( &attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); - - status = ZwOpenKey( &driverRegKey, - KEY_READ, - &attributes ); + status = ScannerOpenServiceParametersKey( DriverObject, + RegistryPath, + &driverRegKey ); if (!NT_SUCCESS( status )) { + driverRegKey = NULL; goto ScannerInitializeScannedExtensionsCleanup; } - closeHandle = TRUE; - // // Query the length of the reg value // @@ -480,7 +638,7 @@ Return Value: valueBuffer = NULL; } - if (closeHandle) { + if (driverRegKey != NULL) { ZwClose( driverRegKey ); } @@ -675,7 +833,7 @@ Return Value return STATUS_SUCCESS; } - + VOID ScannerPortDisconnect( _In_opt_ PVOID ConnectionCookie @@ -717,7 +875,7 @@ Return value ScannerData.UserProcess = NULL; } - + NTSTATUS ScannerUnload ( _In_ FLT_FILTER_UNLOAD_FLAGS Flags diff --git a/filesys/miniFilter/scanner/filter/scanner.vcxproj b/filesys/miniFilter/scanner/filter/scanner.vcxproj index a3eeebcb3..046447587 100644 --- a/filesys/miniFilter/scanner/filter/scanner.vcxproj +++ b/filesys/miniFilter/scanner/filter/scanner.vcxproj @@ -190,6 +190,7 @@ + diff --git a/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters b/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters index 043528f2f..fbf265f0b 100644 --- a/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters +++ b/filesys/miniFilter/scanner/filter/scanner.vcxproj.Filters @@ -28,4 +28,14 @@ Resource Files + + + Header Files + + + + + Driver Files + + \ No newline at end of file diff --git a/filesys/miniFilter/scanner/scanner.inf b/filesys/miniFilter/scanner/scanner.inf index 762f5eec7..d7bf6256e 100644 Binary files a/filesys/miniFilter/scanner/scanner.inf and b/filesys/miniFilter/scanner/scanner.inf differ diff --git a/filesys/miniFilter/simrep/simrep.c b/filesys/miniFilter/simrep/simrep.c index 4d377ecbe..f23dddd66 100644 --- a/filesys/miniFilter/simrep/simrep.c +++ b/filesys/miniFilter/simrep/simrep.c @@ -243,8 +243,31 @@ DriverEntry ( _In_ PUNICODE_STRING RegistryPath ); +typedef +NTSTATUS +(*PFN_IoOpenDriverRegistryKey) ( + PDRIVER_OBJECT DriverObject, + DRIVER_REGKEY_TYPE RegKeyType, + ACCESS_MASK DesiredAccess, + ULONG Flags, + PHANDLE DriverRegKey + ); + +PFN_IoOpenDriverRegistryKey +SimRepGetIoOpenDriverRegistryKey ( + VOID + ); + +NTSTATUS +SimRepOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ); + NTSTATUS SimRepSetConfiguration( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ); @@ -506,6 +529,8 @@ SIMREP_GLOBAL_DATA Globals; #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(INIT, SimRepGetIoOpenDriverRegistryKey) +#pragma alloc_text(INIT, SimRepOpenServiceParametersKey) #pragma alloc_text(INIT, SimRepSetConfiguration) #pragma alloc_text(PAGE, SimRepUnload) #pragma alloc_text(PAGE, SimRepInstanceSetup) @@ -609,7 +634,7 @@ Return Value: // Set the filter configuration based on registry keys // - status = SimRepSetConfiguration( RegistryPath ); + status = SimRepSetConfiguration( DriverObject, RegistryPath ); DebugTrace( DEBUG_TRACE_LOAD_UNLOAD, ("[SimRep]: Driver being loaded\n") ); @@ -664,8 +689,147 @@ Return Value: } #pragma warning(pop) +PFN_IoOpenDriverRegistryKey +SimRepGetIoOpenDriverRegistryKey ( + VOID + ) +{ + static PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey = NULL; + UNICODE_STRING FunctionName = {0}; + + if (pIoOpenDriverRegistryKey == NULL) { + + RtlInitUnicodeString(&FunctionName, L"IoOpenDriverRegistryKey"); + + pIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&FunctionName); + } + + return pIoOpenDriverRegistryKey; +} + +NTSTATUS +SimRepOpenServiceParametersKey ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING ServiceRegistryPath, + _Out_ PHANDLE ServiceParametersKey + ) +/*++ + +Routine Description: + + This routine opens the service parameters key, using the isolation-compliant + APIs when possible. + +Arguments: + + DriverObject - Pointer to driver object created by the system to + represent this driver. + + RegistryPath - The path key passed to the driver during DriverEntry. + + ServiceParametersKey - Returns a handle to the service parameters subkey. + +Return Value: + + STATUS_SUCCESS if the function completes successfully. Otherwise a valid + NTSTATUS code is returned. + +--*/ +{ + NTSTATUS status; + PFN_IoOpenDriverRegistryKey pIoOpenDriverRegistryKey; + UNICODE_STRING Subkey; + HANDLE ParametersKey = NULL; + HANDLE ServiceRegKey = NULL; + OBJECT_ATTRIBUTES Attributes; + + // + // Open the parameters key to read values from the INF, using the API to + // open the key if possible + // + + pIoOpenDriverRegistryKey = SimRepGetIoOpenDriverRegistryKey(); + + if (pIoOpenDriverRegistryKey != NULL) { + + // + // Open the parameters key using the API + // + + status = pIoOpenDriverRegistryKey( DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &ParametersKey ); + + if (!NT_SUCCESS( status )) { + + goto SimRepOpenServiceParametersKeyCleanup; + } + + } else { + + // + // Open specified service root key + // + + InitializeObjectAttributes( &Attributes, + ServiceRegistryPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL ); + + status = ZwOpenKey( &ServiceRegKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto SimRepOpenServiceParametersKeyCleanup; + } + + // + // Open the parameters key relative to service key path + // + + RtlInitUnicodeString( &Subkey, L"Parameters" ); + + InitializeObjectAttributes( &Attributes, + &Subkey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ServiceRegKey, + NULL ); + + status = ZwOpenKey( &ParametersKey, + KEY_READ, + &Attributes ); + + if (!NT_SUCCESS( status )) { + + goto SimRepOpenServiceParametersKeyCleanup; + } + } + + // + // Return value to caller + // + + *ServiceParametersKey = ParametersKey; + +SimRepOpenServiceParametersKeyCleanup: + + if (ServiceRegKey != NULL) { + + ZwClose( ServiceRegKey ); + } + + return status; + +} + NTSTATUS SimRepSetConfiguration( + _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) /*++ @@ -676,6 +840,9 @@ Routine Descrition: Arguments: + DriverObject - Pointer to driver object created by the system to + represent this driver. + RegistryPath - The path key passed to the driver during DriverEntry. Return Value: @@ -686,7 +853,6 @@ Return Value: --*/ { NTSTATUS status; - OBJECT_ATTRIBUTES attributes; HANDLE driverRegKey = NULL; UNICODE_STRING valueName; UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; @@ -701,25 +867,19 @@ Return Value: PAGED_CODE(); // - // Open the SimRep registry key. + // Open service parameters key to query values from // - InitializeObjectAttributes( &attributes, - RegistryPath, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL ); - - status = ZwOpenKey( &driverRegKey, - KEY_READ, - &attributes ); + status = SimRepOpenServiceParametersKey( DriverObject, + RegistryPath, + &driverRegKey ); if (!NT_SUCCESS( status )) { + driverRegKey = NULL; goto SimRepSetConfigurationCleanup; } - #if DBG // diff --git a/filesys/miniFilter/simrep/simrep.inf b/filesys/miniFilter/simrep/simrep.inf index 93632e330..8eea42ce5 100644 Binary files a/filesys/miniFilter/simrep/simrep.inf and b/filesys/miniFilter/simrep/simrep.inf differ diff --git a/filesys/miniFilter/swapBuffers/swapBuffers.inf b/filesys/miniFilter/swapBuffers/swapBuffers.inf index ad88200e1..0aab9452e 100644 Binary files a/filesys/miniFilter/swapBuffers/swapBuffers.inf and b/filesys/miniFilter/swapBuffers/swapBuffers.inf differ