我们有一个NDIS驱动程序,只有在很少的系统上,我们在IRQL_UNEXPECTED_VALUE
上得到了NdisFIndicateReceiveNetBufferLists
,但是在代码的任何部分我们没有提高或降低IRQL,而NdisFIndicateReceiveNetBufferLists
在irp_mj_device_control
回调中被调用。我们还检查了IRQL,如果它的分派,我们将最后一个参数设置为NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL
,否则,这会是问题吗?
我还发现这篇文章:
https://knowledge.broadcom.com/external/article/164146/crash-with-bug-check-0xc8-after-installi.html
他们也有类似的问题,问题似乎是有另一个NDIS驱动程序将IRQL提高到DISPATCH_LEVEL
,而忘记降低它吗?但我还是不确定这是否适用于我们的问题?这是否也是我们的问题呢?
IRQL_UNEXPECTED_VALUE (c8)
The processor's IRQL is not what it should be at this time. This is
usually caused by a lower level routine changing IRQL for some period
and not restoring IRQL at the end of that period (eg acquires spinlock
but doesn't release it).
Arguments:
Arg1: 0000000000020002, (Current IRQL << 16) | (Expected IRQL << 8) | UniqueValue
Arg2: fffff82621a444f0, Depends on UniqueValue:
If UniqueValue is 0 or 1: APC->KernelRoutine.
If UniqueValue is 2: the callout routine
If UniqueValue is 3: the interrupt's ServiceRoutine
If UniqueValue is 0xfe: 1 iff APCs are disabled
Arg3: ffff950cf4dccff0, Depends on UniqueValue:
If UniqueValue is 0 or 1: APC
If UniqueValue is 2: the callout's parameter
If UniqueValue is 3: KINTERRUPT
Arg4: 0000000000000000, Depends on UniqueValue:
If UniqueValue is 0 or 1: APC->NormalRoutine
呼叫堆栈:
nt!KeBugCheckEx
nt!KeExpandKernelStackAndCalloutInternal
nt!KeExpandKernelStackAndCalloutEx
ndis!ndisInvokeNextReceiveHandler
ndis!ndisFilterIndicateReceiveNetBufferLists
ndis!NdisFIndicateReceiveNetBufferLists
OurNdis
第二个参数是标注例程(基于唯一值),是ndis!ndisDataPathExpandStackCallback
。
Edit1:
我做了更多的研究,实际上,似乎ndisDataPathExpandStackCallback
实际上只是调用了ndisCallReceiveHandler
(它没有出现在堆栈中)。我想这只是指示NBL到其他NDIS驱动程序?无论如何,ndisDataPathExpandStackCallback
是通过KeExpandKernelStackAndCalloutInternal
调用的,后者存储IRQL,并在调用后检查IRQL,如果它不匹配,就会引发错误检查,宾果!
但是,现在我的问题是,我如何才能找到有问题的司机?我能以某种方式使用ndiskd扩展来帮助我哪个NDIS驱动程序调用了KeExpandKernelStackAndCalloutInternal
,这样我就可以证明并找到错误的驱动程序了吗?
虽然通过对堆栈的研究,我确实找到了pacer!PcFilterReceiveNetBufferLists
,但我怀疑这是一个错误的驱动程序,考虑到它是一个windows驱动程序,对吗?
发布于 2022-02-20 20:13:20
他们也有类似的问题,问题似乎是有另一个NDIS驱动程序将IRQL提升到DISPATCH_LEVEL,而忘记降低它呢?但我还是不确定这是否适用于我们的问题?这是否也是我们的问题呢?
这个特别的错误意味着有人在已经解除堆栈的代码中泄漏了IRQL。KeExpandKernelStackAndCalloutInternal
正在做这样的事情:
oldIrql = KeGetCurrentIrql();
(*callback)(...);
newIrql = KeGetCurrentIrql();
if (oldIrql != newIrql) {
KeBugCheckEx(IRQL_UNEXPECTED_VALUE, (newIrql << 16) | (oldIrql << 8) | 2, ...);
}
解码第一个参数,这意味着IRQL在输入时为PASSIVE_LEVEL,在退出时为DISPATCH_LEVEL。
不幸的是,这样做的代码已经运行完--这个错误只是确认他们离开房间之前没有清理过这个地方。通过查看!ndiskd.miniport
中的过滤器驱动程序堆栈,您可以对可能运行的代码进行合理的猜测。但这只是给您一个起点:取决于哪些数据包来自网络,网络堆栈可以调用到各种驱动程序中。例如,如果网络指示了一个SMB3数据包,那么执行实际上就会在文件系统堆栈中一直向上走。因此,列出所有可能运行的驱动程序并不容易。
但是,要检查的一件事是,您正确地使用了NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL
标志。只有在确定IRQL当前为DISPATCH_LEVEL
时,才允许设置标志。如果该标志使用不当,您可能会欺骗其他驱动程序使其与IRQL不匹配。例如,假设的司机可能有:
void FilterReceiveNbls(..., ULONG ReceiveFlags) {
KIRQL oldIrql;
KeRaiseCurrentIrql(DISPATCH_LEVEL, &oldIrql);
. . . do stuff at dispatch level . . .
if (0 == (ReceiveFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL)) {
KeLowerCurrentIrql(oldIrql);
}
}
我并不是很肯定地说这正是发生的事。我只是在寻找您可以在您的驱动程序中审计的东西,正确使用NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL就是其中之一。请注意,不将此标志添加到ReceiveFlags
总是正确的。(事实上,如果您看到其他人设置了该标志,那么清除它甚至是正确的--该标志的唯一好处是非常微小的perf优化。)所以如果你有疑问,就别再加旗子了。
如果启用NDIS/WIFI选项,Windows 11可以严格验证此标志。最简单的方法是在所有驱动程序上启用DV,但是如果运行太慢,您可以选择每个单独的网络驱动程序。在Windows 11上,当使用NDIS/WIFI选项启用DV时,如果任何驱动程序误用任何NDIS_XXX_DISPATCH_LEVEL标志,您将在错误所在的位置得到即时错误检查。
(DV目前并不能验证驱动程序是否将IRQL返回到原来的水平-这是未来的一个好主意。)
https://stackoverflow.com/questions/71194617
复制相似问题