why the paging Read go direct FSD(skip the minifilter)?

I observed one problem…
An av-anti software with a minifilter.
It will get fsd driver’s dispatch table,So it get the FsdRead func address.’
It will call NtCreateFile(…file_open_no_intermedia…),and call fsd driver’s FsdRead(skip all filter).
But,when it call FsdRead,the call stack is:

Child-SP RetAddr Call Site
fffff88003897ec0 fffff80003ea2439 fastfat!FatFsdRead(struct _VOLUME_DEVICE_OBJECT * VolumeDeviceObject = 0xfffffa801a40f6f0, struct _IRP * Irp = 0xfffffa801c913480)+0x2e [e:\winddk\7600.16385.1\src\filesys\fastfat\win7\read.c @ 164]
fffff88003897f50 fffff8000411589f nt!IoPageRead+0x2a9
fffff88003897fe0 fffff80004115999 nt!MiPfExecuteReadList+0xff
fffff88003898040 fffff80003e69473 nt!MmPrefetchForCacheManager+0xb5
fffff88003898090 fffff80004166e90 nt!CcFetchDataForRead+0xd3
fffff880038980f0 fffff88005b7d0c7 nt!CcCopyRead+0x180
fffff880038981b0 fffff88005b37e63 fastfat!FatCommonRead(struct _IRP_CONTEXT * IrpContext = 0xfffffa8019966c30, struct _IRP * Irp = 0xfffffa801c6d9010)+0x1297 [e:\winddk\7600.16385.1\src\filesys\fastfat\win7\read.c @ 1372]
fffff88003898340 fffff88004e7794c fastfat!FatFsdRead(struct _VOLUME_DEVICE_OBJECT * VolumeDeviceObject = 0xfffffa801a40f6f0, struct _IRP * Irp = 0xfffffa801c6d9010)+0x1e3 [e:\winddk\7600.16385.1\src\filesys\fastfat\win7\read.c @ 243]
fffff880038983d0 fffff88004e74f76 TSSysKit64+0x894c
fffff880038984f0 fffff88004e7097a TSSysKit64+0x5f76
fffff880038986b0 fffff80004187e4a TSSysKit64+0x197a
fffff88003898850 fffff8000419c36c nt!IopSynchronousServiceTail+0xfa
fffff880038988c0 fffff8000419c406 nt!IopXxxControlFile+0xc49
fffff88003898a00 fffff80003e790d3 nt!NtDeviceIoControlFile+0x56
fffff88003898a70 0000000074aa2e09 nt!KiSystemServiceCopyEnd+0x13
0000000005dbeef8 0000000074aa2944 wow64cpu!CpupSyscallStub+0x9
0000000005dbef00 0000000074b1d286 wow64cpu!DeviceIoctlFileFault+0x31
0000000005dbefc0 0000000074b1c69e wow64!RunCpuSimulation+0xa
0000000005dbf010 00000000770398ec wow64!Wow64LdrpInitialize+0x42a
0000000005dbf560 0000000076ffa36e ntdll! ?? ::FNODOBFM::string'+0x22b74 0000000005dbf5d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

My question is:
why nt!IoPageRead call fastfat!FatFsdRead directly?why it will skip all filter?
In my mind,the cached read will issue the paging IO,and the Paging read will call the filter stack and fsd,right?

The not exhaustive list of possible scenarios are as follows

  • the AV driver/minifilter calls IoCreateFileSpecifyDeviceObjectHint with a DeviceObject hint set to the bottom of the FSD stack, the created file object is used by the Memory Manager to back data section, in that case the IO Manager skips all attached device objects ( including minifilters ) when dispatching paging IO ( this happens in a call to IoGetRelatedDeviceObject when preparing an IRP for paging IO )

  • the data section is backed by a file object opened with IoCreateFileSpecifyDeviceObjectHint as described above by somebody else ( not the AV driver/minifilter ), the Memory Manager issues paging read requests to a file object which was used to initialise structures supporting file mapping ( i.e. data section ) and this file object might not be the file object used by the AV driver/minifilter for cached data IO

  • the FilterManager failed to attach a minifilter device object to the FSD stack

