虫趣:FAST_MUTEX死锁

本文分析了一起由设备驱动在处理电源IRP时超时未完成导致的0x9F蓝屏错误,详细描述了故障定位过程,包括识别错误类型、分析错误参数、跟踪调用栈以及最终找到导致问题的根本原因。文章还介绍了如何通过加载NT模块的私有符号来获取关键信息,并最终确定问题为死锁,提供了从技术层面深入理解并解决问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拿到一个dump文件后,经过简单分析,是设备驱动在处理电源IRP时,超时未完成导致的。这是一个典型的0x9F BSOD错误:

DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time (usually 10 minutes).
Arguments:
Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time
Arg2: fffffa800182aa90, Physical Device Object of the stack
Arg3: fffff800139e9930, nt!TRIAGE_9F_POWER on Win7, otherwise the Functional Device Object of the stack
Arg4: fffffa8002437e10, The blocked IRP

自动分析的内容告诉我:在处理地址为fffffa8002437e10的电源IRP(IRP_MJ_POWER)时,超时(一般10分钟)未能完成,所以引发了系统0x9F蓝屏。自动分析同时列出了当前线程(处理此IRP的线程)调用栈:

Child-SP          RetAddr           Call Site
fffff880`181ab5e0 fffff800`169137cb nt!KiSwapContext(void)+0x76
(Inline Function) --------`-------- nt!KiSwapThread+0xfa
fffff880`181ab720 fffff800`1691260f nt!KiCommitThreadWait+0x23b
fffff880`181ab7e0 fffff800`16977acd nt!KeWaitForSingleObject+0x1cf 
fffff880`181ab870 fffff800`16920255 nt!ExpAcquireFastMutexContended+0x3d
(Inline Function) --------`-------- nt!ExAcquireFastMutex+0x38 
fffff880`181ab8b0 fffff880`046208b6 nt!KeAcquireGuardedMutex(struct _FAST_MUTEX * Mutex = 0xfffffa80`044e81e0)+0x45 
// 中间省略ModuleA的调用
fffff880`181abca0 fffff800`168a2fd9 nt!PopIrpWorker(void * Context = )+0x284
fffff880`181abd50 fffff800`169577e6 nt!PspSystemThreadStartup
fffff880`181abda0 00000000`00000000 nt!KxStartSystemThread(void)+0x16

从调用栈能够看到,线程因为在等待一个同步对象,而进入了休眠状态。从字面上看,这是一个FAST_MUTEX对象。如果能够得到这个对象的地址,就太好了。我试图加载NT模块的私有符号,很幸运成功了。切换到函数KeAcquireGuardedMutex的调用帧后,得到了同步对象的有效信息:

0: kd> dt _fast_mutex 0xfffffa80`044e81e0
nt!_FAST_MUTEX
   +0x000 Count            : 0n4
   +0x008 Owner            : 0xfffffa80`02c8d7c0 Void
   +0x010 Contention       : 8
   +0x018 Event            : _KEVENT
   +0x030 OldIrql          : 0

调试最担心的问题就是地址无效,比较有效的方法是通过关键值的比对,判断地址的有效性。这里我感兴趣的是Owner变量,是这个FAST_MUTEX对象的拥有者线程。如果地址正确的话,我就能够得到一个线程调用栈。切过去看看:

0: kd> !thread 0xfffffa80`02c8d7c0
//省略summary
nt!KiSwapContext+0x76 
nt!KiSwapThread+0xfa (Inline Function @ fffff800`169137cb) 
nt!KiCommitThreadWait+0x23b 
nt!KeWaitForSingleObject+0x1cf 
nt!MiWaitForInPageComplete+0xb8 
nt!MiIssueHardFault+0x1b7 
nt!MmAccessFault+0x81f 
nt!KiPageFault+0x16e (TrapFrame @ fffff880`03b3a810) 
//中间省略ModuleA的调用
nt!PspSystemThreadStartup+0x59 
nt!KxStartSystemThread+0x16

地址是有效的,并且得到的调用栈中也有一堆ModuleA的函数。问题到此可告一段落了:

  1. 线程1在处理IRP_MJ_POWER的时候,试图获取一个FAST_MUTEX同步对象,但因获取失败而进入休眠状态(并因休眠过久,而导致BSOD)。
  2. 在成功获取FAST_MUTEX对象的地址后,从它的结构体中得到了当前拥有此同步对象的线程2地址。
  3. 切换到线程2,发现线程2有一个无法处理的页错误,也同样处于等待状态中。

这个问题到目前为止,可判定是一个死锁问题。只要线程2能够及时释放它所拥有的FAST_MUTEX对象就可以了。但更深层的原因则是线程2竟然因为一个页错误而陷入长时间的等待,得不到解决。由于这个中间的模块是一个保密模块,本人无权限分析。所以到这里为止我的任务就结束了,接下来要让ModuleA模块的部门做进一步分析。

dd40: edb9dd50 c014db00 00000058 c06acc8c 00000000 c0b03c48 ed87c800 c047ad74 dd60: fffffff5 0000000e edb9ddb4 00000000 fffffff4 0000000e edb9ddb4 c0136334 dd80: ed87c800 00000000 00000043 ed87c800 00000000 00000000 ed87c82c c074cc24 dda0: 00000000 edb9de78 ee33c50c c05af644 ed87c800 ed87c800 00000000 c0b03c48 ddc0: ed87c800 00000001 00000043 00000000 00000002 c05af8f0 ed87c800 00000043 dde0: 00000000 c0b03c48 ed87c800 edb9de68 00000000 00000002 ed87c938 c05af920 de00: edbd8580 edb9de68 ed87c800 ee33c500 ee33c50c c0617244 00008914 00000014 de20: 0000002a c02fe674 001c001c ffff0043 b6ef1fa8 00000004 00008916 c0b03c48 de40: 00000020 00008914 bec43b00 bec43b00 bec43b00 ed9faf00 edb9c000 00000036 de60: 00000000 c06197a4 32687465 00000000 00000000 00000000 ffff0043 b6ef1fa8 de80: 00000004 00008916 c0b2c6c0 c05a6c54 edb9dedc edb9dedc 00000000 ffc43b1f dea0: bec43b00 bec43b00 ed9faf00 bec43b00 00000020 00000000 00000051 c0b03c48 dec0: bec43b00 00008914 bec43b00 c0591d44 ee029e50 edc1ed01 edc9db18 32687465 dee0: 00000000 00000000 00000000 ffff0002 b6ef1fa8 00000004 00008916 c0b03c48 df00: bec43b00 edd20e80 ed9faf00 c01f26a0 bec43b00 c01f2fe8 00000057 b6e8b2c4 df20: edb9dfb0 edb99840 00000054 80000007 eda59e40 c014eb88 b6e8b2c4 c0111c5c df40: 00019dd4 00000002 fffff000 c01dbc14 ee2e5680 c0b3e098 00000000 00000000 df60: 00000000 00000007 b6e8b2c4 c0b03c48 ed9faf00 00000004 00008914 bec43b00 df80: ed9faf00 edb9c000 00000036 c01f364c 0002a4b0 00000043 bec43bd0 00000036 dfa0: c0101204 c0101000 0002a4b0 00000043 00000004 00008914 bec43b00 00000002 dfc0: 0002a4b0 00000043 bec43bd0 00000036 ffffffbd 000188d4 bec43eed 00000000 dfe0: 0002a080 bec43afc 00013504 b6e65b9c 400b0010 00000004 00000000 00000000 [<c014d7e0>] (atomic_cmpxchg_relaxed) from [<c014db00>] (atomic_try_cmpxchg_acquire.constprop.0+0x10/0x28) [<c014db00>] (atomic_try_cmpxchg_acquire.constprop.0) from [<c06acc8c>] (mutex_lock+0x38/0x6c) [<c06acc8c>] (mutex_lock) from [<c047ad74>] (axienet_open+0x148/0x6a4) [<c047ad74>] (axienet_open) from [<c05af644>] (__dev_open+0xe0/0xfc) [<c05af644>] (__dev_open) from [<c05af8f0>] (__dev_change_flags+0x150/0x168) [<c05af8f0>] (__dev_change_flags) from [<c05af920>] (dev_change_flags+0x18/0x48) [<c05af920>] (dev_change_flags) from [<c0617244>] (devinet_ioctl+0x2d4/0x580) [<c0617244>] (devinet_ioctl) from [<c06197a4>] (inet_ioctl+0x1f4/0x218) [<c06197a4>] (inet_ioctl) from [<c0591d44>] (sock_ioctl+0xe0/0x440) [<c0591d44>] (sock_ioctl) from [<c01f26a0>] (vfs_ioctl+0x20/0x38) [<c01f26a0>] (vfs_ioctl) from [<c01f2fe8>] (do_vfs_ioctl+0xa4/0x6d0) [<c01f2fe8>] (do_vfs_ioctl) from [<c01f364c>] (ksys_ioctl+0x38/0x54) [<c01f364c>] (ksys_ioctl) from [<c0101000>] (ret_fast_syscall+0x0/0x54) Exception stack(0xedb9dfa8 to 0xedb9dff0) dfa0: 0002a4b0 00000043 00000004 00008914 bec43b00 00000002 dfc0: 0002a4b0 00000043 bec43bd0 00000036 ffffffbd 000188d4 bec43eed 00000000 dfe0: 0002a080 bec43afc 00013504 b6e65b9c Code: e12fff1e e92d4010 e1a03000 ebfffffa (e1930f9f) ---[ end trace 54a2401cab8a4f9a ]--- Segmentation fault
最新发布
03-14
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值