Windows蓝屏分析
+ -

串口过滤驱动调试过程蓝屏NO_MORE_IRP_STACK_LOCATIONS(35)问题分析

2023-06-14 36 0

最近在搞一个串口的过滤驱动程序,在调度过程中报了一个蓝屏问题。

NO_MORE_IRP_STACK_LOCATIONS (35)
A higher level driver has attempted to call a lower level driver through
the IoCallDriver() interface, but there are no more stack locations in the
packet, hence, the lower level driver would not be able to access its
parameters, as there are no parameters for it.  This is a disasterous
situation, since the higher level driver "thinks" it has filled in the
parameters for the lower level driver (something it MUST do before it calls
it), but since there is no stack location for the latter driver, the former
has written off of the end of the packet.  This means that some other memory
has probably been trashed at this point.
Arguments:
Arg1: ffffba86c0b4f4c0, Address of the IRP
Arg2: 0000000000000000
Arg3: 0000000000000000
Arg4: 0000000000000000

这里显示IO_STACK_LOCATION已经消耗完了,没有可用的了。
我们知道,IO_STACK_LOCATION的数量与驱动的枚层级数量一般一致,每一层设备IPR都会分配一个有效的IO_STACK_LOCATION,但是在实际过程中,某些驱动栈可以不使用,而使用IoSkipCurrentIrpStackLocation来跳过当前IO_STACK_LOCATION。

FORCEINLINE
VOID
IoSkipCurrentIrpStackLocation (
    _Inout_ PIRP Irp
)
{
    NT_ASSERT(Irp->CurrentLocation <= Irp->StackCount);
    Irp->CurrentLocation++;
    Irp->Tail.Overlay.CurrentStackLocation++;
}

而IoSkipCurrentIrpStackLocation的功能仅仅是将当前的CurrentLocation+1,即指针栈加1,所以对于最顶层的驱动,其指针在最顶部,而最低层的驱动,其指针在最顶层。
IoCallDriver会自动将rp->CurrentLocation-1,从而实现IO_STACK_LOCATION的平衡。

回到正题,我们当前的是栈已经消耗完,故到底了,所以肯定就是我们的驱动栈平衡有问题,而这种不正确的平衡会导致死循环调用。我们看一下蓝屏时的内核堆栈:

1: kd> k
 # Child-SP          RetAddr           Call Site
