From ef5b664dcc6245a0511d9572e6f3e6d22eabf7eb Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 8 Apr 2016 15:25:09 -0700 Subject: [PATCH] dll: FspFileSystemInitialize, FspFileSystemFinalize --- inc/winfsp/winfsp.h | 1 + src/dll/dispatch.c | 96 ++++++++++++++++++++++++++++++++++++++------- src/dll/library.c | 4 ++ src/dll/library.h | 27 +++++++++++++ 4 files changed, 114 insertions(+), 14 deletions(-) diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index 092d0a72..caa9e042 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -125,6 +125,7 @@ typedef struct _FSP_FILE_SYSTEM ULONG DispatcherThreadCount; NTSTATUS DispatcherResult; PWSTR MountPoint; + LIST_ENTRY MountEntry; } FSP_FILE_SYSTEM; FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams, diff --git a/src/dll/dispatch.c b/src/dll/dispatch.c index 58a899d0..2499ea47 100644 --- a/src/dll/dispatch.c +++ b/src/dll/dispatch.c @@ -13,6 +13,62 @@ enum static FSP_FILE_SYSTEM_INTERFACE FspFileSystemNullInterface; +static CRITICAL_SECTION FspFileSystemMountListGuard; +static LIST_ENTRY FspFileSystemMountList = { &FspFileSystemMountList, &FspFileSystemMountList }; + +VOID FspFileSystemInitialize(VOID) +{ + /* + * This function is called during DLL_PROCESS_ATTACH. We must therefore keep initialization + * tasks to a minimum. + * + * Initialization of synchronization objects is allowed! See: + * https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx + */ + + InitializeCriticalSection(&FspFileSystemMountListGuard); +} + +VOID FspFileSystemFinalize(VOID) +{ + /* + * This function is called during DLL_PROCESS_DETACH. We must therefore keep finalization + * tasks to a minimum. + * + * Very few things can be safely done during DLL_PROCESS_DETACH. See: + * https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx + * https://blogs.msdn.microsoft.com/oldnewthing/20070503-00/?p=27003/ + * https://blogs.msdn.microsoft.com/oldnewthing/20100122-00/?p=15193/ + * + * We enter our FspFileSystemMountListGuard critical section here and then attempt to cleanup + * our mount points using DefineDosDeviceW. On Vista and later orphaned critical sections + * become "electrified", so our process will be forcefully terminated if one of its threads + * was already modifying the list when the ExitProcess happened. This is a good thing! + * + * The use of DefineDosDeviceW is rather suspect and probably unsafe. DefineDosDeviceW reaches + * out to CSRSS, which is probably not the safest thing to do when in DllMain! There is also + * some evidence that it may attempt to load DLL's under some circumstances, which is a + * definite no-no as we are under the loader lock! + */ + + FSP_FILE_SYSTEM *FileSystem; + PLIST_ENTRY MountEntry; + + EnterCriticalSection(&FspFileSystemMountListGuard); + + for (MountEntry = FspFileSystemMountList.Flink; + &FspFileSystemMountList != MountEntry; + MountEntry = MountEntry->Flink) + { + FileSystem = CONTAINING_RECORD(MountEntry, FSP_FILE_SYSTEM, MountEntry); + + DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, + FileSystem->MountPoint, FileSystem->VolumeName); + } + + LeaveCriticalSection(&FspFileSystemMountListGuard); +} + FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams, const FSP_FILE_SYSTEM_INTERFACE *Interface, @@ -74,6 +130,8 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M if (0 != FileSystem->MountPoint) return STATUS_INVALID_PARAMETER; + NTSTATUS Result; + if (0 == MountPoint) { DWORD Drives; @@ -94,17 +152,14 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M MountPoint[0] = Drive; if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName)) { - FileSystem->MountPoint = MountPoint; - return STATUS_SUCCESS; + Result = STATUS_SUCCESS; + goto exit; } } - - SetLastError(ERROR_FILE_NOT_FOUND); + Result = STATUS_NO_SUCH_DEVICE; } - - MemFree(MountPoint); - - return FspNtStatusFromWin32(GetLastError()); + else + Result = FspNtStatusFromWin32(GetLastError()); } else { @@ -122,15 +177,24 @@ FSP_API NTSTATUS FspFileSystemSetMountPoint(FSP_FILE_SYSTEM *FileSystem, PWSTR M MountPoint = P; if (DefineDosDeviceW(DDD_RAW_TARGET_PATH, MountPoint, FileSystem->VolumeName)) - { - FileSystem->MountPoint = MountPoint; - return STATUS_SUCCESS; - } + Result = STATUS_SUCCESS; + else + Result = FspNtStatusFromWin32(GetLastError()); + } +exit: + if (NT_SUCCESS(Result)) + { + FileSystem->MountPoint = MountPoint; + + EnterCriticalSection(&FspFileSystemMountListGuard); + InsertTailList(&FspFileSystemMountList, &FileSystem->MountEntry); + LeaveCriticalSection(&FspFileSystemMountListGuard); + } + else MemFree(MountPoint); - return FspNtStatusFromWin32(GetLastError()); - } + return Result; } FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem) @@ -138,6 +202,10 @@ FSP_API VOID FspFileSystemRemoveMountPoint(FSP_FILE_SYSTEM *FileSystem) if (0 == FileSystem->MountPoint) return; + EnterCriticalSection(&FspFileSystemMountListGuard); + RemoveEntryList(&FileSystem->MountEntry); + LeaveCriticalSection(&FspFileSystemMountListGuard); + DefineDosDeviceW(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, FileSystem->MountPoint, FileSystem->VolumeName); diff --git a/src/dll/library.c b/src/dll/library.c index b57a88c1..15675e80 100644 --- a/src/dll/library.c +++ b/src/dll/library.c @@ -16,6 +16,10 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved) ProcessHeap = GetProcessHeap(); if (0 == ProcessHeap) return FALSE; + FspFileSystemInitialize(); + break; + case DLL_PROCESS_DETACH: + FspFileSystemFinalize(); break; } diff --git a/src/dll/library.h b/src/dll/library.h index d5424e2b..b6f32318 100644 --- a/src/dll/library.h +++ b/src/dll/library.h @@ -68,4 +68,31 @@ void *memset(void *dst, int val, size_t siz) } #endif +static FORCEINLINE +VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry) +{ + PLIST_ENTRY Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} +static FORCEINLINE +BOOLEAN RemoveEntryList(PLIST_ENTRY Entry) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return Flink == Blink; +} + +VOID FspFileSystemInitialize(VOID); +VOID FspFileSystemFinalize(VOID); + #endif