oh shit…the av-anti software(TSSysKit64)…just call FsdCreate directly!
kd> k
Child-SP RetAddr Call Site
fffff88003924a60 fffff88005af3d27 fastfat!FatCommonCreate+0x23b5 [e:\winddk\7600.16385.1\src\filesys\fastfat\win7\create.c @ 1750]
fffff88003925040 fffff800041cf2bb fastfat!FatFsdCreate+0xb7 [e:\winddk\7600.16385.1\src\filesys\fastfat\win7\create.c @ 322]
fffff88003925090 fffff800041cadde nt!IopParseDevice+0x14e2
fffff880039251f0 fffff800041cb8c6 nt!ObpLookupObjectName+0x784
fffff880039252f0 fffff880053a66c0 nt!ObOpenObjectByName+0x306
fffff880039253c0 fffff880053a5e77 TSSysKit64+0x26c0
fffff88003925460 fffff880053aab74 TSSysKit64+0x1e77
fffff880039254f0 fffff880053a597a TSSysKit64+0x6b74
fffff880039256b0 fffff800041d8e4a TSSysKit64+0x197a
fffff88003925850 fffff800041ed36c nt!IopSynchronousServiceTail+0xfa
fffff880039258c0 fffff800041ed406 nt!IopXxxControlFile+0xc49
fffff88003925a00 fffff80003eca0d3 nt!NtDeviceIoControlFile+0x56
fffff88003925a70 0000000074882e09 nt!KiSystemServiceCopyEnd+0x13
0000000004dde9f8 0000000074882944 wow64cpu!CpupSyscallStub+0x9
0000000004ddea00 00000000748fd286 wow64cpu!DeviceIoctlFileFault+0x31
0000000004ddeac0 00000000748fc69e wow64!RunCpuSimulation+0xa
0000000004ddeb10 0000000076e198ec wow64!Wow64LdrpInitialize+0x42a
0000000004ddf060 0000000076dda36e ntdll! ?? ::FNODOBFM::string'+0x22b74 0000000004ddf0d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe

kd> dt _FILE_OBJECT 0xfffffa80196a2880 ntdll!_FILE_OBJECT +0x000 Type : 5 +0x002 Size : 0xd8 +0x008 DeviceObject : 0xfffffa8019c1fcd0 _DEVICE_OBJECT
+0x010 Vpb : 0xfffffa8019805990 _VPB +0x018 FsContext : 0xfffff8a000622320 Void
+0x020 FsContext2 : 0xfffff8a006788cb0 Void +0x028 SectionObjectPointer : 0xfffffa801a214710 _SECTION_OBJECT_POINTERS
+0x030 PrivateCacheMap : (null)
+0x038 FinalStatus : 0
+0x040 RelatedFileObject : (null)
+0x048 LockOperation : 0 ‘’
+0x049 DeletePending : 0 ‘’
+0x04a ReadAccess : 0 ‘’
+0x04b WriteAccess : 0 ‘’
+0x04c DeleteAccess : 0 ‘’
+0x04d SharedRead : 0 ‘’
+0x04e SharedWrite : 0 ‘’
+0x04f SharedDelete : 0 ‘’
+0x050 Flags : 0x42
+0x058 FileName : _UNICODE_STRING “\test\test.docx”
+0x068 CurrentByteOffset : _LARGE_INTEGER 0x0
+0x070 Waiters : 0
+0x074 Busy : 0
+0x078 LastLock : (null)
+0x080 Lock : _KEVENT
+0x098 Event : _KEVENT
+0x0b0 CompletionContext : (null)
+0x0b8 IrpListLock : 0
+0x0c0 IrpList : _LIST_ENTRY [0xfffffa80196a2940 - 0xfffffa80196a2940]
+0x0d0 FileObjectExtension : 0xfffffa80`192bd4c0 Void

kd> dt _VPB 0xfffffa8019805990 ntdll!_VPB +0x000 Type : 0xa +0x002 Size : 0x60 +0x004 Flags : 1 +0x006 VolumeLabelLength : 6 +0x008 DeviceObject : 0xfffffa801aaa1970 _DEVICE_OBJECT
+0x010 RealDevice : 0xfffffa80`19c1fcd0 _DEVICE_OBJECT
+0x018 SerialNumber : 0xaa43f7f
+0x01c ReferenceCount : 0x10
+0x020 VolumeLabel : [32] “???”

kd> !devstack 0xfffffa80`1aaa1970
!DevObj !DrvObj !DevExt ObjectName
fffffa801aab09a0 \FileSystem\FltMgr fffffa801aab0af0

fffffa801aaa1970 \FileSystem\fastfatfffffa801aaa1ac0
kd> !devstack 0xfffffa80`19c1fcd0
!DevObj !DrvObj !DevExt ObjectName
fffffa8019c27340 \Driver\volsnap fffffa8019c27490
fffffa8019c25770 \Driver\rdyboost fffffa8019c258c0
fffffa8019c25b70 \Driver\fvevol fffffa8019c25cc0
fffffa8019c1fcd0 \Driver\volmgr fffffa8019c1fe20 HarddiskVolume2
!DevNode fffffa8019c1f290 :
DeviceInst is “STORAGE\Volume{cba9e03f-c52f-11e7-8054-806e6f6e6963}#0000000000010000
ServiceName is “volsnap”

Nope. The AV driver uses a call to ObOpenObjectByName and it provides a TopDeviceObjectHint as a parameter. This is analogues to calling IoCreateFileSpecifyDeviceObjectHint which also calls ObOpenObjectByName with OpenPacket->TopDeviceObjectHint. For unknown reasons the AV developer decided to use an undocumented ObOpenObjectByName instead of IoCreateFileSpecifyDeviceObjectHint which is effectively a wrapper for ObOpenObjectByName. IoCreateFileSpecifyDeviceObjectHint verifies input parameters and calls ObOpenObjectByName.

This case is the first scenario in the above list, just replace IoCreateFileSpecifyDeviceObjectHint with ObOpenObjectByName