00 ffff9000`14cac928 fffff801`9f25d5ca nt!DbgBreakPointWithStatus
01 ffff9000`14cac930 fffff801`9f25cfad nt!KiBugCheckDebugBreak+0x12
02 ffff9000`14cac990 fffff801`9f1e7c64 nt!KeBugCheck2+0x8a5
03 ffff9000`14cad0a0 fffff801`9f200326 nt!KeBugCheckEx+0x104
04 ffff9000`14cad0e0 fffff80d`6d5c1cbb nt!IofCallDriver+0xfaef6
05 ffff9000`14cad120 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
06 ffff9000`14cad180 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
07 ffff9000`14cad270 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
08 ffff9000`14cad2d0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
09 ffff9000`14cad3c0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
0a ffff9000`14cad420 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
0b ffff9000`14cad510 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
0c ffff9000`14cad570 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
0d ffff9000`14cad660 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
0e ffff9000`14cad6c0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
0f ffff9000`14cad7b0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
10 ffff9000`14cad810 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
11 ffff9000`14cad900 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
12 ffff9000`14cad960 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
13 ffff9000`14cada50 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
14 ffff9000`14cadab0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
15 ffff9000`14cadba0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
16 ffff9000`14cadc00 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
17 ffff9000`14cadcf0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
18 ffff9000`14cadd50 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
19 ffff9000`14cade40 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
1a ffff9000`14cadea0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
1b ffff9000`14cadf90 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
1c ffff9000`14cadff0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
1d ffff9000`14cae0e0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
1e ffff9000`14cae140 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
1f ffff9000`14cae230 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
20 ffff9000`14cae290 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
21 ffff9000`14cae380 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
22 ffff9000`14cae3e0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
23 ffff9000`14cae4d0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
24 ffff9000`14cae530 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
25 ffff9000`14cae620 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
26 ffff9000`14cae680 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
27 ffff9000`14cae770 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
28 ffff9000`14cae7d0 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
29 ffff9000`14cae8c0 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
2a ffff9000`14cae920 fffff80d`6d5c1cbb ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
2b ffff9000`14caea10 fffff80d`6d5c1360 ComFilter!SynWaitIrp+0x5b [F:\ComFilter\ComFilter\ComFilter.cpp @ 64] 
2c ffff9000`14caea70 fffff801`9f506650 ComFilter!DispatchRoutine+0x360 [F:\ComFilter\ComFilter\ComFilter.cpp @ 160] 
2d ffff9000`14caeb60 fffff801`9f5059ec nt!IopSynchronousServiceTail+0x1a0
2e ffff9000`14caec20 fffff801`9f504c46 nt!IopXxxControlFile+0xd9c
2f ffff9000`14caed60 fffff801`9f1f7703 nt!NtDeviceIoControlFile+0x56
30 ffff9000`14caedd0 00000000`6653223c nt!KiSystemServiceCopyEnd+0x13
31 00000000`0009d5e8 00000000`66531e77 wow64cpu!CpupSyscallStub+0xc
32 00000000`0009d5f0 00000000`664ebf67 wow64cpu!DeviceIoctlFileFault+0x31
33 00000000`0009d6a0 00000000`664e8240 wow64!RunCpuSimulation+0xf307
34 00000000`0009d720 00000000`66541ccb wow64!Wow64KiUserCallbackDispatcher+0x420
35 00000000`0009db20 00007ffc`eae29694 wow64win!whcbfnDWORD+0x34b
36 00000000`0009e520 00000000`6654f5f4 ntdll!KiUserCallbackDispatcherContinue
37 00000000`0009e5a8 00000000`665458e2 wow64win!NtUserMessageCall+0x14
38 00000000`0009e5b0 00000000`66545b7e wow64win!whNT32NtUserMessageCallCB+0x32
39 00000000`0009e600 00000000`664d6e55 wow64win!whNtUserMessageCall+0x11e
3a 00000000`0009e6b0 00000000`66531d07 wow64!Wow64SystemServiceEx+0x155
3b 00000000`0009ef70 00000000`664ebf67 wow64cpu!ServiceNoTurbo+0xb
3c 00000000`0009f020 00000000`664dcb80 wow64!RunCpuSimulation+0xf307
3d 00000000`0009f0a0 00007ffc`eae13031 wow64!Wow64LdrpInitialize+0x120
3e 00000000`0009f350 00007ffc`eae4782a ntdll!LdrpInitializeProcess+0x1551
3f 00000000`0009f750 00007ffc`eadf832e ntdll!_LdrpInitialize+0x4f4a6
40 00000000`0009f7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

可以看到,一直在调用

 NTSTATUS status = SynWaitIrp(device, Irp);

函数内容如下:

NTSTATUS SynWaitIrp(PDEVICE_OBJECT device, PIRP Irp)
{
    KEVENT event;
    KeInitializeEvent(&event, NotificationEvent, FALSE);
    IoCopyCurrentIrpStackLocationToNext(Irp);
    IoSetCompletionRoutine(Irp,
        (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
        (PVOID) & event,
        TRUE,
        TRUE,
        TRUE);

    NTSTATUS status = IoCallDriver(device, Irp);
    if (status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&event,
            Executive,
            KernelMode,
            FALSE,
            NULL);
        status = Irp->IoStatus.Status;
    }

    return status;
}

这里看到,我们使用了错误的参数device导致。
这里的device是当前栈的设备,而IoCallDriver使用的是下一层驱动的设备对象,由于我们错误的参数,导致IoCallDriver本应进入下一层的驱动栈,但实际进的是本层驱动栈,从而导致IoCallDriver死循环,最终导致IO_STACK_LOCATION的内层越界。

0 篇笔记 写笔记

串口过滤驱动调试过程蓝屏NO_MORE_IRP_STACK_LOCATIONS(35)问题分析
最近在搞一个串口的过滤驱动程序,在调度过程中报了一个蓝屏问题。NO_MORE_IRP_STACK_LOCATIONS (35)A higher level driver has attempted to call a lower level driver throughthe IoCallDr......
作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!