mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-06-09 21:22:41 +00:00
Windows: harden work item completion drain before queue cleanup
Decrement ActiveWorkItems only after the completion work item has returned queue resources and released its pool item. EncryptedIoQueueStop now synchronizes with WorkItemLock after the active count drains, ensuring the last work item has stopped touching queue state before the work item pool and buffer pools are freed.
This commit is contained in:
@@ -422,12 +422,6 @@ static VOID CompleteIrpWorkItemRoutine(PDEVICE_OBJECT DeviceObject, PVOID Contex
|
||||
}
|
||||
__finally
|
||||
{
|
||||
// If no active work items remain, signal the event
|
||||
if (InterlockedDecrement(&queue->ActiveWorkItems) == 0)
|
||||
{
|
||||
KeSetEvent(&queue->NoActiveWorkItemsEvent, IO_DISK_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
// Return the work item to the free list
|
||||
KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql);
|
||||
InsertTailList(&queue->FreeWorkItemsList, &workItem->ListEntry);
|
||||
@@ -438,6 +432,19 @@ static VOID CompleteIrpWorkItemRoutine(PDEVICE_OBJECT DeviceObject, PVOID Contex
|
||||
|
||||
// Free the item
|
||||
ReleasePoolBuffer(queue, item);
|
||||
|
||||
// Decrement ActiveWorkItems last: once it reaches zero,
|
||||
// EncryptedIoQueueStop frees the work item pool and buffer pools, so
|
||||
// this routine must not touch queue resources afterwards. The
|
||||
// decrement and signal are done under WorkItemLock, which Stop
|
||||
// re-acquires after draining, guaranteeing this routine has left the
|
||||
// protected region before anything is freed.
|
||||
KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql);
|
||||
if (InterlockedDecrement(&queue->ActiveWorkItems) == 0)
|
||||
{
|
||||
KeSetEvent(&queue->NoActiveWorkItemsEvent, IO_DISK_INCREMENT, FALSE);
|
||||
}
|
||||
KeReleaseSpinLock(&queue->WorkItemLock, oldIrql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,6 +1515,15 @@ NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue)
|
||||
KeResetEvent(&queue->NoActiveWorkItemsEvent);
|
||||
}
|
||||
|
||||
// The last work item drops ActiveWorkItems to zero while holding
|
||||
// WorkItemLock; acquiring it here ensures that work item has stopped
|
||||
// touching queue resources before they are freed below.
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
KeAcquireSpinLock(&queue->WorkItemLock, &oldIrql);
|
||||
KeReleaseSpinLock(&queue->WorkItemLock, oldIrql);
|
||||
}
|
||||
|
||||
// Free pre-allocated work items
|
||||
for (ULONG i = 0; i < queue->MaxWorkItems; ++i)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user