Minifilter related queries

Hi All,

Is it right way to check the FO_CLEANUP_COMPLETE of file object to identify whether the cleanup for file is called or not?
Can we call FltGetStreamHandleContext() on such(FO_CLEANUP_COMPLETE is set) file objects in write callback?(write can occur after cleanup for memory mapped files)

Regards,
Rajendra.

It certainly works. Of course, the question has subtleties.

Just keep in mind that between cleanup and close the only operations on a file object (other than IRP_MJ_CLOSE) must have the IRP_PAGING_IO bit set. That’s because nobody other than the VM system (Mm, Cc) should be doing I/O to that file - cleanup represents teardown of the “user mode” state of the given file object. That means no cached I/O (for example).

With that said, some operations might work (non-cached read/write probably will work) due to vagaries of the implementation.

Absolutely. Until the file object is torn down (IRP_MJ_CLOSE) the context information is still present.

Note that you can’t obtain stream handle context information in post close.

Tony
OSR

Hi All,

Thanks Tony for reply.

We are using the flag FO_CLEANUP_COMPLETE in Write callback to check whether the cleanup for object is called or not.

With reference to: https://www.osronline.com/ShowThread.cfm?link=215792
[Comment from Alex Carp]

In other
words, if there is a mapping and nothing gets written but some of the pages are
marked dirty you’ll still see paging writes.
What will be the case in which this will happen?

In our minifilter, we are also monitoring the file modification(including memory mapped files).
We have written a test application which executes following steps on sample file test.exe.
hFile = CreateFile()
hFileMapping = CreateFileMapping()
Close(hFile)------------------> Will result in cleanup
MapViewOfFile()
memcpy()
UnMapViewOfFile() ------------> Will result in write callback in minifilter
Close(hFileMapping)

If we execute 2(or more) instance of above application simultaneously, write callback corresponding to UnMapViewOfFile() gets called in system process context and
if we call FltGetStreamHandleContext(), it returns the same context in for both write callback.

Is it possible that the context returned in write callback will be same if files are memory mapped?

Thanks,
Rajendra

I’d be shocked if you didn’t. Remember, the stream handle context corresponds to the specific open instance (the “file object”) and since all paging I/O is being done against the same file object, it should return the same stream context.

Tony
OSR

Thanks Tony for reply.

So, for my test application with multiple instance running simultaneously, what I understand is:
hFile = CreateFile()------------------> File object will be different and hence stream handle context set in post create will be different.
hFileMapping = CreateFileMapping()----> If file is already mapped it will just point/reference to already backing file object.
Close(hFile)------------------> Will result in cleanup; Cleanup will be for different file objects and hence different stream handle context.
MapViewOfFile()
memcpy()
UnMapViewOfFile() ------------> Will result in write callback in minifilter; All write for memory mapped section will be on same file object and hence we will get same stream handle context.
Close(hFileMapping)

Is my understanding correct?

Regards,
Rajendra.

Yes, that’s correct.

I have this diagram I use in my FS development class that demonstrates this point well. Basically it shows that there’s a (hidden) pointer to the file object from the specific section object. So all paging I/O activity is done against that file object.

In the most extreme case, you can actually find *three* different file objects referenced: one by the Data Section Object, one by the Image Section Object and then one by the Cache Manager.

Getting to this requires that you map the file (as data) before you do cached I/O to it:

(1) Open file X twice so you have H1 and H2 (which correspond to FO1 and FO2)
(2) Map the file via H1 - this will cause Mm to create a new section object (via DataSectionObject) and back it by FO1
(3) Read the file via H2 - this will cause the FSD to set up caching using FO2, so the shared cache map will point to FO2

At some point when the file is closed (before or after these other sequences) you then execute the file - this causes an open/map via the ImageSectionObject (backed by a third file object, FO3)

So DataSectionObject points to FO1
SharedCacheMap points to FO2
ImageSectionObject points to FO3

That’s the “worst case” scenario.

Tony
OSR

Thanks Tony for exploring more details…!

We will monitor the fields in debugger.
lkd> dt nt!_FILE_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Vpb : Ptr32 _VPB
+0x00c FsContext : Ptr32 Void
+0x010 FsContext2 : Ptr32 Void
+0x014 SectionObjectPointer : Ptr32 _SECTION_OBJECT_POINTERS
+0x018 PrivateCacheMap : Ptr32 Void

lkd> dt nt!_SECTION_OBJECT_POINTERS
+0x000 DataSectionObject : Ptr32 Void
+0x004 SharedCacheMap : Ptr32 Void
+0x008 ImageSectionObject : Ptr32 Void