You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NDIS 6过滤驱动克隆Net Buffer List后运行异常缓慢问题排查

NDIS 6过滤驱动接收侧内存管理与网络卡顿问题排查方案

问题背景

开发NDIS 6过滤驱动用于拦截编辑Windows本机网络数据包,仅实现FilterSendNetBufferLists、FilterSendNetBufferListsComplete、FilterReceiveNetBufferLists、FilterReturnNetBufferLists四个核心函数处理DNS数据包,其余NDIS函数设为NULL或保留模板。

发送侧流程正常:克隆NetBufferLists(NdisAllocateCloneNetBufferList)→ 修改后下发(NdisFSendNetBufferLists)→ 完成回调中释放克隆包(NdisFreeCloneNetBufferList),无异常。

接收侧存在两个核心问题:

  1. 驱动运行后网络极度缓慢(可ping通但浏览器无法加载页面),仅修改特定DNS包,排除修改逻辑影响
  2. 尝试释放接收侧克隆包触发系统崩溃,Windbg报错:

An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high.
栈信息末尾包含:
ndis!ndisMSendCompleteNetBufferListsToOpen+0x6c ndis!ndisMSendCompleteNetBufferListsInternal+0x31e ndis!NdisMSendNetBufferListsComplete+0x24b
尝试释放/返回原始NetBufferLists会触发双重释放崩溃,已知接收侧内存应由NDIS回收,但无法定位卡顿原因。


一、接收侧核心逻辑修正(解决网络卡顿)

网络卡顿的根源是原始NetBufferList未被正确归还,导致下层驱动缓冲区池耗尽,修正流程如下:

  • 克隆原始包后,立即调用NdisFReturnNetBufferLists将原始包返回给NDIS,禁止持有原始包占用缓冲区
  • 克隆包属于驱动自行分配的资源,需由驱动主动释放,不能通过NdisFReturnNetBufferLists返回给NDIS

正确的接收侧流程:

  1. 在FilterReceiveNetBufferLists中,接收原始NetBufferList链
  2. 调用NdisAllocateCloneNetBufferList克隆目标DNS包(仅克隆需要修改的包,避免无意义资源消耗)
  3. 修改克隆包中的DNS数据
  4. 调用NdisFIndicateReceiveNetBufferLists将克隆包上传至上层协议栈
  5. 立即调用NdisFReturnNetBufferLists将原始NetBufferList返回给下层驱动
  6. 在FilterReturnNetBufferLists中,接收上层返回的克隆包,将其放入工作线程队列,后续在PASSIVE_LEVEL下调用NdisFreeCloneNetBufferList释放

二、内存释放的IRQL合规性(解决系统崩溃)

Windbg的IRQL过高报错,说明你在高于DISPATCH_LEVEL的IRQL下执行了分页内存操作,修正要点:

  • NdisFreeCloneNetBufferList必须在IRQL ≤ DISPATCH_LEVEL下调用,而FilterReturnNetBufferLists可能在DPC_LEVEL触发(高于DISPATCH_LEVEL)
  • 解决方法:
    1. 在FilterReturnNetBufferLists中,将需要释放的克隆包添加到驱动的工作队列,使用IoQueueWorkItem调度到工作线程执行释放操作
    2. 克隆包时,如果需要在高IRQL下操作,确保NdisAllocateCloneNetBufferList的PoolType参数指定为NonPagedPoolNx,避免分页内存访问问题

三、针对性排查步骤

  1. 缓冲区池耗尽验证:使用Windbg命令!ndis nb查看NetBufferList的分配、释放、未归还统计,确认是否有大量原始包未被归还
  2. 处理延迟排查:检查FilterReceiveNetBufferLists中是否存在耗时操作(如未优化的DNS包解析),将复杂逻辑异步到工作线程,避免阻塞接收路径
  3. 标志位检查:调用NdisFIndicateReceiveNetBufferLists时,设置正确的标志位(如NDIS_RECEIVE_FLAGS_RESOURCES),让NDIS知道驱动已放弃原始包的所有权,减少额外处理开销

四、NDIS接收侧内存管理核心规则

  • 原始包所有权:接收侧的原始NetBufferList属于下层驱动,过滤驱动必须在处理完成后立即返回,禁止长期持有
  • 克隆包所有权:通过NdisAllocateCloneNetBufferList创建的克隆包,所有权属于过滤驱动,必须由驱动主动调用NdisFreeCloneNetBufferList释放,不能返回给NDIS
  • IRQL约束:
    • NdisAllocateCloneNetBufferList:可在IRQL ≤ DISPATCH_LEVEL调用(取决于PoolType参数)
    • NdisFreeCloneNetBufferList:必须在IRQL ≤ DISPATCH_LEVEL调用,高IRQL下需异步到工作线程执行

内容的提问来源于stack exchange,提问作者eng0130

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:17:08