Mini Filter Driver触发Bugcheck D1问题分析

来源:互联网 发布:pc蛋蛋幸运28算法公式 编辑:程序博客网 时间:2024/05/16 14:40

前段时间帮朋友改进他做的文件加密Mini Filter Driver,好不容易把期待的功能完善好了,测试时开始频繁触发蓝屏,Bugcheck号是D1。WinDbg对这个错误号的简单解释如下:

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high.  This is usually caused by drivers using improper addresses.

也就是在高IRQL试图访问可换页内存。看到这种错误的第一反应是头皮发麻。冷静下来后,我回想起以前自己总结出的经验,那就是碰到错误不要慌,首先把错误的所有信息解读清楚。

从栈回溯来看,发生错误的位置如下:

STACK_TEXT:  
8078ab6c 99298fff badb0d00 868992b8 89d28620 nt!KiTrap0E+0x1b3
8078ac30 84c587d1 868992b8 8078ac84 9db0cff8 S_Crypt!PostRead+0x27
8078ac60 84c33324 868992b8 0278ac84 9db0cff8 fltmgr!FltvPostOperation+0x71
8078acc8 84c36512 00899258 86899258 10000000 fltmgr!FltpPerformPostCallbacks+0x24a
8078acdc 84c36b46 86899258 8078ad90 8078ad1c fltmgr!FltpProcessIoCompletion+0x10
8078acec 82b50cd4 8a288728 9db08e28 86899258 fltmgr!FltpPassThroughCompletion+0x98
8078ad1c 82896dd3 8a288728 9db08e28 8078ad90 nt!IovpLocalCompletionRoutine+0x14b
8078ad60 82b50b64 00000001 89c09e98 8a234008 nt!IopfCompleteRequest+0x128
8078adc8 85248498 8078adfc 85248abd 8a2336a8 nt!IovCompleteRequest+0x133

这个函数里并没有提升IRQL的相关动作。那为什么会出这个错呢?

因为我之前也没有做Mini Filter Driver的经验,本着认真学习的态度,开始认真阅读WDK的帮助中有关PFLT_POST_OPERATION_CALLBACK的内容。

Post-operation callback routines are called in an arbitrary thread context, at IRQL <= DISPATCH_LEVEL.  Because this callback routine can be called at IRQL DISPATCH_LEVEL, it is subject to the following constraints ... ...

大意是说Post-operation回调函数可能在任何线程上下文中被调用,IRQL <= DISPATCH_LEVEL。因为有可能IRQL是DISPATCH_LEVEL,所以会有一些限制。基于当时对WinDbg对D1 bugcheck的解释,我很容易的找到了其中的一个限制,于是认为自己大致明白了这个错误的原因:PostRead函数可能会在DISPATCH_LEVEL被调用,所以在它里面不可以访问paged pool.

Any data structures used in this routine must be allocated from nonpaged pool. 

此时,再来看Bugcheck信息里包含的几个参数。

Arguments:
Arg1: 99299000, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000008, value 0 = read operation, 1 = write operation
Arg4: 99298fff, address which referenced memory

惊奇地发现,发出访问请求的地址和被访问的地址都是PostRead函数里的代码地址。这是为什么呢?再冷静下来细看,每次发生蓝屏时,被访问地址的后三位都是000,也就是被访问地址刚好都是一个页的起始地址。猜测是在要执行下一条地址时,下一条地址刚好在另一个内存页上,而这个内存页此时是无效的,所以需要触发Page Fault,而在DISPATCH_LEVEL,这又是不允许的。

再回过头来看WDK的帮助,发现其中还有一条限制如下。之前没有注意到它,可能是因为它太简短,一时没有看明白它的含义。现在明白,它说的是Post-operation回调函数本身不可以是可换页的。

It cannot be made pageable. 

经过一番查找,在一个头文件里找到了如下的内容。

<pre name="code" class="cpp">#pragma alloc_text(PAGE, S_PostRead)

修改过后,重新测试,问题消失。

#pragma alloc_text(NONPAGED, S_PostRead)
再后来,我又追究起为什么刚开始时测试时,没有这样的蓝屏出现,查找之下。原来是在发现功能基本稳定后,打开了Driver Verifier,这大大提高了解发该BSOD的概率。





0 0
原创粉丝点击