From b637a72ec88be05e441eb67c8783845aedde2b0c Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 18 Jun 2019 16:11:38 -0700 Subject: [PATCH] sys: FspFsextProvider --- inc/winfsp/fsctl.h | 9 ++++- opt/fsext/inc/winfsp/fsext.h | 4 +- src/sys/device.c | 31 ++++++++++++++++ src/sys/driver.h | 5 ++- src/sys/fsctl.c | 28 ++++++++++++++ src/sys/fsext.c | 2 +- src/sys/volume.c | 71 +++++++++++++++++++++++++++++------- 7 files changed, 129 insertions(+), 21 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 24c63ef1..ffa455c8 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -65,6 +65,10 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = #define FSP_FSCTL_STOP \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS) +/* fsctl internal device codes (usable only in-kernel) */ +#define FSP_FSCTL_TRANSACT_INTERNAL \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'I', METHOD_NEITHER, FILE_ANY_ACCESS) + #define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams=" #define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR)) @@ -83,7 +87,7 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR), #define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024) #define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX -#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((T) & 0xffffffff)) +#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((UINT_PTR)((T) & 0xffffffff))) #define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff)) #define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */ @@ -185,7 +189,8 @@ enum UINT32 SecurityTimeout; /* security info timeout (millis); overrides FileInfoTimeout */\ UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\ UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */\ - UINT32 Reserved32[2];\ + UINT32 FsextControlCode;\ + UINT32 Reserved32[1];\ UINT64 Reserved64[2]; typedef struct { diff --git a/opt/fsext/inc/winfsp/fsext.h b/opt/fsext/inc/winfsp/fsext.h index 2d16a515..e16b18b8 100644 --- a/opt/fsext/inc/winfsp/fsext.h +++ b/opt/fsext/inc/winfsp/fsext.h @@ -43,10 +43,10 @@ typedef struct /* in */ UINT32 DeviceTransactCode; UINT32 DeviceExtensionSize; - NTSTATUS (*DeviceInit)(PDEVICE_OBJECT DeviceObject); + NTSTATUS (*DeviceInit)(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_PARAMS *VolumeParams); VOID (*DeviceFini)(PDEVICE_OBJECT DeviceObject); VOID (*DeviceExpirationRoutine)(PDEVICE_OBJECT DeviceObject, UINT64 ExpirationTime); - NTSTATUS (*DeviceTransact)(PIRP Irp, PDEVICE_OBJECT DeviceObject); + NTSTATUS (*DeviceTransact)(PDEVICE_OBJECT DeviceObject, PIRP Irp); /* out */ UINT32 DeviceExtensionOffset; } FSP_FSEXT_PROVIDER; diff --git a/src/sys/device.c b/src/sys/device.c index edf74336..af4bcf29 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -325,6 +325,20 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) * to track what has been initialized! */ + /* initialize any fsext provider */ + if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode) + { + FSP_FSEXT_PROVIDER *Provider = FspFsextProvider( + FsvolDeviceExtension->VolumeParams.FsextControlCode); + if (0 != Provider) + { + Result = Provider->DeviceInit(DeviceObject, &FsvolDeviceExtension->VolumeParams); + if (!NT_SUCCESS(Result)) + return Result; + FsvolDeviceExtension->InitDoneFsext = 1; + } + } + /* is there a virtual disk? */ if (0 != FsvolDeviceExtension->FsvrtDeviceObject) { @@ -500,6 +514,15 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) if (0 != FsvolDeviceExtension->SwapVpb) FspFreeExternal(FsvolDeviceExtension->SwapVpb); } + + /* finalize any fsext provider */ + if (FsvolDeviceExtension->InitDoneFsext) + { + FSP_FSEXT_PROVIDER *Provider = FspFsextProvider( + FsvolDeviceExtension->VolumeParams.FsextControlCode); + if (0 != Provider) + Provider->DeviceFini(DeviceObject); + } } static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context) @@ -546,6 +569,14 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context) FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime); + /* run any fsext provider expiration routine */ + if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode) + { + FSP_FSEXT_PROVIDER *Provider = FspFsextProvider( + FsvolDeviceExtension->VolumeParams.FsextControlCode); + if (0 != Provider) + Provider->DeviceExpirationRoutine(DeviceObject, InterruptTime); + } FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime); KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql); diff --git a/src/sys/driver.h b/src/sys/driver.h index 9621edfb..1e7c4897 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1056,7 +1056,8 @@ typedef struct { FSP_DEVICE_EXTENSION Base; UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, InitDoneEa:1, - InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1; + InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1, + InitDoneFsext; PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject; PDEVICE_OBJECT FsvolDeviceObject; @@ -1179,7 +1180,7 @@ VOID FspDeviceGlobalUnlock(VOID) // STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED) /* fsext */ -FSP_FSEXT_PROVIDER *FspFsextProvider(VOID); +FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 ControlCode); /* process buffers conditional usage */ static inline diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index 58b01777..e000dfa4 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -86,6 +86,7 @@ static NTSTATUS FspFsctlFileSystemControl( break; case FSP_FSCTL_TRANSACT: case FSP_FSCTL_TRANSACT_BATCH: + case FSP_FSCTL_TRANSACT_INTERNAL: if (0 != IrpSp->FileObject->FsContext2) Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp); break; @@ -93,6 +94,33 @@ static NTSTATUS FspFsctlFileSystemControl( if (0 != IrpSp->FileObject->FsContext2) Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp); break; + case 0: + /* ensure that 0 != IrpSp->Parameters.FileSystemControl.FsControlCode in default: case */ + break; + default: + if (0 != IrpSp->FileObject->FsContext2) + { + PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; + if (!FspDeviceReference(FsvolDeviceObject)) + { + Result = STATUS_CANCELLED; + break; + } + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension( + FsvolDeviceObject); + if (IrpSp->Parameters.FileSystemControl.FsControlCode == + FsvolDeviceExtension->VolumeParams.FsextControlCode) + { + FSP_FSEXT_PROVIDER *Provider = FspFsextProvider( + FsvolDeviceExtension->VolumeParams.FsextControlCode); + if (0 != Provider) + Result = Provider->DeviceTransact(FsvolDeviceObject, Irp); + } + + FspDeviceDereference(FsvolDeviceObject); + } + break; } break; case IRP_MN_MOUNT_VOLUME: diff --git a/src/sys/fsext.c b/src/sys/fsext.c index 1c3e1ce3..4f5ba307 100644 --- a/src/sys/fsext.c +++ b/src/sys/fsext.c @@ -25,7 +25,7 @@ static KSPIN_LOCK FsextSpinLock = 0; FSP_FSEXT_PROVIDER *FsextProvider; -FSP_FSEXT_PROVIDER *FspFsextProvider(VOID) +FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 ControlCode) { FSP_FSEXT_PROVIDER *Provider; KIRQL Irql; diff --git a/src/sys/volume.c b/src/sys/volume.c index 6cfc645c..f26b450b 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -652,7 +652,8 @@ NTSTATUS FspVolumeTransact( ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction); ASSERT( FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode || - FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode); + FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode || + FSP_FSCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode); ASSERT( METHOD_BUFFERED == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3) || METHOD_OUT_DIRECT == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3)); @@ -663,17 +664,31 @@ NTSTATUS FspVolumeTransact( ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; - PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer; + PVOID InputBuffer = 0; PVOID OutputBuffer = 0; - if (0 != InputBufferLength && - FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength) - return STATUS_INVALID_PARAMETER; - if (0 != OutputBufferLength && - ((FSP_FSCTL_TRANSACT == ControlCode && - FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) || - (FSP_FSCTL_TRANSACT_BATCH == ControlCode && - FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength))) - return STATUS_BUFFER_TOO_SMALL; + if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode) + { + InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer; + if (KernelMode != Irp->RequestorMode) + return STATUS_INVALID_DEVICE_REQUEST; + ASSERT(0 == InputBufferLength || + FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) <= InputBufferLength); + ASSERT(0 == OutputBufferLength || + sizeof(PVOID) <= OutputBufferLength); + } + else + { + InputBuffer = Irp->AssociatedIrp.SystemBuffer; + if (0 != InputBufferLength && + FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength) + return STATUS_INVALID_PARAMETER; + if (0 != OutputBufferLength && + ((FSP_FSCTL_TRANSACT == ControlCode && + FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) || + (FSP_FSCTL_TRANSACT_BATCH == ControlCode && + FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength))) + return STATUS_BUFFER_TOO_SMALL; + } if (!FspDeviceReference(FsvolDeviceObject)) return STATUS_CANCELLED; @@ -683,6 +698,7 @@ NTSTATUS FspVolumeTransact( PUINT8 BufferEnd; FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; + PVOID InternalBuffer = 0; PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp; ULONG LoopCount; LARGE_INTEGER Timeout; @@ -751,6 +767,9 @@ NTSTATUS FspVolumeTransact( /* were we sent an output buffer? */ switch (ControlCode & 3) { + case METHOD_NEITHER: + OutputBuffer = Irp->UserBuffer; + break; case METHOD_OUT_DIRECT: if (0 != Irp->MdlAddress) OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); @@ -795,7 +814,9 @@ NTSTATUS FspVolumeTransact( RepostedIrp = 0; Request = OutputBuffer; BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength; - ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd)); + ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ? + TRUE : + FspFsctlTransactCanProduceRequest(Request, BufferEnd)); LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq); for (;;) { @@ -816,8 +837,18 @@ NTSTATUS FspVolumeTransact( FspIopCompleteIrp(PendingIrp, Result); else { - RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size); - Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size); + if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode) + { + InternalBuffer = FspAllocatePoolMustSucceed( + PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG); + RtlCopyMemory(InternalBuffer, PendingIrpRequest, PendingIrpRequest->Size); + *(PVOID *)OutputBuffer = InternalBuffer; + } + else + { + RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size); + Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size); + } if (!FspIoqStartProcessingIrp(FsvolDeviceExtension->Ioq, PendingIrp)) { @@ -828,12 +859,24 @@ NTSTATUS FspVolumeTransact( * also cancel the PendingIrp we have in our hands. */ ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq)); + if (0 != InternalBuffer) + { + ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode); + FspFree(InternalBuffer); + } FspIopCompleteCanceledIrp(PendingIrp); Result = STATUS_CANCELLED; goto exit; } /* are we doing single request or batch mode? */ + if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode) + { + Irp->IoStatus.Information = sizeof(PVOID); + Result = STATUS_SUCCESS; + goto exit; + } + else if (FSP_FSCTL_TRANSACT == ControlCode) break;