Verifier Checks: A filter has completed an operation but does not implement name provider callbacks
FILTER VERIFIER ERROR: A filter has completed an operation but does not implement name provider callbacks. For example if a filter completes an IRP_MJ_CREATE and is not a name provider it is possible that during name queries the FO will make it's way to the file system and bugcheck. (Filter = Xxx, Cbd = Xxx)
This is a new check in Win7 and I get a lot of questions about it. In order to understand what it means we should talk briefly about how FltGetFileNameInformation and friends work.
In order to normalize a file name Filter Manager will get a path to a file in a number of different ways, including by querying the file system for it, and then it will open directories on that path and query for long names. In order to optimize this as much as possible (as you can imagine this is rather time consuming… incidentally, a minifilter should use opened names where possible as the perf is better) the decision was made to implement a separate mechanism from the normal IO path. Minifilters that change the path in any way should implement some additional callbacks, which we refer to as “name provider callbacks” and filter manager will call those callbacks when it needs to generate and normalize a name. If a minifilter does implement those then it is called a name provider. The best part about this is that if a minifilter is not a name provider then it can stay out of the name resolution path completely. If none of the minifilters on a volume are name providers then filter manager can skip all of them when it tries to resolve a name and go directly to the driver below.
How does this tie into the verifier check above ? If filter manager sees a filter successfully complete any operation that might have an impact on the namespace (like a IRP_MJ_SET_INFORMATION with FileRenameInformation or FileLinkInformation or FileShortNameInformation and so on) then it expects that the minifilter implements the name provider callbacks as well. Now let’s say that the minifilter successfully completed a rename for file “A” to file “B”. If the minifilter in question does not implement name provider callbacks, filter manager will not even ask it for the name. It will go straight to the name provider below (or the file system) and it will get back the old name , “A”. This clearly breaks the abstraction that each filter must implement.
There is one more operation other than those that change names that is particularly important. If a minifilter successfully completes IRP_MJ_CREATE (in this particular case returning STATUS_REPARSE does not count as success) then the FILE_OBJECT should NEVER under any circumstances be seen below that minifilter (the file system will try to interpret the private fields in it as its own, which can lead to bugchecks or data corruption). So if a minifilter successfully completes a create but doesn’t implement name provider callbacks then name queries will bypass it completely and the FILE_OBJECT will be shown below.
So now that we explained all the context, let’s go into what’s allowed and what’s not:
- a minifilter can always fail any operation, including IRP_MJ_CREATE and IRP_MJ_SET_INFORMATION without implementing name provider callbacks. Also, completing an IRP_MJ_CREATE with STATUS_REPARSE counts as a failure in this context, even though STATUS_REPARSE is a success code.
- if a minifilter successfully completes an IRP_MJ_CREATE (excluding STATUS_REPARSE), even if it doesn’t change the name space at all (like an SFO (shadow file object) type of filter) it must still implement name provider callbacks, even if they do nothing and are only passthrough (meaning that they get the name from below by calling FltGetFileNameInformation and return it). This minifilter is called the owner of the FILE_OBJECT.
- if a minifilter implements any type of name space virtualization (which means that if there is any difference at all between the namespace above the minifilter and the namespace below the minifilter) then it must implement name provider callbacks and it must also implement (or at least make a conscious decision not to support some of the features) all the other name support operations, like directory enumeration, setting and querying short names, directory change notification, dile IDs, renames, hardlinks, reparse points and so on. This is true even if the minifilter does not own any file object (i.e. it never completes an IRP_MJ_CREATE but rather it just changes where files are on the file system).
- a minifilter should NEVER skip any portion of the IO stack because there is no way to know if the FILE_OBJECT it cares about belongs above or below the filter. For example, a minifilter should never take a FILE_OBJECT and do something like allocate an IRP and send it directly to the file system below, since it might bypass the owner of that FILE_OBJECT. A far more common scenario of this same behavior is a minifilter that receives a HANDLE from its user mode component and it calls ObReferenceObjectByHandle and then it call some FltXxx function with that FILE_OBJECT, without realizing that the owner of that FILE_OBJECT might be above itself.
I hope this makes sense. As always, if you have any questions please don’t hesitate to ask.
Comments
Anonymous
October 11, 2009
Hi Alex, I'm Royce Lu (from trend). We met in plugfest.Nice arcitle...much m ore detail than WDK document.Thanks for the sharing :)Anonymous
October 26, 2009
Thanks; this was clearly put.I note that "FSFilter Virtualization" altitudes are only defined in vista above, but I suppose that what you mention applies to XP too?Any news on when the virtualization example may be released?Anonymous
November 05, 2009
I've always wondered about this API - why is is so different from the other filtering ones? Why do you have to do the work when all you want to do is say FLT_PREOP_SUCCESS (as opposed to the cases where you want to do work and so return FLT_PREOP_COMPLETE). The code in FltMgr must be structured to be able to pass requests down. It would make my code much simpler if I could do that for FileObjects and for Instances which are not virtualized.Anonymous
November 09, 2009
Honestly, i don't know the reasons for this design decision. The funny thing is the name provider APIs are all call-through when one of the design goals for filter manager was to minimize stack usage and that's why everything else is using a callback model. I've been thinking about it for a while and i still don't see a compelling reason for it. Anyway, it is what it is and it’s probably going to stay that way for backwards compatibility reasons.We definitely need some examples out there, at least for the pass-through case.Anonymous
November 20, 2009
Alex,What if the name provider does not care about the transactions? Is it compulsory to implement thePFLT_NORMALIZE_NAME_COMPONENT_EX callback?Anonymous
November 20, 2009
Nope. Filter manager will figure out which one you have registered and will call that one. If you register both, it will only call the EX one.