1
0

Crash fix

This commit is contained in:
2026-07-03 19:27:44 +02:00
parent 5556ecd838
commit 861813776b
+17 -2
View File
@@ -429,14 +429,29 @@ Return Value:
if (stack->MajorFunction == IRP_MJ_PNP)
{
ntStatus = DMF_BusFilter_DispatchPnp(DeviceObject, Irp, stack->MinorFunction);
// Capture the minor code BEFORE dispatching. For IRP_MN_REMOVE_DEVICE,
// DispatchPnp completes the IRP (invalidating `stack`) and deletes the
// device object (invalidating `extension`). Re-reading stack->MinorFunction
// afterwards is a use-after-free that can steer us into IoReleaseRemoveLock
// on the freed extension.
//
const UCHAR minorFunction = stack->MinorFunction;
ntStatus = DMF_BusFilter_DispatchPnp(DeviceObject, Irp, minorFunction);
// For REMOVE_DEVICE, IoReleaseRemoveLockAndWait inside Relations_RemoveDevice
// has already released the lock (and waited for all other holders). A second
// release here would corrupt the lock count.
//
if (stack->MinorFunction != IRP_MN_REMOVE_DEVICE)
if (minorFunction != IRP_MN_REMOVE_DEVICE)
{
// Safe: this is a non-REMOVE minor, so no teardown path ran, and the
// IoAcquireRemoveLock reference taken at function entry is still
// outstanding here. That outstanding reference blocks any concurrent
// IoReleaseRemoveLockAndWait (in Relations_RemoveDevice / DeviceCleanup)
// from completing IoDeleteDevice, so `extension` is guaranteed alive at
// the moment we release. We must not touch `extension` after this call.
//
IoReleaseRemoveLock(&extension->RemoveLock, Irp);
}