Legacy Filter Driver FastIO Bugcheck 0x3B

Our driver has been used for many years now but we are now finding that on some platforms we get a bugcheck 3B in our FastIoQueryStandardInfo dispatch routine.

Looking at the crash dump, at the point where the crash occurs all of our data seems fine ie. the DeviceObject pointer passed in points to one of our DeviceObjects, our device extension points ok to the attached DeviceObject and its DriverObject pointer points to a valid DriverObject which contains a valid FastIODispatch pointer that we are trying to pass the fastio request on to. The code leading up to the crash is shown below…

  1. mov r13,rcx
  2. je PDRDrv64!PDRDrvFastIoQueryStandardInfo+0xca (fffff800`4af2beaa)
  3. mov rdi,qword ptr [rdi+40h]
  4. lea edx,[rbx+8]
  5. mov rcx,rdi
  6. call PDRDrv64!PDRProbeForRead (fffff800`4af214fc)
  7. cmp al,bl
  8. je PDRDrv64!PDRDrvFastIoQueryStandardInfo+0xe5 (fffff800`4af2bec5)
  9. mov rcx,qword ptr [rdi+8]
  10. lea edx,[rbx+8]
  11. call PDRDrv64!PDRProbeForRead (fffff800`4af214fc)
  12. cmp al,bl
  13. je PDRDrv64!PDRDrvFastIoQueryStandardInfo+0xe5 (fffff800`4af2bec5)
  14. mov rcx,qword ptr [rdi+8]
  15. lea edx,[rbx+8]
  16. mov rcx,qword ptr [rcx+8] <– Crash here

The dump shows …

  • Crash occuring at line 16 due to rcx being 00000000’00000000.
  • At this time of crash, rdi contained ffffe00081423ce0.

So, for rcx to be 0 then qword ptr [rdi+8] (ie ffffe00081423ce8) must have contained 0 when line 14 executed.

However, when the crash occurred at line 16, ffffe00081423ce8 contained ffffe0007e4c1b70 which is a valid pointer to the DeviceObject I would expect it to point to since ffffe00081423ce8 is the field in our device extension structure which holds the address of the DeviceObject we have attached to.

I attach to any newly mounted files systems using IoAttachDeviceToDeviceStackSafe and passing in the address of the field in my device extension which holds the attached device object as the third parameter.

So, my question is, how could I even be in one of my drivers fastio routine before my device extension structure has received the address of the DeviceObject it is hooked up to ?

Any help greatly appreciated.

Just re-read my post and maybe its a bit unclear. As the device object attached to part of my device extension structure seems to be changing under my feet, i can only assume it’s because it is still in the process of being created and the fastio routine has been called before its fully initialized. Of course, theer may be othe reasons. Output of analyze -v below …

*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

SYSTEM_SERVICE_EXCEPTION (3b)
An exception happened while executing a system service routine.
Arguments:
Arg1: 00000000c0000005, Exception code that caused the bugcheck
Arg2: fffff8004af2be46, Address of the instruction which caused the bugcheck
Arg3: ffffd0010dbb0920, Address of the context record for the exception that caused the bugcheck
Arg4: 0000000000000000, zero.

Debugging Details:

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

FAULTING_IP:
PDRDrv64!PDRDrvFastIoQueryStandardInfo+66 [u:\PDRdrv\PDRdrv.c @ 783]
fffff800`4af2be46 488b4908 mov rcx,qword ptr [rcx+8]

CONTEXT: ffffd0010dbb0920 – (.cxr 0xffffd0010dbb0920)
rax=0000000000000001 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000008 rsi=ffffd0010dbb13c0 rdi=ffffe00081423ce0
rip=fffff8004af2be46 rsp=ffffd0010dbb1340 rbp=ffffd0010dbb13e8
r8=ffffd0010dbb13e8 r9=ffffd0010dbb13c0 r10=ffffe0007bfe5f80
r11=ffffe000814012b0 r12=0000000001000001 r13=ffffe000813d68c0
r14=ffffd0010dbb14d8 r15=0000000000000002
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010202
PDRDrv64!PDRDrvFastIoQueryStandardInfo+0x66:
fffff8004af2be46 488b4908 mov rcx,qword ptr [rcx+8] ds:002b:0000000000000008=???
Resetting default scope

DEFAULT_BUCKET_ID: WIN8_DRIVER_FAULT

BUGCHECK_STR: 0x3B

PROCESS_NAME: dwm.exe

CURRENT_IRQL: 0

LAST_CONTROL_TRANSFER: from fffff8009d0511eb to fffff8004af2be46

STACK_TEXT:
ffffd0010dbb1340 fffff8009d0511eb : 0000000000000402 ffffd0010dbb1410 ffffe000813d68c0 0000000000000000 : PDRDrv64!PDRDrvFastIoQueryStandardInfo+0x66 [u:\PDRdrv\PDRdrv.c @ 783]
ffffd0010dbb1390 fffff8009d04fffa : 0000000000000000 0000000000000000 0000000000000402 ffff1ed800000000 : nt!FsRtlGetFileSize+0x77
ffffd0010dbb1440 fffff8009d0dd07b : ffffe000813d68c0 0000000001000000 ffffd0010dbb16e9 0000000000000000 : nt!MiCreateImageFileMap+0x82
ffffd0010dbb15f0 fffff8009d123635 : 0000000000000402 ffffd0010dbb1820 ffffffffffffffff ffffffffffffffff : nt!MiCreateNewSection+0xd7
ffffd0010dbb1720 fffff8009d122b09 : ffffd0010dbb1960 0000000000000000 000000010060d628 ffffd0010dbb1958 : nt!MiCreateSection+0xa15
ffffd0010dbb18f0 fffff8009cdd71a3 : ffffe0008142a080 000000010060d568 ffffd0010dbb19a8 000000010060d660 : nt!NtCreateSection+0x1c9
ffffd0010dbb1990 00007ffb51a05a24 : 00007ffb51967aba 000000010060d660 000000010000003e 0000000100480046 : nt!KiSystemServiceCopyEnd+0x13
000000010060d548 00007ffb51967aba : 000000010060d660 000000010000003e 0000000100480046 0000000100000030 : ntdll!NtCreateSection+0x14
000000010060d550 00007ffb51969537 : 0000000000000000 00000000000001d0 00000174c12df268 0000000000000000 : ntdll!LdrpMapDllNtFileName+0x15a
000000010060d620 00007ffb519692dc : 0000000000000000 00000174c135b0f0 000000010060d801 000000010060db00 : ntdll!LdrpMapDllFullPath+0xcb
000000010060d7a0 00007ffb51971e79 : 00000174c135b0f0 000000010060d901 000000010060d8b4 000000010060d8c0 : ntdll!LdrpProcessWork+0x50
000000010060d7f0 00007ffb519719fe : 000000010060d8c0 000000010060da50 0000000000000000 0000000000002001 : ntdll!LdrpLoadDllInternal+0x14d
000000010060d870 00007ffb51970c44 : 0000000000000000 0000000000000000 0000000000000000 0000000000002009 : ntdll!LdrpLoadDll+0xf2
000000010060da10 00007ffb4e08c77f : 000000010060de10 0000000000000000 00000000000001c8 0000000000000000 : ntdll!LdrLoadDll+0x114
000000010060db10 00007ffb50dd15f8 : 0036004400000000 000000010060dce0 00410041002d0044 0000000000000000 : KERNELBASE!LoadLibraryExW+0x16f
000000010060db80 00007ffb50dd1521 : 00000000ffffffff 000000010060dc58 000000010060dce0 000000010060dcb8 : combase!LoadLibraryWithLogging+0x2c
000000010060dbc0 00007ffb50dd1336 : 000000010060e300 000000010060dc70 000000010060dce0 0000000000000000 : combase!CClassCache::CDllPathEntry::LoadDll+0x59
000000010060dc10 00007ffb50dd0e3d : 000000010060e3e0 000000010060dfe8 00000174c1359650 0000000000000000 : combase!CClassCache::CDllPathEntry::Create+0x52
000000010060dca0 00007ffb50e33835 : 00000174c1359650 00000174c1359650 00000174c1359650 000000010060e358 : combase!CClassCache::CClassEntry::CreateDllClassEntry+0x109
000000010060df60 00007ffb50dd03b9 : 000000010060e3e0 0000000000000016 00000174c12b2470 00000000001c001c : combase!CClassCache::GetClassObjectActivator+0x825
000000010060e310 00007ffb50dcfe52 : 00000174c13584e0 0000000000000000 00007ffb50e2ae50 000000010060ed68 : combase!CClassCache::GetClassObject+0x4d
000000010060e380 00007ffb50e3bc53 : 0000017400000001 000000010060f238 000000010060eb30 000000010060f600 : combase!CServerContextActivator::CreateInstance+0x172
000000010060e480 00007ffb50dd0687 : 00007ffb50dd0700 000000010060e578 0000000000000000 00007ffb50e3bb70 : combase!ActivationPropertiesIn::DelegateCreateInstance+0xe3
000000010060e500 00007ffb50dcf3e9 : 00007ffb50fc96f0 0000000000000000 000000010060eb30 00007ffb50ea1af0 : combase!CApartmentActivator::CreateInstance+0xc7
000000010060e5c0 00007ffb50dcf504 : 00007ffb50fc9700 0000000000000001 0000000000000000 0000000000000020 : combase!CProcessActivator::CCICallback+0x79
000000010060e600 00007ffb50dcf5e0 : 00007ffb50dcf4a0 000000010060f600 0000000000000001 0000000000000000 : combase!CProcessActivator::AttemptActivation+0x64
000000010060e640 00007ffb50dcf900 : 00007ffb50dcf530 00007ffb50f531d8 0000000000000000 0000000100000001 : combase!CProcessActivator::ActivateByContext+0xb0
000000010060e6d0 00007ffb50e3bca4 : 00007ffb50fc96f0 000000010060ed68 000000010060eb30 000000010060f418 : combase!CProcessActivator::CreateInstance+0x90
000000010060e720 00007ffb50e3926a : 000000010060e7d0 00007ffb00000000 000000010060e7d0 000000010060e7d0 : combase!ActivationPropertiesIn::DelegateCreateInstance+0x134
000000010060e7a0 00007ffb50e3bc66 : 00007ffb50fc96e8 00007ffb50e39110 000000010060ed68 000000010060f330 : combase!CClientContextActivator::CreateInstance+0x15a
000000010060ea60 00007ffb50e30c31 : 000000010060ed70 000000010060f550 0000000000000001 000000010060ed70 : combase!ActivationPropertiesIn::DelegateCreateInstance+0xf6
000000010060eae0 00007ffb50e2fe77 : 0000000000000000 0000000000000000 00000174c1290000 0000000000000080 : combase!ICoCreateInstanceEx+0xc91
000000010060f800 00007ffb50e2fcdc : 0000000000000000 0000000000000000 0000000000000001 0000000000000000 : combase!CComActivator::DoCreateInstance+0x147
000000010060f880 00007ffb4c4246ff : 0000000000000000 0000000000000000 000000010060fa50 00000000000001b0 : combase!CoCreateInstance+0x19c
000000010060f910 00007ffb4c423d95 : 00000000000001b0 00000000000001b0 0000000000000000 0000000000000000 : udwm!CDesktopManager::InitializeComObjects+0x53
000000010060f950 00007ffb512e8102 : 0000000000000000 00007ffb4c423c90 00000000000001b0 0000000000000000 : udwm!CDesktopManager::DwmEventThreadProc+0x105
000000010060fa90 00007ffb519bc5b4 : 00007ffb512e80e0 0000000000000000 0000000000000000 0000000000000000 : KERNEL32!BaseThreadInitThunk+0x22
000000010060fac0 0000000000000000 : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : ntdll!RtlUserThreadStart+0x34

FOLLOWUP_IP:
PDRDrv64!PDRDrvFastIoQueryStandardInfo+66 [u:\PDRdrv\PDRdrv.c @ 783]
fffff800`4af2be46 488b4908 mov rcx,qword ptr [rcx+8]

FAULTING_SOURCE_LINE: u:\PDRdrv\PDRdrv.c

FAULTING_SOURCE_FILE: u:\PDRdrv\PDRdrv.c

FAULTING_SOURCE_LINE_NUMBER: 783

SYMBOL_STACK_INDEX: 0

SYMBOL_NAME: PDRDrv64!PDRDrvFastIoQueryStandardInfo+66

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: PDRDrv64

IMAGE_NAME: PDRDrv64.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 57ab4986

STACK_COMMAND: .cxr 0xffffd0010dbb0920 ; kb

BUCKET_ID_FUNC_OFFSET: 66

FAILURE_BUCKET_ID: 0x3B_PDRDrv64!PDRDrvFastIoQueryStandardInfo

BUCKET_ID: 0x3B_PDRDrv64!PDRDrvFastIoQueryStandardInfo

Followup: MachineOwner

IoAttachDeviceToDeviceStackSafe() is there to eliminate a race where the
DO is not updated before the driver begins receiving requests, as
indicated in the documentation.

You can start receiving requests before the API returns but the
AttachedToDeviceObject should be populated already. Can you send a code
snippet of where you call this routine?

FYI - Get away from legacy filters …

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

------ Original Message ------
From: xxxxx@gmail.com
To: “Windows File Systems Devs Interest List”
Sent: 8/19/2016 1:04:16 PM
Subject: [ntfsd] Legacy Filter Driver FastIO Bugcheck 0x3B

>Our driver has been used for many years now but we are now finding that
>on some platforms we get a bugcheck 3B in our FastIoQueryStandardInfo
>dispatch routine.
>
>Looking at the crash dump, at the point where the crash occurs all of
>our data seems fine ie. the DeviceObject pointer passed in points to
>one of our DeviceObjects, our device extension points ok to the
>attached DeviceObject and its DriverObject pointer points to a valid
>DriverObject which contains a valid FastIODispatch pointer that we are
>trying to pass the fastio request on to. The code leading up to the
>crash is shown below…
>
>1. mov r13,rcx
>2. je PDRDrv64!PDRDrvFastIoQueryStandardInfo+0xca
>(fffff8004af2beaa)<br>&gt;3. mov rdi,qword ptr [rdi+40h]<br>&gt;4. lea edx,[rbx+8]<br>&gt;5. mov rcx,rdi<br>&gt;6. call PDRDrv64!PDRProbeForRead (fffff8004af214fc)
>7. cmp al,bl
>8. je PDRDrv64!PDRDrvFastIoQueryStandardInfo+0xe5
>(fffff8004af2bec5)<br>&gt;9. mov rcx,qword ptr [rdi+8]<br>&gt;10. lea edx,[rbx+8]<br>&gt;11. call PDRDrv64!PDRProbeForRead (fffff8004af214fc)
>12. cmp al,bl
>13. je PDRDrv64!PDRDrvFastIoQueryStandardInfo+0xe5
>(fffff800`4af2bec5)
>14. mov rcx,qword ptr [rdi+8]
>15. lea edx,[rbx+8]
>16. mov rcx,qword ptr [rcx+8] <– Crash here
>
>The dump shows …
>
>- Crash occuring at line 16 due to rcx being 00000000’00000000.
>- At this time of crash, rdi contained ffffe00081423ce0.
>
>So, for rcx to be 0 then qword ptr [rdi+8] (ie ffffe00081423ce8) must
>have contained 0 when line 14 executed.
>
>However, when the crash occurred at line 16, ffffe00081423ce8 contained
>ffffe0007e4c1b70 which is a valid pointer to the DeviceObject I would
>expect it to point to since ffffe00081423ce8 is the field in our device
>extension structure which holds the address of the DeviceObject we have
>attached to.
>
>I attach to any newly mounted files systems using
>IoAttachDeviceToDeviceStackSafe and passing in the address of the field
>in my device extension which holds the attached device object as the
>third parameter.
>
>So, my question is, how could I even be in one of my drivers fastio
>routine before my device extension structure has received the address
>of the DeviceObject it is hooked up to ?
>
>Any help greatly appreciated.
>
>
>—
>NTFSD is sponsored by OSR
>
>
>MONTHLY seminars on crash dump analysis, WDF, Windows internals and
>software drivers!
>Details at http:
>
>To unsubscribe, visit the List Server section of OSR Online at
>http:</http:></http:>

