1
0
mirror of https://github.com/winfsp/winfsp.git synced 2026-06-29 15:51:04 -05:00

Compare commits

..

14 Commits

Author SHA1 Message Date
Bill Zissimopoulos e7c7ccc5c4 build: version 2026 Beta2 2026-06-23 15:48:18 +03:00
Bill Zissimopoulos 0953e76255 changelog: 2026 Beta2 2026-06-23 15:46:35 +03:00
Bill Zissimopoulos 932e52769d Contributors: sort names 2026-06-23 15:27:31 +03:00
Bill Zissimopoulos 9d1b37f0f1 Merge pull request #672 from Maksim-Isakau/test-notify-rename-race
tst: notify_rename_race_test: repro notify/rename deadlock
2026-06-23 15:24:24 +03:00
Bill Zissimopoulos 169eb2c35d Merge pull request #669 from yeonsh/fix-notify-rename-selfdeadlock
sys: fix FileRenameResource self-deadlock between notify session and FspVolumeNotifyWork
2026-06-23 15:21:41 +03:00
Seunghoon Yeon 786b8e2707 Updated Contributors.asciidoc 2026-06-23 20:13:24 +09:00
Max Isakov 2669a86a8e Max Isakov - sign Contributor Agreement 2026-06-23 12:46:23 +02:00
Max Isakov f7b313313f tst: notify_rename_race_test: repro notify/rename deadlock 2026-06-21 09:50:03 +02:00
Bill Zissimopoulos bd8b54c469 sys: FspVolumeNotify: fix integer overflow vulnerability
This vulnerability was reported by:
- Tay Kiat Loong (GitHub: @owl4444)
- uhg (GitHub: @UltimateHG)
2026-06-13 16:41:35 +03:00
Bill Zissimopoulos bdab233e92 doc: add KeibiDrop to known file systems 2026-06-13 15:01:36 +03:00
Bill Zissimopoulos 1ad7d9935f doc: add KeibiDrop to known file systems 2026-06-13 14:59:27 +03:00
yeonsh 82f59837f6 sys: fix FileRenameResource self-deadlock between notify session and FspVolumeNotifyWork
Under heavy concurrent rename + change-notification load a volume can
deadlock permanently: all renames (exclusive) and opens (shared) on the
volume block, freezing the mount.

FspFileSystemNotifyBegin (FspVolumeNotifyLock) acquires the per-volume
FileRenameResource shared via an owner pointer (&VolumeNotifyCount) and
holds it for the whole Begin/End session. If a rename queues as an
exclusive waiter mid-session, the asynchronous FspVolumeNotifyWork then
re-acquires the same resource shared with ExAcquireResourceSharedLite.
Due to ERESOURCE writer-priority that shared acquire blocks behind the
queued exclusive waiter (the worker thread is not the owner -- the owner
is the &VolumeNotifyCount pointer). But that work item is the one that
must process FspFileSystemNotifyEnd to drop VolumeNotifyCount to 0 and
release the session, so it can never run: the session lock is never
released and the rename waits forever, while VolumeNotifyCount runs away
as Begin keeps incrementing it.

