GetVolumeFromName reenters file system stack

My mini filter is attached to some but not all volumes. In pre-create I sometimes have to gather information about the I/O requestor process? underlying .exe file. I get the process? image name and try to open the file. To prevent reentrancy I?d like to use one of the FltCreateFile() calls with the correct filter instance pointer (if I’m attached). As the .exe?s volume/instance may differ from the one in the pre-create I?m in, I cannot simply use ?pFltObjects->Instance?. Instead I extract the volume name from the exe name and call FltGetVolumeFromName(), then FltGetVolumeInstanceFromName() to get the instance to use in FltCreateFile(). Unfortunately FltGetVolumeFromName() seems to reenter the file system stack and my pre-create is called again. Below is an example of the last 2 recursions. In this example my mini filter is attached to “\Device\HarddiskVolume2”.

00 nt!DbgBreakPointWithStatus
01 nt!KiBugCheckDebugBreak+0x12
02 nt!KeBugCheck2+0x71e
03 nt!KeBugCheckEx+0x104
04 nt!KiBugCheckDispatch+0x69
05 nt!KiDoubleFaultAbort+0xb2 (TrapFrame @ fffff80000ba2e70) 06 nt!ObpAllocateObject+0x12a 07 nt!IopAllocRealFileObject+0xf0 08 nt!IopParseDevice+0xf9f 09 nt!ObpLookupObjectName+0x784 0a nt!ObOpenObjectByName+0x306 0b nt!IopCreateFile+0x2bc 0c nt!NtCreateFile+0x78 0d nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880070cd5f0)
0e nt!KiServiceLinkage
0f fltmgr!FltpIoGetDeviceObjectPointer+0x72
10 fltmgr!FltpGetVolumeFromName+0x47
=> “\Device\HarddiskVolume2” is passed to FltGetVolumeFromName().
11 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName = 0xfffff880070cdb98, struct _FLT_VOLUME ** pVolume = 0xfffff880070cd9f8)+0x124
12 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName = 0xfffff880070cdb98)+0x21 13 MyFlt!Open(struct _UNICODE_STRING \* pFileName = 0xfffff880070cdb98, unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880070cdbc0, struct _FILE_OBJECT \*\* ppFileObject = 0xfffff880070cdba8)+0x85
14 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName = 0xfffff880070cdb98, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880070cdbc0, struct _FILE_OBJECT ** ppFileObject = 0xfffff880070cdba8)+0x3a =\> "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to MyFlt!OpenFile() 15 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA \* pData = 0xfffffa83045ef9e0)+0x16d
16 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData = 0xfffffa83045ef9e0, struct _FLT_RELATED_OBJECTS * pFltObjects = 0xfffff880070cddb8, void ** ppCompletionContext = 0xfffff880070cdca8)+0x7d 17 fltmgr!FltpPerformPreCallbacks+0x2f7 18 fltmgr!FltpPassThroughInternal+0x4a 19 fltmgr!FltpCreate+0x293 1a nt!IopParseDevice+0x14e2 1b nt!ObpLookupObjectName+0x784 1c nt!ObOpenObjectByName+0x306 1d nt!IopCreateFile+0x2bc 1e nt!NtCreateFile+0x78 1f nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880070ce3f0)
20 nt!KiServiceLinkage
21 fltmgr!FltpIoGetDeviceObjectPointer+0x72
22 fltmgr!FltpGetVolumeFromName+0x47
=> “\Device\HarddiskVolume2” is passed to FltGetVolumeFromName().
23 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName = 0xfffff880070ce998, struct _FLT_VOLUME ** pVolume = 0xfffff880070ce7f8)+0x124
24 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName = 0xfffff880070ce998)+0x21 25 MyFlt!Open(struct _UNICODE_STRING \* pFileName = 0xfffff880070ce998, unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880070ce9c0, struct _FILE_OBJECT \*\* ppFileObject = 0xfffff880070ce9a8)+0x85
26 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName = 0xfffff880070ce998, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880070ce9c0, struct _FILE_OBJECT ** ppFileObject = 0xfffff880070ce9a8)+0x3a =\> I.e. "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to MyFlt!OpenFile() 27 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA \* pData = 0xfffffa830702e420)+0x16d
28 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData = 0xfffffa830702e420, struct _FLT_RELATED_OBJECTS * pFltObjects = 0xfffff880070cebb8, void ** ppCompletionContext = 0xfffff880`070ceaa8)+0x7d

How can I fix this problem?

Thanks,
Michael

There are a couple of ways to overcome this.
You could already have info about your process image, by for example have a
registered process notify routine and setup all the information over there,
and then in your Create just lookup you process and use the info.
There is also the possibility to use your own custom ECP to avoid
re-entrancy. Use this ECP in all you FltCreate calls. In the Create
callback just check if your ECP is there and simply ignore that Create.
Another way would simply be to have a small list of thread IDs that are
“excepted” from filtering. Add the current thread to the list before
calling the Flt API and check your thread except list in Create and skip if
the thread is present in the list. Remove the thread after the Flt call.
But you should try to avoid as much as possible filtering in Pre Create and
also you should use the existing file objects add much as possible.
The right approach in my book is that by the time a process issues a Create
you should have the information about that process stashed somewhere and if
should be as easy as querying it from an internal list.

Good luck,
Gabriel
www.kasardia.com

On Tue, Mar 6, 2018, 01:14 xxxxx@segira.com wrote:

> My mini filter is attached to some but not all volumes. In pre-create I
> sometimes have to gather information about the I/O requestor process?
> underlying .exe file. I get the process? image name and try to open the
> file. To prevent reentrancy I?d like to use one of the FltCreateFile()
> calls with the correct filter instance pointer (if I’m attached). As the
> .exe?s volume/instance may differ from the one in the pre-create I?m in, I
> cannot simply use ?pFltObjects->Instance?. Instead I extract the volume
> name from the exe name and call FltGetVolumeFromName(), then
> FltGetVolumeInstanceFromName() to get the instance to use in
> FltCreateFile(). Unfortunately FltGetVolumeFromName() seems to reenter the
> file system stack and my pre-create is called again. Below is an example of
> the last 2 recursions. In this example my mini filter is attached to
> “\Device\HarddiskVolume2”.
>
> 00 nt!DbgBreakPointWithStatus
> 01 nt!KiBugCheckDebugBreak+0x12
> 02 nt!KeBugCheck2+0x71e
> 03 nt!KeBugCheckEx+0x104
> 04 nt!KiBugCheckDispatch+0x69
> 05 nt!KiDoubleFaultAbort+0xb2 (TrapFrame @ fffff80000ba2e70)<br>&gt; 06 nt!ObpAllocateObject+0x12a<br>&gt; 07 nt!IopAllocRealFileObject+0xf0<br>&gt; 08 nt!IopParseDevice+0xf9f<br>&gt; 09 nt!ObpLookupObjectName+0x784<br>&gt; 0a nt!ObOpenObjectByName+0x306<br>&gt; 0b nt!IopCreateFile+0x2bc<br>&gt; 0c nt!NtCreateFile+0x78<br>&gt; 0d nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880070cd5f0)
> 0e nt!KiServiceLinkage
> 0f fltmgr!FltpIoGetDeviceObjectPointer+0x72
> 10 fltmgr!FltpGetVolumeFromName+0x47
> => “\Device\HarddiskVolume2” is passed to FltGetVolumeFromName().
> 11 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName =
> 0xfffff880070cdb98, struct _FLT_VOLUME **pVolume =<br>&gt; 0xfffff880070cd9f8)+0x124
> 12 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName =
> 0xfffff880070cdb98)+0x21<br>&gt; 13 MyFlt!Open(struct _UNICODE_STRING * pFileName = 0xfffff880070cdb98,
> unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void
>** hFile = 0xfffff880070cdbc0, struct _FILE_OBJECT **ppFileObject =<br>&gt; 0xfffff880070cdba8)+0x85
> 14 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName =
> 0xfffff880070cdb98, unsigned long desiredAccess = 0, void** hFile =<br>&gt; 0xfffff880070cdbc0, struct _FILE_OBJECT ppFileObject =
> 0xfffff880070cdba8)+0x3a<br>&gt; =&gt; "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to<br>&gt; MyFlt!OpenFile()<br>&gt; 15 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA * pData =<br>&gt; 0xfffffa83045ef9e0)+0x16d
> 16 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData =
> 0xfffffa83045ef9e0, struct _FLT_RELATED_OBJECTS * pFltObjects =<br>&gt; 0xfffff880070cddb8, void
ppCompletionContext = 0xfffff880070cdca8)+0x7d<br>&gt; 17 fltmgr!FltpPerformPreCallbacks+0x2f7<br>&gt; 18 fltmgr!FltpPassThroughInternal+0x4a<br>&gt; 19 fltmgr!FltpCreate+0x293<br>&gt; 1a nt!IopParseDevice+0x14e2<br>&gt; 1b nt!ObpLookupObjectName+0x784<br>&gt; 1c nt!ObOpenObjectByName+0x306<br>&gt; 1d nt!IopCreateFile+0x2bc<br>&gt; 1e nt!NtCreateFile+0x78<br>&gt; 1f nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880070ce3f0)
> 20 nt!KiServiceLinkage
> 21 fltmgr!FltpIoGetDeviceObjectPointer+0x72
> 22 fltmgr!FltpGetVolumeFromName+0x47
> => “\Device\HarddiskVolume2” is passed to FltGetVolumeFromName().
> 23 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName =
> 0xfffff880070ce998, struct _FLT_VOLUME **pVolume =<br>&gt; 0xfffff880070ce7f8)+0x124
> 24 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName =
> 0xfffff880070ce998)+0x21<br>&gt; 25 MyFlt!Open(struct _UNICODE_STRING * pFileName = 0xfffff880070ce998,
> unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void
>** hFile = 0xfffff880070ce9c0, struct _FILE_OBJECT **ppFileObject =<br>&gt; 0xfffff880070ce9a8)+0x85
> 26 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName =
> 0xfffff880070ce998, unsigned long desiredAccess = 0, void** hFile =<br>&gt; 0xfffff880070ce9c0, struct _FILE_OBJECT ppFileObject =
> 0xfffff880070ce9a8)+0x3a<br>&gt; =&gt; I.e. "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to<br>&gt; MyFlt!OpenFile()<br>&gt; 27 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA * pData =<br>&gt; 0xfffffa830702e420)+0x16d
> 28 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData =
> 0xfffffa830702e420, struct _FLT_RELATED_OBJECTS * pFltObjects =<br>&gt; 0xfffff880070cebb8, void
ppCompletionContext = 0xfffff880`070ceaa8)+0x7d
> …
>
> How can I fix this problem?
>
> Thanks,
> Michael
>
>
> —
> 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://www.osronline.com/page.cfm?name=ListServer&gt;
></http:>

Regarding reentrancy, I think it is difficult to be 100% sure that calling Fltxx functions will avoid it. Another driver below might start a new operation without using Fltxx function… On other paths such as pre-reads, calling FltRead might internally start another read operation, and reenter your pre-read…

> Regarding reentrancy, I think it is difficult to be 100% sure that calling

Fltxx functions will avoid it.

Until you’ve seen your filter at three (four if you are a name provider)
different places on the stack you are probably not done…

Thanks for all the good advice. Gabriel, I do in fact have a process notify routine set up. But my filter may be start at any time and I must be able to filter I/O from processes that are already running at that time and this is exactly when my problem occurred.

Anyway, you all made it clear that I have to deal with reentrancy, even if it’s not because of my own code.

Thanks a bunch,
Michael