From 25ce03a30256f3023cb1a038f055adc362b3d1d9 Mon Sep 17 00:00:00 2001 From: Torin Date: Sun, 22 Mar 2026 20:10:09 +0200 Subject: [PATCH] fix(heap): eliminate TOCTOU gap in _ExFreePoolWithTracking Hold TrackingLock across both double-free check and UntrackAllocation to prevent another thread from modifying state between the two operations. CRITICAL_SECTION recursive acquisition allows UntrackAllocation to safely re-enter the lock. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/KernelHeap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/KernelHeap.c b/src/KernelHeap.c index 71c614d..a9b92cc 100644 --- a/src/KernelHeap.c +++ b/src/KernelHeap.c @@ -352,9 +352,11 @@ void _ExFreePoolWithTracking(PVOID pointer, const char* FileName, int LineNumber HEAP_VERBOSE("_ExFreePoolWithTracking: State info - heap handle: %p, TrackFreedMemory: %d", state->HeapHandle, state->TrackFreedMemory); - if (state->TrackFreedMemory) { - EnterCriticalSection(&state->TrackingLock); + /* Hold TrackingLock across double-free check AND untrack to prevent TOCTOU. + * CRITICAL_SECTION is recursive, so UntrackAllocation can re-enter safely. */ + EnterCriticalSection(&state->TrackingLock); + if (state->TrackFreedMemory) { PLIST_ENTRY current = state->MemoryAllocations.Flink; while (current != &state->MemoryAllocations) { PMEMORY_TRACKING_ENTRY entry = CONTAINING_RECORD(current, MEMORY_TRACKING_ENTRY, ListEntry); @@ -375,13 +377,13 @@ void _ExFreePoolWithTracking(PVOID pointer, const char* FileName, int LineNumber } HEAP_TRACE("_ExFreePoolWithTracking: No double-free detected for %p", pointer); } - - LeaveCriticalSection(&state->TrackingLock); } HEAP_TRACE("_ExFreePoolWithTracking: Calling UntrackAllocation for %p", pointer); found = UntrackAllocation(pointer, FileName, LineNumber); + LeaveCriticalSection(&state->TrackingLock); + HEAP_VERBOSE("_ExFreePoolWithTracking: UntrackAllocation returned %d for %p", found, pointer); if (!found && !state->SuppressErrors) {