Re: IRQL规则

Windows内核调试

IRQL规则


yushang 2009-08-12, 12:12 下午
都说在DPC级别时,不能调用导致缺页中断的函数,我猜想是不是Windows会在某个地方检查当前的IRQL,如果在DPC上就BugCheck一个IRQL_NOT_LESS_OR_EQUAL错误。如果是这样,是在哪个地方检查的呢?我试着检查了一下TRAP0E的代码,发现只要MmAccessFault返回0D0000006的话,就会导致TRAP0E BugCheck这个错误,但是MmAccessFault太长了,有人能提供一点启发吗?

Re: IRQL规则


王宇 2009-08-12, 15:49 下午
这个问题很简单,看看源码 / 跟一下就知道了

http://advdbg.org/forums/2018/ShowPost.aspx

首先 MmAccessFault 内部会判断:

PreviousIrql = KeGetCurrentIrql ();

......

if (
#if (_MI_PAGING_LEVELS >= 4)
(PointerPxe->u.Hard.Valid == 0) ||
#endif
#if (_MI_PAGING_LEVELS >= 3)
(PointerPpe->u.Hard.Valid == 0) ||
#endif
(PointerPde->u.Hard.Valid == 0) ||

((!MI_PDE_MAPS_LARGE_PAGE (PointerPde)) && (PointerPte->u.Hard.Valid == 0))) {

if (KeInvalidAccessAllowed (TrapInformation) == TRUE) {
return STATUS_ACCESS_VIOLATION;
}

KdPrint(("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
VirtualAddress,
PreviousIrql));

if (TrapInformation != NULL) {
MI_DISPLAY_TRAP_INFORMATION (TrapInformation);
}

//
// Signal the fatal error to the trap handler.
//

return STATUS_IN_PAGE_ERROR | 0x10000000;

}

也就是这里的 PTE 等判断失败,返回值 d0000006。这里已经“命中注定”要蓝屏了。

//
// MessageId: STATUS_IN_PAGE_ERROR
//
// MessageText:
//
// The instruction at "0x%08lx" referenced memory at "0x%08lx". The required data was not placed into memory because of an I/O error status of "0x%08lx".
//
#define STATUS_IN_PAGE_ERROR ((NTSTATUS)0xC0000006L) // winnt

----------------------------

此时再回到 _KiTrap0E 的流程做几个判断:

1. Check to determine if the fault occured in the interlocked pop entry slist code.

2. Check to determine if the page fault occured in the user mode interlocked pop entry SLIST code.

3. Did the fault occur in KiSystemService while copying arguments from user stack to kernel stack?

4. Did the fault occur in a VDM?

5. Did the fault occur in a VDM while running in protected mode?

之所以说“命中注定”是因为:

;
; test to see if reserved status code bit is set. If so, then bugchecka
;

cmp eax, STATUS_IN_PAGE_ERROR or 10000000h ; 我们的返回值
je Kt0e12 ; bugchecka

最后蓝屏:

Kt0e12:
CurrentIrql ; (eax) = OldIrql
Kt0e12a:
lock inc ds:_KiHardwareTrigger ; trip hardware analyzer

;
; bugcheck a, addr, irql, load/store, pc
;
mov ecx, [ebp]+TsErrCode ; (ecx)= error code
shr ecx, 1 ; isolate read/write bit
and ecx, _KeErrorMask ;
mov esi, [ebp]+TsEip ; [esi] = faulting instruction

stdCall _KeBugCheck2,

错误码是:IRQL_NOT_LESS_OR_EQUAL

打完收功~

Re: IRQL规则


yushang 2009-08-13, 17:19 下午

不过好像PreviousIrql就没有和谁比较过,似乎当前IRQL大于等于DPC的事实隐含在

if (
#if (_MI_PAGING_LEVELS >= 4)
(PointerPxe->u.Hard.Valid == 0) ||
#endif
#if (_MI_PAGING_LEVELS >= 3)
(PointerPpe->u.Hard.Valid == 0) ||
#endif
(PointerPde->u.Hard.Valid == 0) ||

((!MI_PDE_MAPS_LARGE_PAGE (PointerPde)) && (PointerPte->u.Hard.Valid == 0)))