When I see a mystery like CPU architectural registers changing in the middle of a code flow I always look at calls made prior and check that I don’t forget to check for STATUS_PENDING and wait for operation completion.

Some function parameters are placed on the stack by a caller. For example

FooA(_in HANDLE FileHandle )
// FileHandle is created without FILE_SYNCHRONOUS
* flags
{
IO_STATUS_BLOCK IoStatus;
NTSTATUS RC;

RC = ZwReadFile( Handle,…, &IoStatus, … );
// there is no check for STATUS_PENDING
return RC;
}

Imagine that file system driver(FSD) uses a separate thread for asynchronous processing and returns STATUS_PENDING if File Object was not opened for synchronous access and FooA() fails to check for it.

ZwReadFile returns STATUS_PENDING. When the caller FooA() returns the stack is freed ( by moving a stack pointer up, i.e. add RSP, 0xXXXXX ). After that another function FooB is called by the same thread and it reuses the same stack addresses( by moving a stack pointer down, i.e. sub RSP, 0xXXXXX ), the file system driver in the meantime holds an address of Status variable pointing on the same stack as it has not finished with read request.

This is what happens next - an interrupt is fired and CPU switches to ISR after line 14 commits ( i.e. RCX has a correct value, this value is placed in the CPU register). At the end of interrupt processing the kernel calls the thread scheduler that pushes all registers on the stack. It happens that RCX is pushed at the same address with IoStatus.Status from function FooA.