Acquire the rename resource in FspVolumeNotifyWork with
ExAcquireSharedStarveExclusive instead. The enclosing Begin/End session
already holds the resource shared and already defers renames until End,
so granting this redundant shared acquire ahead of the queued exclusive
waiter preserves name-stability semantics while breaking the deadlock. A
real exclusive holder still blocks the starve-exclusive acquire, so
correctness is unchanged.
2026-06-05 22:48:47 +09:00
Bill Zissimopoulos ff9e38c82d doc: add 9p-winfsp to known file systems 2026-05-31 21:34:09 +03:00
Bill Zissimopoulos 608e16761e tst: passthrough, passthrough-cpp: fix #662 2026-05-18 12:22:22 +03:00
10 changed files with 178 additions and 4 deletions
+17
View File
@@ -1,6 +1,23 @@
# Changelog
## v2.2B2 (2026 Beta2)
- [FIX] Fixes vulnerability CVE-2026-3006 discovered by Tay Kiat Loong (GitHub: @Owl4444).
- [FIX] Fixes vulnerability CVE-2026-7162 discovered by Tay Kiat Loong (GitHub: @Owl4444) and uhg (GitHub: @UltimateHG).
- [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] The WinFsp Network Provider provides improved shell support for network file systems not managed by the Launcher. See commit f021496.
- [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.2B1 (2026 Beta1)
- [FIX] Fixes vulnerability CVE-2026-3006 discovered by Tay Kiat Loong.
+2
View File
@@ -68,12 +68,14 @@ CONTRIBUTOR LIST
|John Oberschelp |john at oberschelp.net
|John Tyner |jtyner at gmail.com
|Konstantinos Karakostas |noiredev at protonmail.com
|Max Isakov |max at resilio.com
|Naoki Ikeguchi |me at s6n.jp
|Paweł Wegner (Google LLC, https://google.com) |lemourin at google.com
|Pedro Frejo (Arpa System, https://arpasystem.com) |pedro.frejo at arpasystem.com
|Ronny Chan |ronny at ronnychan.ca
|Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com
|Santiago Ganis |sganis at gmail.com
|Seunghoon Yeon (Bdrive Inc, https://www.bdrive.com) |ysh at bdrive.com
|Thomas Gibson-Robinson |tom at cocotec.io
|Tobias Urlaub |saibotu at outlook.de
|Victor Gao |victgm at outlook.com
+1 -1
View File
@@ -20,7 +20,7 @@
<MyCanonicalVersion>2.2</MyCanonicalVersion>
<MyProductVersion>2026 Beta1</MyProductVersion>
<MyProductVersion>2026 Beta2</MyProductVersion>
<MyProductStage>Beta</MyProductStage>
<MyCrossCert>CrossCert.cer</MyCrossCert>
+2
View File
@@ -4,6 +4,7 @@ This document contains a list of known open-source file systems and file system
== File Systems
- https://github.com/dharmatech/9p-winfsp[9p-winfsp] - Experimental native Windows client for mounting Plan 9 9P exports.
- https://github.com/wesley1975/blobfs-win[blobfs-win] - The native porting of the blobfs on the windows platform, blobfs can help you mount the Azure Blob storage as the local disk driver, no matter it is a Linux system or a Windows system.
- https://github.com/buildbarn/bb-remote-execution[buildbarn] - A bazel-compatible remote execution service that uses WinFSP to provide a virtual directory for performing builds
- https://github.com/cryptomator/cryptomator[Cryptomator] - Multi-platform transparent client-side encryption of your files in the cloud
@@ -13,6 +14,7 @@ This document contains a list of known open-source file systems and file system
- https://github.com/sganis/golddrive[golddrive] - Windows ssh network drive
- https://github.com/winfsp/hubfs[hubfs] - File system for GitHub
- https://github.com/juicedata/juicefs[JuiceFS] - a distributed POSIX file system built on top of Redis and S3
- https://github.com/KeibiSoft/KeibiDrop[KeibiDrop] - End-to-end encrypted peer-to-peer filesystem with on-demand file streaming
- https://github.com/FrKaram/KS2.Drive[KS2.Drive] - Mount a webDAV/AOS server as a local drive
- https://github.com/winfsp/nfs-win[nfs-win] - NFS for Windows
- https://github.com/winfsp/objfs[objfs] - Object Storage File System
+2
View File
@@ -147,6 +147,8 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
#define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */
#define FSP_FSCTL_NOTIFY_INFO_SIZEMAX (0x7fffffffU)
/* marshalling */
#pragma warning(push)
#pragma warning(disable:4200 4201) /* zero-sized array in struct/union; nameless struct/union */
+18
View File
@@ -1363,6 +1363,24 @@ BOOLEAN FspFsvolDeviceFileRenameTryAcquireExclusive(PDEVICE_OBJECT DeviceObject)
return ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->FileRenameResource, FALSE);
}
static inline
VOID FspFsvolDeviceFileRenameAcquireSharedStarveExclusive(PDEVICE_OBJECT DeviceObject)
{
/*
* Acquire the file rename resource shared, but starve (ignore) any QUEUED
* exclusive waiter. Used by FspVolumeNotifyWork: a notify session opened by
* FspFileSystemNotifyBegin already holds this resource shared (via owner
* pointer) and intentionally defers renames until FspFileSystemNotifyEnd. A
* plain ExAcquireResourceSharedLite here would honor a concurrently queued
* exclusive rename waiter and block -- but the very work item that blocks is
* the one that must run FspFileSystemNotifyEnd processing to release the
* session and let that rename proceed, so the two self-deadlock. Starving the
* queued exclusive waiter is safe: the rename stays blocked behind the shared
* holders either way, so name stability across the notify is preserved.
*/
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
ExAcquireSharedStarveExclusive(&FsvolDeviceExtension->FileRenameResource, TRUE);
}
static inline
VOID FspFsvolDeviceFileRenameSetOwner(PDEVICE_OBJECT DeviceObject, PVOID Owner)
{
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
+12 -1
View File
@@ -1389,6 +1389,9 @@ NTSTATUS FspVolumeNotify(
if (0 == InputBufferLength)
return FspVolumeNotifyLock(FsvolDeviceObject);
if (FSP_FSCTL_NOTIFY_INFO_SIZEMAX < InputBufferLength)
return STATUS_INVALID_PARAMETER;
if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED;
@@ -1499,7 +1502,15 @@ static VOID FspVolumeNotifyWork(PVOID NotifyWorkItem0)
BOOLEAN Unlock = FALSE;
NTSTATUS Result;
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
/*
* Starve queued exclusive (rename) waiters here to avoid a self-deadlock:
* the enclosing FspFileSystemNotifyBegin/End session already holds this
* resource shared, and a rename that queues exclusive mid-session would
* otherwise block this work item -- the same work item that must release
* the session (FspVolumeNotifyLock count) and unblock that rename. See
* FspFsvolDeviceFileRenameAcquireSharedStarveExclusive.
*/
FspFsvolDeviceFileRenameAcquireSharedStarveExclusive(FsvolDeviceObject);
/* iterate over notify information and invalidate/notify each file */
for (; (PUINT8)NotifyInfo + sizeof(NotifyInfo->Size) <= NotifyInfoEnd;
+1 -1
View File
@@ -191,7 +191,7 @@ Ptfs::~Ptfs()
NTSTATUS Ptfs::SetPath(PWSTR Path)
{
WCHAR FullPath[MAX_PATH];
WCHAR FullPath[FULLPATH_SIZE];
ULONG Length;
HANDLE Handle;
FILETIME CreationTime;
+1 -1
View File
@@ -626,7 +626,7 @@ static VOID PtfsDelete(PTFS *Ptfs);
static NTSTATUS PtfsCreate(PWSTR Path, PWSTR VolumePrefix, PWSTR MountPoint, UINT32 DebugFlags,
PTFS **PPtfs)
{
WCHAR FullPath[MAX_PATH];
WCHAR FullPath[FULLPATH_SIZE];
ULONG Length;
HANDLE Handle;
FILETIME CreationTime;
+122
View File
@@ -27,6 +27,37 @@
#include "winfsp-tests.h"
static
void notify_invalid_dotest(ULONG Flags)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
NTSTATUS Result;
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 1);
ASSERT(STATUS_ACCESS_VIOLATION == Result);
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, FSP_FSCTL_NOTIFY_INFO_SIZEMAX);
ASSERT(STATUS_ACCESS_VIOLATION == Result || STATUS_INSUFFICIENT_RESOURCES == Result);
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, FSP_FSCTL_NOTIFY_INFO_SIZEMAX + 1);
ASSERT(STATUS_INVALID_PARAMETER == Result);
Result = FspFsctlNotify(FileSystem->VolumeHandle, 0, 0xffffffffU);
ASSERT(STATUS_INVALID_PARAMETER == Result);
memfs_stop(memfs);
}
static
void notify_invalid_test(void)
{
if (WinFspDiskTests)
notify_invalid_dotest(MemfsDisk);
if (WinFspNetTests)
notify_invalid_dotest(MemfsNet);
}
static
void notify_abandon_dotest(ULONG Flags)
{
@@ -474,11 +505,101 @@ void notify_dirnotify_test(void)
}
}
struct notify_rename_race_params
{
WCHAR Src[MAX_PATH];
WCHAR Dst[MAX_PATH];
HANDLE StartEvent;
};
static
unsigned __stdcall notify_rename_race_dotest_thread(void *Params0)
{
struct notify_rename_race_params *Params = Params0;
WaitForSingleObject(Params->StartEvent, INFINITE);
BOOL Success = MoveFileExW(Params->Src, Params->Dst, 0);
return Success ? 0 : GetLastError();
}
static
void notify_rename_race_dotest(ULONG Flags, PWSTR Prefix)
{
void *memfs = memfs_start(Flags);
FSP_FILE_SYSTEM *FileSystem = MemfsFileSystem(memfs);
union
{
FSP_FSCTL_NOTIFY_INFO V;
UINT8 B[sizeof(FSP_FSCTL_NOTIFY_INFO) + 2 * sizeof(WCHAR)];
} NotifyInfo;
struct notify_rename_race_params Params;
HANDLE Thread;
DWORD ExitCode;
NTSTATUS Result;
HANDLE Handle;
PWSTR FileName;
StringCbPrintfW(Params.Src, sizeof Params.Src, L"%s%s\\file0",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
StringCbPrintfW(Params.Dst, sizeof Params.Dst, L"%s%s\\file0.new",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Handle = CreateFileW(Params.Src,
GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
CloseHandle(Handle);
FileName = L"\\";
NotifyInfo.V.Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + wcslen(FileName) * sizeof(WCHAR));
NotifyInfo.V.Filter = FILE_NOTIFY_CHANGE_LAST_WRITE;
NotifyInfo.V.Action = FILE_ACTION_MODIFIED;
memcpy(NotifyInfo.V.FileNameBuf, FileName, NotifyInfo.V.Size - sizeof(FSP_FSCTL_NOTIFY_INFO));
Params.StartEvent = CreateEventW(0, TRUE, FALSE, 0);
ASSERT(0 != Params.StartEvent);
Thread = (HANDLE)_beginthreadex(0, 0, notify_rename_race_dotest_thread, &Params, 0, 0);
ASSERT(0 != Thread);
Result = FspFileSystemNotifyBegin(FileSystem, 1000);
ASSERT(STATUS_SUCCESS == Result);
SetEvent(Params.StartEvent);
Sleep(1000); /* wait for rename IRP to enter the kernel and block */
Result = FspFileSystemNotify(FileSystem, &NotifyInfo.V, NotifyInfo.V.Size);
ASSERT(STATUS_SUCCESS == Result);
Result = FspFileSystemNotifyEnd(FileSystem);
ASSERT(STATUS_SUCCESS == Result);
WaitForSingleObject(Thread, INFINITE);
GetExitCodeThread(Thread, &ExitCode);
CloseHandle(Thread);
ASSERT(STATUS_SUCCESS == ExitCode);
CloseHandle(Params.StartEvent);
memfs_stop(memfs);
}
static
void notify_rename_race_test(void)
{
if (WinFspDiskTests)
notify_rename_race_dotest(MemfsDisk, 0);
if (WinFspNetTests)
notify_rename_race_dotest(MemfsNet, L"\\\\memfs\\share");
}
void notify_tests(void)
{
if (OptExternal || OptNotify)
return;
TEST(notify_invalid_test);
TEST(notify_abandon_test);
TEST(notify_abandon_rename_test);
/* OBSOLETE: it is now possible to have multiple outstanding NotifyBegin() calls. */
@@ -489,4 +610,5 @@ void notify_tests(void)
TEST(notify_change_test);
TEST(notify_open_change_test);
TEST(notify_dirnotify_test);
TEST(notify_rename_race_test);
}