。。。

中,可以这样理解吗?

Re: IRQL规则


王宇 2009-08-14, 10:04 上午
当前 IRQL 大于等于 DPC 本身不是问题
P位 标识出页不在物理内存中才是问题
所以才有那些代码

Re: IRQL规则


yushang 2009-08-14, 19:53 下午

晕

Re: IRQL规则


yushang 2009-08-15, 23:22 下午
为什么PTE 等判断失败就等效于IRQL >= DPC ,谢谢?

Re: IRQL规则


王宇 2009-08-17, 09:18 上午
IRQL >= DPC 只要你访问的页面有效 (锁定在物理内存中的分页 / 非分页) 就没有问题
但是 IRQL >= DPC 且页面无效,这就违背了 IRQL 的基本准则。


“都说在DPC级别时,不能调用导致缺页中断的函数,我猜想是不是Windows会在某个地方检查当前的IRQL,如果在DPC上就BugCheck一个IRQL_NOT_LESS_OR_EQUAL错误。” <-- 在 DPC 上本身不是错,在 DPC 上缺页才是错

Re: IRQL规则


yushang 2009-08-17, 20:30 下午

但是 IRQL >= DPC 且页面无效,这就违背了 IRQL 的基本准则。

是啊,我也是这样认为的,但是系统是在什么地方判断出IRQL >= DPC 的呢?还是引用我前面问过的话:

“。。。好像PreviousIrql就没有和谁比较过。。。”,例如,是不是应该有类似这样的比较:

if ( PreviousIrql >= DISPATCH_LEVEL )

   BugCheck...

谢谢

Re: IRQL规则


王宇 2009-08-17, 21:56 下午
大哥 你介是逼我贴代码啊  WRK 有代码引用协议的........

    PreviousIrql = KeGetCurrentIrql ();

    if (PreviousIrql > APC_LEVEL) {  // 条件一

        if (
#if (_MI_PAGING_LEVELS >= 4)
            (PointerPxe->u.Hard.Valid == 0) ||
#endif
#if (_MI_PAGING_LEVELS >= 3)
            (PointerPpe->u.Hard.Valid == 0) ||
#endif
            (PointerPde->u.Hard.Valid == 0) ||

            ((!MI_PDE_MAPS_LARGE_PAGE (PointerPde)) && (PointerPte->u.Hard.Valid == 0))) {  // 条件二

            if (KeInvalidAccessAllowed (TrapInformation) == TRUE) {
                return STATUS_ACCESS_VIOLATION;
            }

            KdPrint(("MM:***PAGE FAULT AT IRQL > 1  Va %p, IRQL %lx\n",
                     VirtualAddress,
                     PreviousIrql));

            if (TrapInformation != NULL) {
                MI_DISPLAY_TRAP_INFORMATION (TrapInformation);
            }

            //
            // Signal the fatal error to the trap handler.
            //

            return STATUS_IN_PAGE_ERROR | 0x10000000;  // ~

        }

    ......

    }

Re: IRQL规则


yushang 2009-08-17, 22:21 下午

呵呵,终于看到关键的东西了,不贴也可以啊,你只要确认有类似的语句就行了。

Re: IRQL规则


格蠹老雷 2009-08-17, 22:23 下午
呵呵,刨根问底没有错啊,也可以贴汇编么 :-)

Re: IRQL规则


yushang 2009-08-17, 22:40 下午

回过头来看看汇编,似乎下面这一段是和所贴代码对应的

...

call    dword ptr [nt!_imp__KeGetCurrentIrql (804d9108)]     ;PreviousIrql

cmp     al,1                                                                              ;和APC_LEVEL比较

mov     byte ptr [ebp-2],al

jbe     nt!MmAccessFault+0x185

//>APC_LEVEL,进一步判断第二个条件,如果也满足就BSOD了

mov     ecx,ebx

call    nt!MiCheckPdeForPagedPool

...

Powered by Community Server Powered by CnForums.Net