diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index b9c9b249..8843ec77 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -185,6 +185,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index f8e5bfe7..7ee41c66 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -122,6 +122,9 @@ Source\shared\ku + + Source + diff --git a/src/dll/fsctl.c b/src/dll/fsctl.c index 4a64899d..c5023815 100644 --- a/src/dll/fsctl.c +++ b/src/dll/fsctl.c @@ -242,6 +242,22 @@ static NTSTATUS FspFsctlStartService(VOID) DWORD LastError; NTSTATUS Result; + /* Determine if we are running inside container. + * + * See https://github.com/microsoft/perfview/blob/V1.9.65/src/TraceEvent/TraceEventSession.cs#L525 + * See https://stackoverflow.com/a/50748300 + */ + LastError = RegGetValueW( + HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control", + L"ContainerType", + RRF_RT_REG_DWORD, 0, + 0, 0); + if (ERROR_SUCCESS == LastError) + { + Result = STATUS_SUCCESS; + goto exit; + } + ScmHandle = OpenSCManagerW(0, 0, 0); if (0 == ScmHandle) { diff --git a/src/sys/driver.c b/src/sys/driver.c index f430deb8..a03c385a 100644 --- a/src/sys/driver.c +++ b/src/sys/driver.c @@ -21,26 +21,16 @@ #include -/* - * Define the following macro to include FspUnload. - * - * Note that this driver is no longer unloadable. - * See the comments in DriverEntry as to why! - */ -//#define FSP_UNLOAD - DRIVER_INITIALIZE DriverEntry; static VOID FspDriverMultiVersionInitialize(VOID); -#if defined(FSP_UNLOAD) -DRIVER_UNLOAD FspUnload; -#endif +static NTSTATUS FspDriverInitializeDevices(VOID); +static VOID FspDriverFinalizeDevices(VOID); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(INIT, FspDriverMultiVersionInitialize) -#if defined(FSP_UNLOAD) -#pragma alloc_text(PAGE, FspUnload) -#endif +#pragma alloc_text(PAGE, FspDriverInitializeDevices) +#pragma alloc_text(PAGE, FspDriverFinalizeDevices) #endif NTSTATUS DriverEntry( @@ -49,9 +39,6 @@ NTSTATUS DriverEntry( FSP_ENTER_DRV(); /* setup the driver object */ -#if defined(FSP_UNLOAD) - DriverObject->DriverUnload = FspUnload; -#endif DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose; DriverObject->MajorFunction[IRP_MJ_READ] = FspRead; @@ -133,94 +120,41 @@ NTSTATUS DriverEntry( #pragma prefast(suppress:28175, "We are a filesystem: ok to access FastIoDispatch") DriverObject->FastIoDispatch = &FspFastIoDispatch; - BOOLEAN InitDoneGRes = FALSE, InitDonePsBuf = FALSE; - UNICODE_STRING DeviceSddl; - UNICODE_STRING DeviceName; + BOOLEAN InitDoneGRes = FALSE, InitDoneSilo = FALSE, InitDonePsBuf = FALSE, + InitDoneDevices = FALSE; FspDriverObject = DriverObject; + FspDriverMultiVersionInitialize(); + ExInitializeResourceLite(&FspDeviceGlobalResource); InitDoneGRes = TRUE; - FspDriverMultiVersionInitialize(); + Result = FspSiloInitialize(FspDriverInitializeDevices, FspDriverFinalizeDevices); + if (!NT_SUCCESS(Result)) + goto exit; + InitDoneSilo = TRUE; Result = FspProcessBufferInitialize(); if (!NT_SUCCESS(Result)) goto exit; InitDonePsBuf = TRUE; - /* create the file system control device objects */ - RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL); - RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME); - Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, - &DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, - &DeviceSddl, &FspFsctlDeviceClassGuid, - &FspFsctlDiskDeviceObject); + Result = FspDriverInitializeDevices(); if (!NT_SUCCESS(Result)) goto exit; - RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME); - Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, - &DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, - &DeviceSddl, &FspFsctlDeviceClassGuid, - &FspFsctlNetDeviceObject); - if (!NT_SUCCESS(Result)) - goto exit; - Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0, - FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE, - &FspFsmupDeviceObject); - if (!NT_SUCCESS(Result)) - goto exit; - -#if DBG - /* - * Fix GitHub issue #177. All credit for the investigation of this issue - * and the suggested steps to reproduce and work around the problem goes - * to GitHub user @thinkport. - * - * On debug builds set DO_LOW_PRIORITY_FILESYSTEM to place the file system - * at the end of the file system list during IoRegisterFileSystem below. - * This allows us to test the behavior of our Fsvrt devices when foreign - * file systems attempt to use them for mounting. - */ - SetFlag(FspFsctlDiskDeviceObject->Flags, DO_LOW_PRIORITY_FILESYSTEM); -#endif - - Result = FspDeviceInitialize(FspFsctlDiskDeviceObject); - ASSERT(STATUS_SUCCESS == Result); - Result = FspDeviceInitialize(FspFsctlNetDeviceObject); - ASSERT(STATUS_SUCCESS == Result); - Result = FspDeviceInitialize(FspFsmupDeviceObject); - ASSERT(STATUS_SUCCESS == Result); - - RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME); - Result = FsRtlRegisterUncProviderEx(&FspMupHandle, - &DeviceName, FspFsmupDeviceObject, 0); - if (!NT_SUCCESS(Result)) - goto exit; - - /* - * Register our "disk" device as a file system. We do not register our "net" device - * as a file system; we register with the MUP instead. - * - * Please note that the call below makes our driver unloadable. In fact the driver - * remains unloadable even if we issue an IoUnregisterFileSystem() call immediately - * after our IoRegisterFileSystem() call! Some system component appears to keep an - * extra reference to our device somewhere. - */ - IoRegisterFileSystem(FspFsctlDiskDeviceObject); + InitDoneDevices = TRUE; Result = STATUS_SUCCESS; exit: if (!NT_SUCCESS(Result)) { - if (0 != FspFsmupDeviceObject) - FspDeviceDelete(FspFsmupDeviceObject); - if (0 != FspFsctlNetDeviceObject) - FspDeviceDelete(FspFsctlNetDeviceObject); - if (0 != FspFsctlDiskDeviceObject) - FspDeviceDelete(FspFsctlDiskDeviceObject); + if (InitDoneDevices) + FspDriverFinalizeDevices(); if (InitDonePsBuf) FspProcessBufferFinalize(); + if (InitDoneSilo) + FspSiloFinalize(); if (InitDoneGRes) ExDeleteResourceLite(&FspDeviceGlobalResource); } @@ -253,35 +187,157 @@ static VOID FspDriverMultiVersionInitialize(VOID) FspHasReparsePointCaseSensitivityFix = TRUE; } -#if defined(FSP_UNLOAD) -VOID FspUnload( - PDRIVER_OBJECT DriverObject) +static NTSTATUS FspDriverInitializeDevices(VOID) { - FSP_ENTER_VOID(PAGED_CODE()); + PAGED_CODE(); - FsRtlDeregisterUncProvider(FspMupHandle); + FSP_SILO_GLOBALS *Globals; + UNICODE_STRING DeviceSddl; + UNICODE_STRING DeviceName; + GUID Guid; + NTSTATUS Result; - FspFsctlDiskDeviceObject = 0; - FspFsctlNetDeviceObject = 0; - FspFsmupDeviceObject = 0; - //FspDeviceDeleteAll(); + FspSiloGetGlobals(&Globals); + ASSERT(0 != Globals); - ExDeleteResourceLite(&FspDeviceGlobalResource); - FspDriverObject = 0; + /* create the file system control device objects */ + RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL); + RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME); + Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, + &DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, + &DeviceSddl, &FspFsctlDeviceClassGuid, + &Globals->FsctlDiskDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; + RtlInitUnicodeString(&DeviceName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME); + Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0, + &DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, + &DeviceSddl, &FspFsctlDeviceClassGuid, + &Globals->FsctlNetDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; + Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0, + FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE, + &Globals->FsmupDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; - FspProcessBufferFinalize(); - -#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName") - FSP_LEAVE_VOID("DriverName=\"%wZ\"", - &DriverObject->DriverName); -} +#if DBG + /* + * Fix GitHub issue #177. All credit for the investigation of this issue + * and the suggested steps to reproduce and work around the problem goes + * to GitHub user @thinkport. + * + * On debug builds set DO_LOW_PRIORITY_FILESYSTEM to place the file system + * at the end of the file system list during IoRegisterFileSystem below. + * This allows us to test the behavior of our Fsvrt devices when foreign + * file systems attempt to use them for mounting. + */ + SetFlag(Globals->FsctlDiskDeviceObject->Flags, DO_LOW_PRIORITY_FILESYSTEM); #endif + Result = FspDeviceInitialize(Globals->FsctlDiskDeviceObject); + ASSERT(STATUS_SUCCESS == Result); + Result = FspDeviceInitialize(Globals->FsctlNetDeviceObject); + ASSERT(STATUS_SUCCESS == Result); + Result = FspDeviceInitialize(Globals->FsmupDeviceObject); + ASSERT(STATUS_SUCCESS == Result); + + FspSiloGetContainerId(&Guid); + RtlInitEmptyUnicodeString(&DeviceName, + Globals->FsmupDeviceNameBuf, sizeof Globals->FsmupDeviceNameBuf); + Result = RtlUnicodeStringPrintf(&DeviceName, + 0 == ((PULONG)&Guid)[0] && 0 == ((PULONG)&Guid)[1] && + 0 == ((PULONG)&Guid)[2] && 0 == ((PULONG)&Guid)[3] ? + L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME : + L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + Guid.Data1, Guid.Data2, Guid.Data3, + Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3], + Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); + ASSERT(NT_SUCCESS(Result)); + DeviceName.MaximumLength = DeviceName.Length; + Result = FsRtlRegisterUncProviderEx(&Globals->MupHandle, + &DeviceName, Globals->FsmupDeviceObject, 0); + if (!NT_SUCCESS(Result)) + { + Globals->MupHandle = 0; + goto exit; + } + + /* + * Register our "disk" device as a file system. We do not register our "net" device + * as a file system; we register with the MUP instead. + */ + IoRegisterFileSystem(Globals->FsctlDiskDeviceObject); + + Result = STATUS_SUCCESS; + +exit: + if (!NT_SUCCESS(Result)) + { + if (0 != Globals->MupHandle) + { + FsRtlDeregisterUncProvider(Globals->MupHandle); + Globals->MupHandle = 0; + } + if (0 != Globals->FsmupDeviceObject) + { + FspDeviceDelete(Globals->FsmupDeviceObject); + Globals->FsmupDeviceObject = 0; + } + if (0 != Globals->FsctlNetDeviceObject) + { + FspDeviceDelete(Globals->FsctlNetDeviceObject); + Globals->FsctlNetDeviceObject = 0; + } + if (0 != Globals->FsctlDiskDeviceObject) + { + FspDeviceDelete(Globals->FsctlDiskDeviceObject); + Globals->FsctlDiskDeviceObject = 0; + } + } + + FspSiloDereferenceGlobals(Globals); + + return Result; +} + +static VOID FspDriverFinalizeDevices(VOID) +{ + PAGED_CODE(); + + FSP_SILO_GLOBALS *Globals; + + FspSiloGetGlobals(&Globals); + ASSERT(0 != Globals); + + IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject); + + if (0 != Globals->MupHandle) + { + FsRtlDeregisterUncProvider(Globals->MupHandle); + Globals->MupHandle = 0; + } + if (0 != Globals->FsmupDeviceObject) + { + FspDeviceDelete(Globals->FsmupDeviceObject); + Globals->FsmupDeviceObject = 0; + } + if (0 != Globals->FsctlNetDeviceObject) + { + FspDeviceDelete(Globals->FsctlNetDeviceObject); + Globals->FsctlNetDeviceObject = 0; + } + if (0 != Globals->FsctlDiskDeviceObject) + { + FspDeviceDelete(Globals->FsctlDiskDeviceObject); + Globals->FsctlDiskDeviceObject = 0; + } + + FspSiloDereferenceGlobals(Globals); +} + PDRIVER_OBJECT FspDriverObject; -PDEVICE_OBJECT FspFsctlDiskDeviceObject; -PDEVICE_OBJECT FspFsctlNetDeviceObject; -PDEVICE_OBJECT FspFsmupDeviceObject; -HANDLE FspMupHandle; FAST_IO_DISPATCH FspFastIoDispatch; CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; diff --git a/src/sys/driver.h b/src/sys/driver.h index 2eaee33f..9391541a 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -652,6 +652,23 @@ VOID FspIrpHookReset(PIRP Irp); PVOID FspIrpHookContext(PVOID Context); NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); +/* silos */ +typedef struct +{ + PDEVICE_OBJECT FsctlDiskDeviceObject; + PDEVICE_OBJECT FsctlNetDeviceObject; + PDEVICE_OBJECT FsmupDeviceObject; + HANDLE MupHandle; + WCHAR FsmupDeviceNameBuf[64]; +} FSP_SILO_GLOBALS; +typedef NTSTATUS (*FSP_SILO_INIT_CALLBACK)(VOID); +typedef VOID (*FSP_SILO_FINI_CALLBACK)(VOID); +NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals); +VOID FspSiloDereferenceGlobals(FSP_SILO_GLOBALS *Globals); +VOID FspSiloGetContainerId(GUID *ContainerId); +NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini); +VOID FspSiloFinalize(VOID); + /* process buffers */ #define FspProcessBufferSizeMax (64 * 1024) NTSTATUS FspProcessBufferInitialize(VOID); @@ -1069,6 +1086,7 @@ typedef struct KSPIN_LOCK SpinLock; LONG RefCount; UINT32 Kind; + GUID SiloContainerId; } FSP_DEVICE_EXTENSION; typedef struct { @@ -1695,10 +1713,6 @@ FSP_MV_CcCoherencyFlushAndPurgeCache( /* extern */ extern PDRIVER_OBJECT FspDriverObject; -extern PDEVICE_OBJECT FspFsctlDiskDeviceObject; -extern PDEVICE_OBJECT FspFsctlNetDeviceObject; -extern PDEVICE_OBJECT FspFsmupDeviceObject; -extern HANDLE FspMupHandle; extern FAST_IO_DISPATCH FspFastIoDispatch; extern CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; diff --git a/src/sys/silo.c b/src/sys/silo.c new file mode 100644 index 00000000..d266aa60 --- /dev/null +++ b/src/sys/silo.c @@ -0,0 +1,325 @@ +/** + * @file sys/silo.c + * + * @copyright 2015-2020 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this software + * in accordance with the commercial license agreement provided in + * conjunction with the software. The terms and conditions of any such + * commercial license agreement shall govern, supersede, and render + * ineffective any application of the GPLv3 license to this software, + * notwithstanding of any reference thereto in the software or + * associated repository. + */ + +#include + +NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, FspSiloInitialize) +#endif + +typedef PEJOB FSP_PESILO; +typedef PVOID FSP_PSILO_MONITOR; + +typedef NTSTATUS (NTAPI *FSP_SILO_MONITOR_CREATE_CALLBACK)(FSP_PESILO Silo); +typedef VOID (NTAPI *FSP_SILO_MONITOR_TERMINATE_CALLBACK)(FSP_PESILO Silo); +typedef VOID (NTAPI *FSP_SILO_CONTEXT_CLEANUP_CALLBACK)(PVOID SiloContext); + +#pragma warning(push) +#pragma warning(disable:4201) /* nameless struct/union */ +typedef struct _FSP_SILO_MONITOR_REGISTRATION +{ + UCHAR Version; + BOOLEAN MonitorHost; + BOOLEAN MonitorExistingSilos; + UCHAR Reserved[5]; + union + { + PUNICODE_STRING DriverObjectName; + PUNICODE_STRING ComponentName; + }; + FSP_SILO_MONITOR_CREATE_CALLBACK CreateCallback; + FSP_SILO_MONITOR_TERMINATE_CALLBACK TerminateCallback; +} FSP_SILO_MONITOR_REGISTRATION; +#pragma warning(pop) + +typedef NTSTATUS FSP_SILO_PsRegisterSiloMonitor( + FSP_SILO_MONITOR_REGISTRATION *Registration, + FSP_PSILO_MONITOR *ReturnedMonitor); +typedef NTSTATUS FSP_SILO_PsStartSiloMonitor( + FSP_PSILO_MONITOR Monitor); +typedef VOID FSP_SILO_PsUnregisterSiloMonitor( + FSP_PSILO_MONITOR Monitor); +typedef ULONG FSP_SILO_PsGetSiloMonitorContextSlot( + FSP_PSILO_MONITOR Monitor); +typedef NTSTATUS FSP_SILO_PsCreateSiloContext( + FSP_PESILO Silo, + ULONG Size, + POOL_TYPE PoolType, + FSP_SILO_CONTEXT_CLEANUP_CALLBACK ContextCleanupCallback, + PVOID *ReturnedSiloContext); +typedef VOID FSP_SILO_PsDereferenceSiloContext( + PVOID SiloContext); +typedef NTSTATUS FSP_SILO_PsInsertSiloContext( + FSP_PESILO Silo, + ULONG ContextSlot, + PVOID SiloContext); +typedef NTSTATUS FSP_SILO_PsRemoveSiloContext( + FSP_PESILO Silo, + ULONG ContextSlot, + PVOID *RemovedSiloContext); +typedef NTSTATUS FSP_SILO_PsGetSiloContext( + FSP_PESILO Silo, + ULONG ContextSlot, + PVOID *ReturnedSiloContext); +typedef FSP_PESILO FSP_SILO_PsAttachSiloToCurrentThread( + FSP_PESILO Silo); +typedef VOID FSP_SILO_PsDetachSiloFromCurrentThread( + FSP_PESILO PreviousSilo); +typedef FSP_PESILO FSP_SILO_PsGetCurrentServerSilo( + VOID); +typedef GUID* FSP_SILO_PsGetSiloContainerId( + FSP_PESILO Silo); + +static FSP_SILO_PsRegisterSiloMonitor *FspSiloPsRegisterSiloMonitor; +static FSP_SILO_PsStartSiloMonitor *FspSiloPsStartSiloMonitor; +static FSP_SILO_PsUnregisterSiloMonitor *FspSiloPsUnregisterSiloMonitor; +static FSP_SILO_PsGetSiloMonitorContextSlot *FspSiloPsGetSiloMonitorContextSlot; +static FSP_SILO_PsCreateSiloContext *FspSiloPsCreateSiloContext; +static FSP_SILO_PsDereferenceSiloContext *FspSiloPsDereferenceSiloContext; +static FSP_SILO_PsInsertSiloContext *FspSiloPsInsertSiloContext; +static FSP_SILO_PsRemoveSiloContext *FspSiloPsRemoveSiloContext; +static FSP_SILO_PsGetSiloContext *FspSiloPsGetSiloContext; +static FSP_SILO_PsAttachSiloToCurrentThread *FspSiloPsAttachSiloToCurrentThread; +static FSP_SILO_PsDetachSiloFromCurrentThread *FspSiloPsDetachSiloFromCurrentThread; +static FSP_SILO_PsGetCurrentServerSilo *FspSiloPsGetCurrentServerSilo; +static FSP_SILO_PsGetSiloContainerId *FspSiloPsGetSiloContainerId; +static FSP_PSILO_MONITOR FspSiloMonitor; +static FSP_SILO_INIT_CALLBACK FspSiloInitCallback; +static FSP_SILO_FINI_CALLBACK FspSiloFiniCallback; +static BOOLEAN FspSiloInitDone = FALSE; + +static FSP_SILO_GLOBALS FspSiloHostGlobals; + +#define FSP_SILO_MONITOR_REGISTRATION_VERSION 1 + +#define LOAD(n) \ + { \ + UNICODE_STRING Name; \ + RtlInitUnicodeString(&Name, L"" #n);\ + FspSilo ## n = \ + (FSP_SILO_ ## n *)(UINT_PTR)MmGetSystemRoutineAddress(&Name);\ + if (0 == FspSilo ## n) \ + Fail++; \ + } +#define CALL(n) (FspSilo ## n) + +NTSTATUS FspSiloGetGlobals(FSP_SILO_GLOBALS **PGlobals) +{ + FSP_PESILO Silo; + ULONG ContextSlot; + FSP_SILO_GLOBALS *Globals; + NTSTATUS Result; + + if (!FspSiloInitDone || + 0 == (Silo = CALL(PsGetCurrentServerSilo)())) + { + *PGlobals = &FspSiloHostGlobals; + return STATUS_SUCCESS; + } + + ContextSlot = CALL(PsGetSiloMonitorContextSlot)(FspSiloMonitor); + + Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals); + if (!NT_SUCCESS(Result)) + { + *PGlobals = 0; + return Result; + } + + *PGlobals = Globals; + return STATUS_SUCCESS; +} + +VOID FspSiloDereferenceGlobals(FSP_SILO_GLOBALS *Globals) +{ + if (&FspSiloHostGlobals == Globals) + return; + + CALL(PsDereferenceSiloContext)(Globals); +} + +VOID FspSiloGetContainerId(GUID *ContainerId) +{ + FSP_PESILO Silo; + GUID *Guid; + + if (!FspSiloInitDone || + 0 == (Silo = CALL(PsGetCurrentServerSilo)()) || + 0 == (Guid = CALL(PsGetSiloContainerId)(Silo))) + { + RtlZeroMemory(ContainerId, sizeof *ContainerId); + return; + } + + RtlCopyMemory(ContainerId, Guid, sizeof *ContainerId); +} + +static NTSTATUS NTAPI FspSiloMonitorCreateCallback(FSP_PESILO Silo) +{ + ULONG ContextSlot; + FSP_SILO_GLOBALS *Globals = 0; + BOOLEAN Inserted = FALSE; + NTSTATUS Result; + + ASSERT(0 != Silo); + + ContextSlot = CALL(PsGetSiloMonitorContextSlot)(FspSiloMonitor); + + Result = CALL(PsCreateSiloContext)(Silo, sizeof(FSP_SILO_GLOBALS), NonPagedPoolNx, 0, &Globals); + if (!NT_SUCCESS(Result)) + goto exit; + RtlZeroMemory(Globals, sizeof(FSP_SILO_GLOBALS)); + + /* PsInsertSiloContext adds reference to Globals */ + Result = CALL(PsInsertSiloContext)(Silo, ContextSlot, Globals); + if (!NT_SUCCESS(Result)) + goto exit; + Inserted = TRUE; + + if (0 != FspSiloInitCallback) + { + FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo); + Result = FspSiloInitCallback(); + CALL(PsDetachSiloFromCurrentThread)(PreviousSilo); + } + +exit: + if (!NT_SUCCESS(Result)) + { + if (Inserted) + CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0); + } + + if (0 != Globals) + CALL(PsDereferenceSiloContext)(Globals); + + /* + * Ignore errors and return success. There are two reasons for this: + * + * - Returning an error will disallow container creation. + * - In some cases returning an error will crash Windows with an + * unexpected page fault in wcifs.sys. + */ + return STATUS_SUCCESS; +} + +static VOID NTAPI FspSiloMonitorTerminateCallback(FSP_PESILO Silo) +{ + ULONG ContextSlot; + FSP_SILO_GLOBALS *Globals; + NTSTATUS Result; + + ASSERT(0 != Silo); + + ContextSlot = CALL(PsGetSiloMonitorContextSlot)(FspSiloMonitor); + + /* if we cannot get the Globals, it must mean that we failed in Create callback */ + Result = CALL(PsGetSiloContext)(Silo, ContextSlot, &Globals); + if (!NT_SUCCESS(Result)) + return; + CALL(PsDereferenceSiloContext)(Globals); + Globals = 0; + + if (0 != FspSiloFiniCallback) + { + FSP_PESILO PreviousSilo = CALL(PsAttachSiloToCurrentThread)(Silo); + FspSiloFiniCallback(); + CALL(PsDetachSiloFromCurrentThread)(PreviousSilo); + } + + /* PsRemoveSiloContext removes reference to Globals (possibly freeing it) */ + CALL(PsRemoveSiloContext)(Silo, ContextSlot, 0); +} + +NTSTATUS FspSiloInitialize(FSP_SILO_INIT_CALLBACK Init, FSP_SILO_FINI_CALLBACK Fini) +{ + NTSTATUS Result = STATUS_SUCCESS; + + if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS5)) + { + ULONG Fail = 0; + + LOAD(PsRegisterSiloMonitor); + LOAD(PsStartSiloMonitor); + LOAD(PsUnregisterSiloMonitor); + LOAD(PsGetSiloMonitorContextSlot); + LOAD(PsCreateSiloContext); + LOAD(PsDereferenceSiloContext); + LOAD(PsInsertSiloContext); + LOAD(PsRemoveSiloContext); + LOAD(PsGetSiloContext); + LOAD(PsAttachSiloToCurrentThread); + LOAD(PsDetachSiloFromCurrentThread); + LOAD(PsGetCurrentServerSilo); + LOAD(PsGetSiloContainerId); + + if (0 == Fail) + { + FSP_SILO_MONITOR_REGISTRATION Registration = + { + .Version = FSP_SILO_MONITOR_REGISTRATION_VERSION, + .MonitorHost = FALSE, + .MonitorExistingSilos = TRUE, + .DriverObjectName = 0, + .CreateCallback = FspSiloMonitorCreateCallback, + .TerminateCallback = FspSiloMonitorTerminateCallback, + }; + FSP_PSILO_MONITOR Monitor = 0; + UNICODE_STRING DriverName; + + RtlInitUnicodeString(&DriverName, L"" DRIVER_NAME); + Registration.DriverObjectName = &DriverName; + Result = CALL(PsRegisterSiloMonitor)(&Registration, &Monitor); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = CALL(PsStartSiloMonitor)(Monitor); + if (!NT_SUCCESS(Result)) + goto exit; + + FspSiloMonitor = Monitor; + FspSiloInitCallback = Init; + FspSiloFiniCallback = Fini; + + FspSiloInitDone = TRUE; + Result = STATUS_SUCCESS; + + exit: + if (!NT_SUCCESS(Result)) + { + if (0 != Monitor) + CALL(PsUnregisterSiloMonitor)(Monitor); + } + } + } + + return Result; +} + +VOID FspSiloFinalize(VOID) +{ + if (!FspSiloInitDone) + return; + + CALL(PsUnregisterSiloMonitor)(FspSiloMonitor); +} diff --git a/src/sys/volume.c b/src/sys/volume.c index 06784a4b..2017432e 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -24,11 +24,13 @@ NTSTATUS FspVolumeCreate( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspVolumeCreateNoLock( - PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + FSP_SILO_GLOBALS *Globals); VOID FspVolumeDelete( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static VOID FspVolumeDeleteNoLock( - PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + FSP_SILO_GLOBALS *Globals); static WORKER_THREAD_ROUTINE FspVolumeDeleteDelayed; NTSTATUS FspVolumeMount( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); @@ -77,15 +79,25 @@ NTSTATUS FspVolumeCreate( { PAGED_CODE(); + FSP_SILO_GLOBALS *Globals; NTSTATUS Result; + + FspSiloGetGlobals(&Globals); + ASSERT(0 != Globals); + FspDeviceGlobalLock(); - Result = FspVolumeCreateNoLock(FsctlDeviceObject, Irp, IrpSp); + Result = FspVolumeCreateNoLock(FsctlDeviceObject, Irp, IrpSp, + Globals); FspDeviceGlobalUnlock(); + + FspSiloDereferenceGlobals(Globals); + return Result; } static NTSTATUS FspVolumeCreateNoLock( - PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + FSP_SILO_GLOBALS *Globals) { PAGED_CODE(); @@ -302,18 +314,18 @@ static NTSTATUS FspVolumeCreateNoLock( /* do we need to register with fsmup? */ if (0 == FsvrtDeviceObject) { - Result = FspMupRegister(FspFsmupDeviceObject, FsvolDeviceObject); + Result = FspMupRegister(Globals->FsmupDeviceObject, FsvolDeviceObject); if (!NT_SUCCESS(Result)) { FspDeviceDereference(FsvolDeviceObject); return Result; } - RtlInitUnicodeString(&FsmupDeviceName, L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME); + RtlInitUnicodeString(&FsmupDeviceName, Globals->FsmupDeviceNameBuf); Result = IoCreateSymbolicLink(&FsvolDeviceExtension->VolumeName, &FsmupDeviceName); if (!NT_SUCCESS(Result)) { - FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject); + FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject); FspDeviceDereference(FsvolDeviceObject); return Result; } @@ -331,6 +343,7 @@ VOID FspVolumeDelete( { // !PAGED_CODE(); + FSP_SILO_GLOBALS *Globals; PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; @@ -350,10 +363,16 @@ VOID FspVolumeDelete( FspDeviceReference(FsvolDeviceObject); + FspSiloGetGlobals(&Globals); + ASSERT(0 != Globals); + FspDeviceGlobalLock(); - FspVolumeDeleteNoLock(FsctlDeviceObject, Irp, IrpSp); + FspVolumeDeleteNoLock(FsctlDeviceObject, Irp, IrpSp, + Globals); FspDeviceGlobalUnlock(); + FspSiloDereferenceGlobals(Globals); + /* * Call MmForceSectionClosed on active files to ensure that Mm removes them from Standby List. */ @@ -370,7 +389,8 @@ VOID FspVolumeDelete( } static VOID FspVolumeDeleteNoLock( - PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) + PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + FSP_SILO_GLOBALS *Globals) { // !PAGED_CODE(); @@ -445,7 +465,7 @@ static VOID FspVolumeDeleteNoLock( else { IoDeleteSymbolicLink(&FsvolDeviceExtension->VolumeName); - FspMupUnregister(FspFsmupDeviceObject, FsvolDeviceObject); + FspMupUnregister(Globals->FsmupDeviceObject, FsvolDeviceObject); } /* release the volume device object */