- May 7, 2013
- 10,400
There is a few different variations of this bugcheck, although, it is always related to either a corrupt timer object or an invalid DPC. You’ll need to examine the parameters individually to ascertain why that is the case. Commonly, it’ll be due to a driver incorrectly calling a function which implements a timer or DPC. Again, this is going to be a very short post, I just wanted to shed some light on this rather unknown bugcheck.
In our example, we can see that we have an invalid DPC object. The address of the said object is stored in the second parameter and the processor which the DPC object was queued to can be found in the third parameter. Notice how the processor index number is far greater than the number of available processors? This is why the system crashed, the DPC object was queued to a DPC queue on a processor which doesn’t exist. If we dump the DPC object itself, then we can see such information:
The Number field of the KDPC structure refers to the processor index which the DPC will be queued to. It is actually used by the KeSetTargetProcessorDpcEx function, which uses it to determine wherever to switch to a different CPU based upon the Number field of the KDPC object. If the value of the said field is equal to or greater than 0x500, then 0x500 is subtracted from the Number field and then used to index into an array called nt!KiProcessorBlock. This array contains all the current KPRCB structures for each logical processor in the system. Once the appropriate KPRCB structure has been found, then the system will queue the DPC to that processor’s DPC queue. To illustrate this point further, let’s examine a valid DPC object.
If we subtract 0x500 from 0x509, then we get 0x9, which matches the Number (processor index) of a valid logical processor in the system.
And if we dump the processor control block array, we’ll see that the corresponding PRCB is at position 9 of the array. Remember arrays begin at an index of 0.
And the DPC queue for the processor shows the same DPC:
Going back to the DPC from the bugcheck, the DeferredRoutine field provides some indication of what might have queued the DPC object. afd.sys is related to WinSock, and therefore it would advisable to check for any networking drivers or any security software.
As a closing note, looking at the call stack, we can clearly see the DPC object was being queued. Shortly afterwards, the system crashed with the bugcheck which was shown to us.
References:
KPRCB (amd64)
KDPC
Reversing DPC: KeInsertQueueDpc · Low Level Pleasure
Rich (BB code):
TIMER_OR_DPC_INVALID (c7)
Kernel timer or DPC used incorrectly.
Arguments:
Arg1: 0000000000000003, Incorrect processor number for DPC.
Arg2: ffffe0012080c450, Address of the DPC object.
Arg3: 0000000000001000, Processor number.
Arg4: 0000000000000004, Number of processors in the system.
In our example, we can see that we have an invalid DPC object. The address of the said object is stored in the second parameter and the processor which the DPC object was queued to can be found in the third parameter. Notice how the processor index number is far greater than the number of available processors? This is why the system crashed, the DPC object was queued to a DPC queue on a processor which doesn’t exist. If we dump the DPC object itself, then we can see such information:
Rich (BB code):
0: kd> dt _KDPC ffffe0012080c450
nt!_KDPC
+0x000 TargetInfoAsUlong : 0x10000113
+0x000 Type : 0x13 ''
+0x001 Importance : 0x1 ''
+0x002 Number : 0x1000
+0x008 DpcListEntry : _SINGLE_LIST_ENTRY
+0x010 ProcessorHistory : 0
+0x018 DeferredRoutine : 0xfffff801`b7f26f30 void afd!AfdTimeoutPoll+0
+0x020 DeferredContext : 0xffffe001`2080c430 Void
+0x028 SystemArgument1 : 0x00000000`006f0053 Void
+0x030 SystemArgument2 : 0x00650072`00000000 Void
+0x038 DpcData : (null)
The Number field of the KDPC structure refers to the processor index which the DPC will be queued to. It is actually used by the KeSetTargetProcessorDpcEx function, which uses it to determine wherever to switch to a different CPU based upon the Number field of the KDPC object. If the value of the said field is equal to or greater than 0x500, then 0x500 is subtracted from the Number field and then used to index into an array called nt!KiProcessorBlock. This array contains all the current KPRCB structures for each logical processor in the system. Once the appropriate KPRCB structure has been found, then the system will queue the DPC to that processor’s DPC queue. To illustrate this point further, let’s examine a valid DPC object.
Rich (BB code):
0: kd> dt _KDPC 0xffffb60f24d0f700
nt!_KDPC
+0x000 TargetInfoAsUlong : 0x5090313
+0x000 Type : 0x13 ''
+0x001 Importance : 0x3 ''
+0x002 Number : 0x509
+0x008 DpcListEntry : _SINGLE_LIST_ENTRY
+0x010 ProcessorHistory : 0x200
+0x018 DeferredRoutine : 0xfffff800`38605010 void nt!PopExecuteProcessorCallback+0
+0x020 DeferredContext : 0xffffb60f`24d0f6d0 Void
+0x028 SystemArgument1 : (null)
+0x030 SystemArgument2 : (null)
+0x038 DpcData : 0x00000000`00000001 Void
If we subtract 0x500 from 0x509, then we get 0x9, which matches the Number (processor index) of a valid logical processor in the system.
Rich (BB code):
9: kd> dt _KPRCB -y Number ffffa500abcc0180
nt!_KPRCB
+0x024 Number : 9
And if we dump the processor control block array, we’ll see that the corresponding PRCB is at position 9 of the array. Remember arrays begin at an index of 0.
Rich (BB code):
9: kd> dq nt!KiProcessorBlock
fffff800`390fdc80 fffff800`33c8b180 ffffa500`ab4e0180
fffff800`390fdc90 ffffa500`ab5c0180 ffffa500`ab6c0180
fffff800`390fdca0 ffffa500`ab781180 ffffa500`ab8c0180
fffff800`390fdcb0 ffffa500`ab9c0180 ffffa500`abac0180
fffff800`390fdcc0 ffffa500`abbc0180 ffffa500`abcc0180
fffff800`390fdcd0 ffffa500`abdc0180 ffffa500`abec0180
fffff800`390fdce0 00000000`00000000 00000000`00000000
fffff800`390fdcf0 00000000`00000000 00000000`00000000
And the DPC queue for the processor shows the same DPC:
Rich (BB code):
9: kd> !dpcs
CPU Type KDPC Function
0: Normal : 0xffffe384643bbd60 0xfffff8003a5b3850 Wdf01000!FxInterrupt::_InterruptDpcThunk
0: Normal : 0xffffe384641020e0 0xfffff8004d202a64 nvlddmkm
0: Normal : 0xffffe38462fa7bc0 0xfffff8004ca9c2e8 nvlddmkm
0: Normal : 0xffffe38465f3ed28 0xfffff8004c402be0 HDAudBus!HdaController::CodecDpc
0: Normal : 0xffffe3846421a520 0xfffff8003a5b3850 Wdf01000!FxInterrupt::_InterruptDpcThunk
0: Normal : 0xffffe3845ed84050 0xfffff8003b383980 ndis!ndisPeriodicReceivesTimer
0: Normal : 0xfffff80033c93290 0xfffff8003866e680 nt!PpmPerfAction
0: Normal : 0xffffe3845e57e1e0 0xfffff8003ad92270 stornvme!NVMeCompletionDpcRoutine
0: Normal : 0xffffb60f2031f700 0xfffff80038605010 nt!PopExecuteProcessorCallback
0: Normal : 0xffffe3845eec20b8 0xfffff8003b45eaa0 tcpip!TcpPeriodicTimeoutHandler
0: Normal : 0xffffb60f28c77700 0xfffff80038605010 nt!PopExecuteProcessorCallback
0: Normal : 0xffffb60f28d07700 0xfffff80038605010 nt!PopExecuteProcessorCallback
9: Normal : 0xffffb60f24d0f700 0xfffff80038605010 nt!PopExecuteProcessorCallback
9: Normal : 0xffffb60f22702700 0xfffff80038605010 nt!PopExecuteProcessorCallback
9: Normal : 0xffffb60f2799f700 0xfffff80038605010 nt!PopExecuteProcessorCallback
9: Normal : 0xffffa500abcc8290 0xfffff8003866e680 nt!PpmPerfAction
9: Normal : 0xffffa500abcc8868 0xfffff80038713790 nt!KiEntropyDpcRoutine
9: Normal : 0xffffe3845eec2f10 0xfffff8003b45eaa0 tcpip!TcpPeriodicTimeoutHandler
Going back to the DPC from the bugcheck, the DeferredRoutine field provides some indication of what might have queued the DPC object. afd.sys is related to WinSock, and therefore it would advisable to check for any networking drivers or any security software.
Rich (BB code):
0: kd> !stack -p
Call Stack : 5 frames
## Stack-Pointer Return-Address Call-Site
00 fffff8000d8947e8 fffff8000b7dc759 nt!KeBugCheckEx+0
Parameter[0] = 00000000000000c7
Parameter[1] = 0000000000000003
Parameter[2] = ffffe0012080c450
Parameter[3] = 0000000000001000
01 fffff8000d8947f0 fffff8000b6cb19f nt!KiInsertQueueDpc+13e909 (perf) << Crash here!
Parameter[0] = ffffe0012080c450
Parameter[1] = 000000004703fb1f
Parameter[2] = 0000000001d15f65
Parameter[3] = ffffe0012080c490
02 fffff8000d894870 fffff8000b6cb7b9 nt!KiTimerWaitTest+32f
Parameter[0] = fffff8000b99f180
Parameter[1] = ffffe0012080c490
Parameter[2] = fffff8000d894a18
Parameter[3] = (unknown)
03 fffff8000d894910 fffff8000b7c6d3a nt!KiRetireDpcList+399
Parameter[0] = fffff8000b99f180
Parameter[1] = (unknown)
Parameter[2] = (unknown)
Parameter[3] = (unknown)
04 fffff8000d894b60 0000000000000000 nt!KiIdleLoop+5a
Parameter[0] = (unknown)
Parameter[1] = (unknown)
Parameter[2] = (unknown)
Parameter[3] = (unknown)
As a closing note, looking at the call stack, we can clearly see the DPC object was being queued. Shortly afterwards, the system crashed with the bugcheck which was shown to us.
References:
KPRCB (amd64)
KDPC
Reversing DPC: KeInsertQueueDpc · Low Level Pleasure