Thursday, May 31, 2012

Using FileModeInformation

I've recently had to debug again how the system handles the FileModeInformation information class and whenever that happens (debugging something more than once) it's generally a good indication that I need to write a blog post, at least so that I don't have to debug yet again in the future. Incidentally, it's quite scary when I occasionally search for something and I discover that I have actually written a blog post about it but I've completely forgotten not only the information in the post but even the fact that I have written about it. I hope this explanation will come in quite handy at some point in the future when I'll actually write a blog post about something I've already blogged about :).

Anyway, on to business. FileModeInformation is an interesting information class because it can be used to query and set some of the create options that were used when the file was opened. Another reason why it is interesting is because it's completely handled in the IO manager (i.e. a request is never sent to the file system). Since this information class is also part of the FileAllInformation information class, the fact that the file system doesn't handle this leads to pretty interesting semantics (since the IO manager must fill in part of the FILE_ALL_INFORMATION structure while the file system fills in the rest). I've discussed this in my previous blog post on Filters And IRP_MJ_QUERY_INFORMATION.

Other than the specifics of implementing the FileAllInformation class in a filter, there are a couple of other aspects that I think are interesting to discuss about the FileModeInformation class.

  • Querying - the list of CreateOptions that can be queried using the FileModeInformation is limited to (the information is listed on the MSDN page 2.4.24 FileModeInformation):
    • FILE_WRITE_THROUGH
    • FILE_SEQUENTIAL_ONLY
    • FILE_NO_INTERMEDIATE_BUFFERING
    • FILE_SYNCHRONOUS_IO_ALERT
    • FILE_SYNCHRONOUS_IO_NONALERT
    • FILE_DELETE_ON_CLOSE - please note that the MSDN documentation states that this flag isn't implemented yet and is never returned as set. However, peeking at the implementation (do a uf nt!IopGetModeInformation) clearly shows that the FILE_DELETE_ON_CLOSE is set when the FILE_OBJECT flag FO_DELETE_ON_CLOSE is set. This is the only time I've actually seen FO_DELETE_ON_CLOSE used anywhere. I had tried a couple of times in the past to see where it gets set but could never find it (though obviously I couldn't rule out the possibility that it does get set somewhere). Now, looking at the implementation of IopGetModeInformation and at the documentation page I can draw the conclusion that this flag isn't actually set anywhere at all.
  • Setting - the list of attributes that can be set is even shorter. It is addressed in the MSDN page 3.1.5.14.7 FileModeInformation. One thing to note is that the list of attributes that can be set is also available as a bitmask in the WDK, as FILE_VALID_SET_FLAGS. Also the list of flags that can be set using FileModeInformation indicates which of these modes make sense to change for a file that has already been open (and possibly in use) for a while (in other words, flags that can change file system behavior at a certain point and not only when the file is opened; for example, setting the FILE_DELETE_ON_CLOSE attribute doesn't make sense once the file was opened so it's not available to set). Anyway, these are the attributes that can be changed using the FileModeInformation information class:
    • FILE_WRITE_THROUGH
    • FILE_SEQUENTIAL_ONLY
    • FILE_SYNCHRONOUS_IO_ALERT
    • FILE_SYNCHRONOUS_IO_NONALERT
  • Issuing these requests from a minifilter - this is a pretty interesting issue. The dedicated FltMgr APIs, FltQueryInformationFile and FltSetInformationFile do little else that to allocate a FLT_CALLBACK_DATA structure and send it to the file system. However, since the file system doesn't actually implement these requests it's impossible to use FileModeInformation with either FltQueryInformationFile or FltSetInformationFile (though a request will actually be sent). Since the actual implementation happens in the IO manager a filter could call the ZwQueryInformationFile and ZwSetInformationFile APIs but those require a handle for the FILE_OBJECT and filters don't often have that. So what can a file system filter do if it wants to query or set these flags ? As far as I can tell there are two options:
    1. The file system filter can implement the equivalent IO manager code (which is actually not that hard since the steps are documented pretty well on the MSDN page 3.1.5.14.7 FileModeInformation and the implementation for nt!IopGetModeInformation is pretty straightforward).
    2. The file system filter can call an undocumented API, IoSetInformation(), that is a pretty good replacement for ZwSetInformationFile(). Unfortunately I couldn't find a similar function for ZwQueryInformationFile() so filters would most likely have to resort to checking flags directly.