Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting... Please check out the Community Guidelines in the
Announcements and Administration Category, below.

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 @ fffff800`00ba2e70)
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 @ fffff880`070cd5f0)
0e nt!KiServiceLinkage
0f fltmgr!FltpIoGetDeviceObjectPointer+0x72
10 fltmgr!FltpGetVolumeFromName+0x47
=> "\Device\HarddiskVolume2" is passed to FltGetVolumeFromName().
11 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName = 0xfffff880`070cdb98, struct _FLT_VOLUME ** pVolume = 0xfffff880`070cd9f8)+0x124
12 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName = 0xfffff880`070cdb98)+0x21
13 MyFlt!Open(struct _UNICODE_STRING * pFileName = 0xfffff880`070cdb98, unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880`070cdbc0, struct _FILE_OBJECT ** ppFileObject = 0xfffff880`070cdba8)+0x85
14 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName = 0xfffff880`070cdb98, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880`070cdbc0, struct _FILE_OBJECT ** ppFileObject = 0xfffff880`070cdba8)+0x3a
=> "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to MyFlt!OpenFile()
15 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA * pData = 0xfffffa83`045ef9e0)+0x16d
16 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData = 0xfffffa83`045ef9e0, struct _FLT_RELATED_OBJECTS * pFltObjects = 0xfffff880`070cddb8, void ** ppCompletionContext = 0xfffff880`070cdca8)+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 @ fffff880`070ce3f0)
20 nt!KiServiceLinkage
21 fltmgr!FltpIoGetDeviceObjectPointer+0x72
22 fltmgr!FltpGetVolumeFromName+0x47
=> "\Device\HarddiskVolume2" is passed to FltGetVolumeFromName().
23 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName = 0xfffff880`070ce998, struct _FLT_VOLUME ** pVolume = 0xfffff880`070ce7f8)+0x124
24 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName = 0xfffff880`070ce998)+0x21
25 MyFlt!Open(struct _UNICODE_STRING * pFileName = 0xfffff880`070ce998, unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880`070ce9c0, struct _FILE_OBJECT ** ppFileObject = 0xfffff880`070ce9a8)+0x85
26 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName = 0xfffff880`070ce998, unsigned long desiredAccess = 0, void ** hFile = 0xfffff880`070ce9c0, struct _FILE_OBJECT ** ppFileObject = 0xfffff880`070ce9a8)+0x3a
=> I.e. "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to MyFlt!OpenFile()
27 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA * pData = 0xfffffa83`0702e420)+0x16d
28 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData = 0xfffffa83`0702e420, struct _FLT_RELATED_OBJECTS * pFltObjects = 0xfffff880`070cebb8, void ** ppCompletionContext = 0xfffff880`070ceaa8)+0x7d
...

How can I fix this problem?

Thanks,
Michael

Comments

  • Gabriel_BerceaGabriel_Bercea Posts: 464
    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 @ fffff800`00ba2e70)
    > 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 @ fffff880`070cd5f0)
    > 0e nt!KiServiceLinkage
    > 0f fltmgr!FltpIoGetDeviceObjectPointer+0x72
    > 10 fltmgr!FltpGetVolumeFromName+0x47
    > => "\Device\HarddiskVolume2" is passed to FltGetVolumeFromName().
    > 11 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName =
    > 0xfffff880`070cdb98, struct _FLT_VOLUME ** pVolume =
    > 0xfffff880`070cd9f8)+0x124
    > 12 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName =
    > 0xfffff880`070cdb98)+0x21
    > 13 MyFlt!Open(struct _UNICODE_STRING * pFileName = 0xfffff880`070cdb98,
    > unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void
    > ** hFile = 0xfffff880`070cdbc0, struct _FILE_OBJECT ** ppFileObject =
    > 0xfffff880`070cdba8)+0x85
    > 14 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName =
    > 0xfffff880`070cdb98, unsigned long desiredAccess = 0, void ** hFile =
    > 0xfffff880`070cdbc0, struct _FILE_OBJECT ** ppFileObject =
    > 0xfffff880`070cdba8)+0x3a
    > => "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to
    > MyFlt!OpenFile()
    > 15 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA * pData =
    > 0xfffffa83`045ef9e0)+0x16d
    > 16 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData =
    > 0xfffffa83`045ef9e0, struct _FLT_RELATED_OBJECTS * pFltObjects =
    > 0xfffff880`070cddb8, void ** ppCompletionContext = 0xfffff880`070cdca8)+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 @ fffff880`070ce3f0)
    > 20 nt!KiServiceLinkage
    > 21 fltmgr!FltpIoGetDeviceObjectPointer+0x72
    > 22 fltmgr!FltpGetVolumeFromName+0x47
    > => "\Device\HarddiskVolume2" is passed to FltGetVolumeFromName().
    > 23 MyFlt!GetVolumeFromName(struct _UNICODE_STRING * pFileName =
    > 0xfffff880`070ce998, struct _FLT_VOLUME ** pVolume =
    > 0xfffff880`070ce7f8)+0x124
    > 24 MyFlt!GetInstanceFromName(struct _UNICODE_STRING * pFileName =
    > 0xfffff880`070ce998)+0x21
    > 25 MyFlt!Open(struct _UNICODE_STRING * pFileName = 0xfffff880`070ce998,
    > unsigned long createOptions = 0x860, unsigned long desiredAccess = 0, void
    > ** hFile = 0xfffff880`070ce9c0, struct _FILE_OBJECT ** ppFileObject =
    > 0xfffff880`070ce9a8)+0x85
    > 26 MyFlt!OpenFile(struct _UNICODE_STRING * pFileName =
    > 0xfffff880`070ce998, unsigned long desiredAccess = 0, void ** hFile =
    > 0xfffff880`070ce9c0, struct _FILE_OBJECT ** ppFileObject =
    > 0xfffff880`070ce9a8)+0x3a
    > => I.e. "\Device\HarddiskVolume2\Windows\System32\net1.exe" is passed to
    > MyFlt!OpenFile()
    > 27 MyFlt!GetIoProcess(struct _FLT_CALLBACK_DATA * pData =
    > 0xfffffa83`0702e420)+0x16d
    > 28 MyFlt!PreCreate(struct _FLT_CALLBACK_DATA * pData =
    > 0xfffffa83`0702e420, struct _FLT_RELATED_OBJECTS * pFltObjects =
    > 0xfffff880`070cebb8, 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
    >
    > To unsubscribe, visit the List Server section of OSR Online at <
    > http://www.osronline.com/page.cfm?name=ListServer>;
    >

    Cheers,
    Gabriel

  • 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
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!