Then a thread switching occurs and CPU is switched to a FSD thread that completes the request from FooA() and sets IoStatus->Status to STATUS_SUCCESS( i.e 0x0 ) but &IoStatus->Status is the same address where RCX value was pushed by the Scheduler.

When the thread resumes its execution inside FooB() it popes RCX back from the stack and it happens to have a value set by FSD read completion for IoStatus->Status.

FooB()
{
14. mov rcx,qword ptr [rdi+8]
<<< here interrupt happens and a scheduler is called on return from an interrupt
Scheduler(){
Saving CPU registers on the stack

push RCX <– at the same address with &IoStatus.Status from FooA()

Switching to another thread, which is an FSD thread completing read request from FooA()
FsdCompleteRead {
IoStatus->Status = STATUS_SUCCESS;
}
Switching back to the thread executing FooB, restoring CPU registers from the stack

pop RCX <– now RCX has a value of IoStatus->Status
}
<<<
15. lea edx,[rbx+8]
16. mov rcx,qword ptr [rcx+8] <– Crash here
}

Pete & Slava, thanks for the replies.

Pete, conversion to mini-filter is high on my todo list, especially as I believe the next Windows10 update may prevent them loading at all.

There is one instance in my driver where I call IoAttachDeviceToDeviceStackSafe but do not pass the address of the structure member in my device extension to receive the address of the DeviceObject i’ve attached to. I actualy get the address back into a local variable and assign to my device extensoin later on. So, i’ve made some changes in this area and hopefully this will fix it.

Once again, thanks for the help,
Paolo.