mirror of
https://github.com/winfsp/winfsp.git
synced 2026-09-02 08:48:38 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fde790d8ea | ||
|
|
f97012ec46 | ||
|
|
43b9a6e222 | ||
|
|
f41f3afa07 | ||
|
|
d0bd2170bd | ||
|
|
57e0a24dd0 | ||
|
|
5b53285545 | ||
|
|
7ee0873f4b | ||
|
|
97e6d92b5b | ||
|
|
a744d6f24c | ||
|
|
1916d9bf06 |
@@ -1,6 +1,35 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## v2.2B4 (2026 Beta4)
|
||||
|
||||
- [FIX] Fixes vulnerability CVE-2026-3006 reported by Tay Kiat Loong (GitHub: @Owl4444).
|
||||
|
||||
- [FIX] Fixes vulnerability CVE-2026-7162 reported by Tay Kiat Loong (GitHub: @Owl4444) and uhg (GitHub: @UltimateHG).
|
||||
|
||||
- [FIX] Fixes vulnerability reported by Wencheng Xue (GitHub @panwnvda).
|
||||
|
||||
- [FIX] Fixes vulnerability reported by Abhinav Agarwal (GitHub @abhinavagarwal07).
|
||||
|
||||
- [FIX] Fixes deadlock during cached writes under memory pressure. See PR #677 for discussion.
|
||||
|
||||
- [FIX] Fixes deadlock in the file system notification mechanism with concurrent renames. See fix PR #669 by @yeonsh and test PR #672 by @Maksim-Isakau.
|
||||
|
||||
- [FIX] Fixes deadlock when closing named streams while the file system is being forcibly terminated. See issue #680.
|
||||
|
||||
- [FIX] Fixes another complicated deadlock when the file system is being forcibly terminated. See issue #682.
|
||||
|
||||
- [FIX] The WinFsp Network Provider provides improved shell support for network file systems not managed by the Launcher. See commit f021496.
|
||||
|
||||
- [FIX] Fixes a problem with mounting on a directory with a trailing backslash. See issue #674.
|
||||
|
||||
- [FUSE] Add FUSE option `FlushOnCleanup`. See PR #614 by @chenjie4255.
|
||||
|
||||
- [FUSE] FUSE now respects the `direct_io` flag. See PR #646 by @chenjie4255.
|
||||
|
||||
- [FUSE] Add FUSE option `AddWriteEaAccess`. See PR #648 by @chenjie4255.
|
||||
|
||||
|
||||
## v2.2B3 (2026 Beta3)
|
||||
|
||||
- [FIX] Fixes vulnerability CVE-2026-3006 discovered by Tay Kiat Loong (GitHub: @Owl4444).
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<MyCanonicalVersion>2.2</MyCanonicalVersion>
|
||||
|
||||
<MyProductVersion>2026 Beta3</MyProductVersion>
|
||||
<MyProductVersion>2026 Beta4</MyProductVersion>
|
||||
<MyProductStage>Beta</MyProductStage>
|
||||
|
||||
<MyCrossCert>CrossCert.cer</MyCrossCert>
|
||||
|
||||
@@ -127,6 +127,11 @@ HANDLE FspCreateDirectoryFileW(
|
||||
Length = GetFullPathNameW(FileName, Length + 1, FullFileName, &FilePart);
|
||||
if (0 == Length)
|
||||
goto exit;
|
||||
if (0 == FilePart)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
FilePartChar = *FilePart;
|
||||
*FilePart = L'\0';
|
||||
|
||||
+2
-1
@@ -179,7 +179,8 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||
{
|
||||
DirInfoSize = DirInfo->Size;
|
||||
|
||||
if (sizeof(FSP_FSCTL_DIR_INFO) > DirInfoSize)
|
||||
if (sizeof(FSP_FSCTL_DIR_INFO) > DirInfoSize ||
|
||||
(SIZE_T)(DirInfoEnd - (PUINT8)DirInfo) < DirInfoSize)
|
||||
{
|
||||
if (0 == *PDestLen)
|
||||
return STATUS_NO_MORE_FILES;
|
||||
|
||||
+6
-2
@@ -698,14 +698,18 @@ NTSTATUS FspOplockFsctrl(
|
||||
/* utility: synchronous work queue */
|
||||
typedef struct
|
||||
{
|
||||
KEVENT Event;
|
||||
LONG RefCount;
|
||||
PWORKER_THREAD_ROUTINE Routine;
|
||||
PVOID Context;
|
||||
KEVENT Event;
|
||||
WORK_QUEUE_ITEM WorkQueueItem;
|
||||
} FSP_SYNCHRONOUS_WORK_ITEM;
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem);
|
||||
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
BOOLEAN Alertable);
|
||||
|
||||
/* utility: delayed work queue */
|
||||
typedef struct
|
||||
|
||||
+33
-3
@@ -121,6 +121,7 @@ NTSTATUS FspMainFileOpen(
|
||||
NTSTATUS FspMainFileClose(
|
||||
HANDLE MainFileHandle,
|
||||
PFILE_OBJECT MainFileObject);
|
||||
static WORKER_THREAD_ROUTINE FspMainFileCloseSynchronousWork;
|
||||
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
|
||||
VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
|
||||
@@ -183,6 +184,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
#pragma alloc_text(PAGE, FspFileDescSetDirectoryMarker)
|
||||
#pragma alloc_text(PAGE, FspMainFileOpen)
|
||||
#pragma alloc_text(PAGE, FspMainFileClose)
|
||||
#pragma alloc_text(PAGE, FspMainFileCloseSynchronousWork)
|
||||
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
|
||||
#pragma alloc_text(PAGE, FspFileNodeOplockComplete)
|
||||
#endif
|
||||
@@ -2803,14 +2805,42 @@ NTSTATUS FspMainFileClose(
|
||||
|
||||
if (0 != MainFileHandle)
|
||||
{
|
||||
Result = ObCloseHandle(MainFileHandle, KernelMode);
|
||||
if (!NT_SUCCESS(Result))
|
||||
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *WorkItem;
|
||||
|
||||
WorkItem = DEBUGTEST(90) ?
|
||||
FspAllocateSynchronousWorkItem(FspMainFileCloseSynchronousWork, MainFileHandle) :
|
||||
0;
|
||||
if (0 != WorkItem)
|
||||
/*
|
||||
* Fix issue #680:
|
||||
* Instead of closing the main file handle in this thread, close it in a system thread
|
||||
* and wait for that close to complete in an alertable manner. This avoids a deadlock
|
||||
* due to the file system process being forcibly terminated via NtTerminateProcess.
|
||||
*/
|
||||
Result = FspExecuteSynchronousWorkItem(WorkItem, TRUE);
|
||||
else
|
||||
/*
|
||||
* Best effort: Close the main file handle in this thread.
|
||||
* Small chance of deadlock if someone is killing our file system.
|
||||
*/
|
||||
FspMainFileCloseSynchronousWork(MainFileHandle);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspMainFileCloseSynchronousWork(PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
HANDLE MainFileHandle = Context;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = ObCloseHandle(MainFileHandle, KernelMode);
|
||||
if (!NT_SUCCESS(Result))
|
||||
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result));
|
||||
}
|
||||
|
||||
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
+2
-1
@@ -669,7 +669,8 @@ static NTSTATUS FspFsvolQueryStreamInformationCopy(
|
||||
{
|
||||
StreamInfoSize = StreamInfo->Size;
|
||||
|
||||
if (sizeof(FSP_FSCTL_STREAM_INFO) > StreamInfoSize)
|
||||
if (sizeof(FSP_FSCTL_STREAM_INFO) > StreamInfoSize ||
|
||||
(SIZE_T)(StreamInfoEnd - (PUINT8)StreamInfo) < StreamInfoSize)
|
||||
break;
|
||||
|
||||
StreamNameLength = StreamInfoSize - sizeof(FSP_FSCTL_STREAM_INFO) + STREAM_EXTRA_LENGTH;
|
||||
|
||||
+47
-7
@@ -115,9 +115,12 @@ NTSTATUS FspOplockFsctrl(
|
||||
POPLOCK Oplock,
|
||||
PIRP Irp,
|
||||
ULONG OpenCount);
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem);
|
||||
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
BOOLEAN Alertable);
|
||||
static WORKER_THREAD_ROUTINE FspExecuteSynchronousWorkItemRoutine;
|
||||
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
@@ -167,6 +170,7 @@ LONG FspCompareUnicodeString(
|
||||
#pragma alloc_text(PAGE, FspCheckOplock)
|
||||
#pragma alloc_text(PAGE, FspCheckOplockEx)
|
||||
#pragma alloc_text(PAGE, FspOplockFsctrl)
|
||||
#pragma alloc_text(PAGE, FspAllocateSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
|
||||
@@ -1123,27 +1127,56 @@ NTSTATUS FspOplockFsctrl(
|
||||
return Result;
|
||||
}
|
||||
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem;
|
||||
|
||||
SynchronousWorkItem = FspAllocNonPaged(sizeof *SynchronousWorkItem);
|
||||
if (0 != SynchronousWorkItem)
|
||||
{
|
||||
FspInitializeSynchronousWorkItem(SynchronousWorkItem, Routine, Context);
|
||||
SynchronousWorkItem->RefCount = 2; /* make it refcounted */
|
||||
}
|
||||
|
||||
return SynchronousWorkItem;
|
||||
}
|
||||
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
||||
SynchronousWorkItem->RefCount = 0; /* initialize as non-refcounted */
|
||||
SynchronousWorkItem->Routine = Routine;
|
||||
SynchronousWorkItem->Context = Context;
|
||||
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
|
||||
ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem,
|
||||
FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem);
|
||||
}
|
||||
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem)
|
||||
NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
BOOLEAN Alertable)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
|
||||
|
||||
NTSTATUS Result;
|
||||
Result = KeWaitForSingleObject(&SynchronousWorkItem->Event, Executive, KernelMode, FALSE, 0);
|
||||
ASSERT(STATUS_SUCCESS == Result);
|
||||
|
||||
/* Alertable=TRUE requires item allocated by FspAllocateSynchronousWorkItem */
|
||||
ASSERT(!Alertable || 0 < SynchronousWorkItem->RefCount);
|
||||
|
||||
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
|
||||
Result = KeWaitForSingleObject(&SynchronousWorkItem->Event, Executive, KernelMode, Alertable, 0);
|
||||
|
||||
if (0 < SynchronousWorkItem->RefCount)
|
||||
{
|
||||
if (0 == InterlockedDecrement(&SynchronousWorkItem->RefCount))
|
||||
FspFree(SynchronousWorkItem);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
||||
@@ -1151,8 +1184,15 @@ static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context;
|
||||
|
||||
SynchronousWorkItem->Routine(SynchronousWorkItem->Context);
|
||||
KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE);
|
||||
|
||||
if (0 < SynchronousWorkItem->RefCount)
|
||||
{
|
||||
if (0 == InterlockedDecrement(&SynchronousWorkItem->RefCount))
|
||||
FspFree(SynchronousWorkItem);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
|
||||
|
||||
+8
-4
@@ -432,6 +432,9 @@ VOID FspVolumeDelete(
|
||||
ULONG FileNodeCount, Index;
|
||||
NTSTATUS Result;
|
||||
|
||||
/* stop the I/O queue */
|
||||
FspIoqStop(FsvolDeviceExtension->Ioq, TRUE);
|
||||
|
||||
FspFsvolDeviceVolumeDeleteAcquireExclusive(FsvolDeviceObject);
|
||||
FsvolDeviceExtension->VolumeDeleted = TRUE;
|
||||
|
||||
@@ -486,9 +489,6 @@ static VOID FspVolumeDeleteNoLock(
|
||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
|
||||
/* stop the I/O queue */
|
||||
FspIoqStop(FsvolDeviceExtension->Ioq, TRUE);
|
||||
|
||||
/* do we have a virtual disk device or are we registered with fsmup? */
|
||||
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
|
||||
{
|
||||
@@ -1381,6 +1381,7 @@ NTSTATUS FspVolumeNotify(
|
||||
ASSERT(0 != IrpSp->FileObject->FsContext2);
|
||||
|
||||
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PVOID InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
||||
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||
FSP_VOLUME_NOTIFY_WORK_ITEM *NotifyWorkItem = 0;
|
||||
@@ -1396,7 +1397,8 @@ NTSTATUS FspVolumeNotify(
|
||||
return STATUS_CANCELLED;
|
||||
|
||||
FspFsvolDeviceVolumeDeleteAcquireShared(FsvolDeviceObject);
|
||||
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeDeleted)
|
||||
if (FsvolDeviceExtension->VolumeDeleted ||
|
||||
FspIoqStopped(FsvolDeviceExtension->Ioq))
|
||||
{
|
||||
Result = STATUS_CANCELLED;
|
||||
goto fail;
|
||||
@@ -1523,6 +1525,8 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
|
||||
Unlock = TRUE;
|
||||
break;
|
||||
}
|
||||
if ((SIZE_T)(NotifyInfoEnd - (PUINT8)NotifyInfo) < NotifyInfoSize)
|
||||
break;
|
||||
|
||||
FileName.Length =
|
||||
FileName.MaximumLength = (USHORT)(NotifyInfoSize - sizeof(FSP_FSCTL_NOTIFY_INFO));
|
||||
|
||||
Reference in New Issue
Block a user