sys: FspMainFileClose: fix issue #680

Instead of closing the main file handle in the dispatcher 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.
This commit is contained in:
Bill Zissimopoulos
2026-07-28 15:36:48 +03:00
parent 97e6d92b5b
commit 5b53285545
3 changed files with 86 additions and 12 deletions
+6 -2
View File
@@ -698,14 +698,18 @@ NTSTATUS FspOplockFsctrl(
/* utility: synchronous work queue */ /* utility: synchronous work queue */
typedef struct typedef struct
{ {
KEVENT Event; LONG RefCount;
PWORKER_THREAD_ROUTINE Routine; PWORKER_THREAD_ROUTINE Routine;
PVOID Context; PVOID Context;
KEVENT Event;
WORK_QUEUE_ITEM WorkQueueItem; WORK_QUEUE_ITEM WorkQueueItem;
} FSP_SYNCHRONOUS_WORK_ITEM; } FSP_SYNCHRONOUS_WORK_ITEM;
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem, VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
PWORKER_THREAD_ROUTINE Routine, PVOID Context); 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 */ /* utility: delayed work queue */
typedef struct typedef struct
+33 -3
View File
@@ -121,6 +121,7 @@ NTSTATUS FspMainFileOpen(
NTSTATUS FspMainFileClose( NTSTATUS FspMainFileClose(
HANDLE MainFileHandle, HANDLE MainFileHandle,
PFILE_OBJECT MainFileObject); PFILE_OBJECT MainFileObject);
static WORKER_THREAD_ROUTINE FspMainFileCloseSynchronousWork;
VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp); VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp);
VOID FspFileNodeOplockComplete(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, FspFileDescSetDirectoryMarker)
#pragma alloc_text(PAGE, FspMainFileOpen) #pragma alloc_text(PAGE, FspMainFileOpen)
#pragma alloc_text(PAGE, FspMainFileClose) #pragma alloc_text(PAGE, FspMainFileClose)
#pragma alloc_text(PAGE, FspMainFileCloseSynchronousWork)
#pragma alloc_text(PAGE, FspFileNodeOplockPrepare) #pragma alloc_text(PAGE, FspFileNodeOplockPrepare)
#pragma alloc_text(PAGE, FspFileNodeOplockComplete) #pragma alloc_text(PAGE, FspFileNodeOplockComplete)
#endif #endif
@@ -2803,14 +2805,42 @@ NTSTATUS FspMainFileClose(
if (0 != MainFileHandle) if (0 != MainFileHandle)
{ {
Result = ObCloseHandle(MainFileHandle, KernelMode); FSP_SYNCHRONOUS_WORK_ITEM *WorkItem;
if (!NT_SUCCESS(Result))
DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result)); 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; 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) VOID FspFileNodeOplockPrepare(PVOID Context, PIRP Irp)
{ {
PAGED_CODE(); PAGED_CODE();
+47 -7
View File
@@ -115,9 +115,12 @@ NTSTATUS FspOplockFsctrl(
POPLOCK Oplock, POPLOCK Oplock,
PIRP Irp, PIRP Irp,
ULONG OpenCount); ULONG OpenCount);
FSP_SYNCHRONOUS_WORK_ITEM *FspAllocateSynchronousWorkItem(
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem, VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
PWORKER_THREAD_ROUTINE Routine, PVOID Context); 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; static WORKER_THREAD_ROUTINE FspExecuteSynchronousWorkItemRoutine;
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
PWORKER_THREAD_ROUTINE Routine, PVOID Context); PWORKER_THREAD_ROUTINE Routine, PVOID Context);
@@ -167,6 +170,7 @@ LONG FspCompareUnicodeString(
#pragma alloc_text(PAGE, FspCheckOplock) #pragma alloc_text(PAGE, FspCheckOplock)
#pragma alloc_text(PAGE, FspCheckOplockEx) #pragma alloc_text(PAGE, FspCheckOplockEx)
#pragma alloc_text(PAGE, FspOplockFsctrl) #pragma alloc_text(PAGE, FspOplockFsctrl)
#pragma alloc_text(PAGE, FspAllocateSynchronousWorkItem)
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem) #pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem) #pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine) #pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
@@ -1123,27 +1127,56 @@ NTSTATUS FspOplockFsctrl(
return Result; 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, VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
PWORKER_THREAD_ROUTINE Routine, PVOID Context) PWORKER_THREAD_ROUTINE Routine, PVOID Context)
{ {
PAGED_CODE(); PAGED_CODE();
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE); SynchronousWorkItem->RefCount = 0; /* initialize as non-refcounted */
SynchronousWorkItem->Routine = Routine; SynchronousWorkItem->Routine = Routine;
SynchronousWorkItem->Context = Context; SynchronousWorkItem->Context = Context;
KeInitializeEvent(&SynchronousWorkItem->Event, NotificationEvent, FALSE);
ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem, ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem,
FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem); FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem);
} }
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem) NTSTATUS FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
BOOLEAN Alertable)
{ {
PAGED_CODE(); PAGED_CODE();
ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue);
NTSTATUS Result; 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) static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
@@ -1151,8 +1184,15 @@ static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context)
PAGED_CODE(); PAGED_CODE();
FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context; FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem = Context;
SynchronousWorkItem->Routine(SynchronousWorkItem->Context); SynchronousWorkItem->Routine(SynchronousWorkItem->Context);
KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE); KeSetEvent(&SynchronousWorkItem->Event, 1, FALSE);
if (0 < SynchronousWorkItem->RefCount)
{
if (0 == InterlockedDecrement(&SynchronousWorkItem->RefCount))
FspFree(SynchronousWorkItem);
}
} }
VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,