DPC_WATCHDOG_VIOLATION BSOD с ожиданием спайлока

#networking #windbg #kernel-module #wdk

Вопрос:

У меня есть драйвер фильтра NDIS, работающий в Windows 10 (СТРОКА BUILD_VERSION_STRING: 18362.1.amd64fre.19h1_release.190318-1202). С помощью одного из тестовых сценариев на определенном тестовом компьютере он завершается ошибкой DPC_WATCHDOG_VIOLATION BSOD. Стек вызовов выглядит следующим образом:

 nt!KeBugCheckEx
nt!KeAccumulateTicks 0x1815bd
nt!KeClockInterruptNotify 0xc07
hal!HalpTimerClockIpiRoutine 0x21
nt!KiCallInterruptServiceRoutine 0xa5
nt!KiInterruptSubDispatchNoLockNoEtw 0xfa
nt!KiInterruptDispatchNoLockNoEtw 0x37
nt!KxWaitForSpinLockAndAcquire 0x33
nt!KeAcquireSpinLockAtDpcLevel 0x5b
MYDRV!FilterReceiveNetBufferLists 0x1c8 [c:MYDRV_SRCmy_filter.cpp @ 1768]
ndis!ndisCallReceiveHandler 0x60
ndis!ndisInvokeNextReceiveHandler 0x206cf
ndis!NdisMIndicateReceiveNetBufferLists 0x104
e1i65x64!RECEIVE::RxIndicateNBLs 0x12f
e1i65x64!RECEIVE::RxProcessInterrupts 0x20a
e1i65x64!INTERRUPT::MsgIntDpcTxRxProcessing 0x124
e1i65x64!INTERRUPT::MsgIntMessageInterruptDPC 0x1ff
e1i65x64!INTERRUPT::MiniportMessageInterruptDPC 0x28
ndis!ndisInterruptDpc 0x19c
nt!KiExecuteAllDpcs 0x30a
nt!KiRetireDpcList 0x1ef
nt!KxRetireDpcList 0x5
nt!KiDispatchInterruptContinue
nt!KiDpcInterrupt 0x2ee
nt!RtlpHpSegPageRangeShrink 0x2d5
nt!ExFreeHeapPool 0x751
nt!ExFreePool 0x9
MYDRV!StartReqCancel 0x16f [c:MYDRV_SRCmy_device.cpp @ 1420] 
nt!IoCancelIrp 0x71
nt!IopCancelIrpsInCurrentThreadList 0x104
 

MYDRV!StartReqCancel-это процедура отмены IRP пользователя.
Выполнение застряло в списках FilterReceiveNetBufferLists здесь:

 NdisDprAcquireSpinLock(amp;pFilter->startIrpLock);
 

В MYDRV!Процедура отмены StartReqCancel эта блокировка заблокирована для освобождения связанных ресурсов, таких как:

     // Clear Cancel routine
    IoSetCancelRoutine(pIrp, NULL);
    // Release the cancel spinlock
    IoReleaseCancelSpinLock(pIrp->CancelIrql);

    NdisDprAcquireSpinLock(amp;pFilter->startIrpLock);

    // Clear capture data
    //...
    for (int i=0; i<pFilter->dataN;   i )
       ExFreePool(pFilter->pCaptData[i]); //non-paged data!
    //...

    NdisDprReleaseSpinLock(amp;pFilter->startIrpLock);
    
    // Complete the request
    pIrp->IoStatus.Status = STATUS_CANCELLED;
    pIrp->IoStatus.Information = 0;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);//CAPTURE_START_IRP
 

Похоже, что во время вызова ExFreePool драйвер HW получает прерывание для входящих пакетов и в конечном итоге вызывает списки FilterReceiveNetBufferLists моего драйвера фильтра, где он пытается получить блокировку pFilter->startIrpLock (на уровне DISPATCH_LEVEL), которая была заблокирована MYDRV!StartReqCancel.
Но похоже, что StartReqCancel никогда не возвращается из ExFreePool. Значение pFilter->Данные не слишком большие (>

У вас есть какие-нибудь идеи, почему это может быть?

Ответ №1:

Только что нашли причину этой странной аварии, благодаря Верификатору водителя:

 //....

// Release the cancel spinlock
// Here we have  IRQL = DISPATCH_LEVEL here
IoReleaseCancelSpinLock(pIrp->CancelIrql);
// Now we have  IRQL < DISPATCH_LEVEL !!!

NdisDprAcquireSpinLock(amp;pFilter->startIrpLock); // !!! No real spinlock acquisition here!!!

// NON LOCKED code here.
// ....
// NdisDprReleaseSpinLock(amp;pFilter->startIrpLock); // Nothing unlocked here