In my minifilter driver, the cleanup callback for a stream handle context is not being called under certain conditions.
Scenario:
- During
PostCreate
, a section context and its corresponding section object are created using FltAllocateContext
and FltCreateSectionForDataScan
, based on specific conditions.
- This section context is stored within a stream handle context.
- In the
PreAcquireForSectionSynchronization
handler, the section context is retrieved using FltGetSectionContext
(currently via the file object, though it could be accessed directly from the stream handle context). After scanning, the section context's reference is released using FltReleaseContext
.
- If the driver is unloaded at this point, the stream handle context's cleanup callback is not invoked. The intention was to perform cleanup of the section object and its context within this callback using
FltCloseSectionForDataScan
and FltReleaseContext
, avoiding reliance on the application to call CloseHandle
and triggering cleanup in the IRP_MJ_CLEANUP
handler.
- As a result, the filter driver remains loaded and cannot be unloaded cleanly. However, if the section object and its context are released in the
IRP_MJ_CLEANUP
handler, the filter unloads as expected.
I recognize that a section object maintains an active reference to its associated file object, preventing the file object's deletion (and consequently, its context's deletion) until the section object is fully released. Nonetheless, I anticipated that the cleanup callback for the stream handle context would be invoked during filter unload, regardless of outstanding references.
Is my understanding correct regarding the behaviour of stream handle context cleanup callbacks in relation to section object references?
Thanks
I don't know the exact reason for the hang, but these data scan sections aren't meant to be long lived like this.
For one they enable purge failure mode in the lower file system, which is going to result in purge failures being turned into an infinite wait by FltMgr for the data scan section(s) to go away. So, they're really meant to be created, used, and then closed.
The "section context" is kind of a misnomer here because they're not really meant to be contexts on the section itself but it's just how FltMgr keeps track of the in-progress data scan sections so it can handle the purge failures.
So, they're really meant to be created, used, and then closed.
I have always wondered if that is the case and if I was being too cute in trying to access it across IRPs but couldn't find any best practices documentation around this online.
Can you please share if you're aware of any?
Having said that, shouldn't context cleanup callbacks be something that are guaranteed to be called independently irrespective of the type when filter unloads - otherwise filters wouldn't get a chance to cleanup their contexts.
Sounds like a bug in the filter manager?
Thanks
No, I don’t know any best practices documentation.
It’s really just a wrapper around FsRtlCreateSectionForDataScan, which is in turn a wrapper around ZwCreateSection. I guess best practice would then be inferred by the doc pages for those APIs combined.
But fundamentally by keeping the data scan section around you’re keeping a data section active to the stream. Data sections can interfere with things like file size changes, deletes, writes, etc. (just like any other section) so keeping them around indefinitely isn’t a great idea. And, in fact, the whole point of the section context is so that FltMgr can avoid applications getting errors back because of a section it didn’t create and doesn’t know exists (e.g. for an A/V scan, which is really the primary use case of the API).
You’re right in general about context cleanup and I could see an argument that there might be a bug here. But given that the section context has a very specific use within FltMgr (and wasn’t even added until Win8) I suspect the ultimate answer is “don’t do that”. Have you tracked down the hanging FltMgr thread(s) waiting for unload? It’s quite possible they run down the section contexts before doing anything else with the assumption that they’re short lived and should be flushed out in short order. I don’t know that to be true, but I could see writing the code that way.
I think you're spot on there. As soon as I close section object in the PreCleanup
(this is also present in the stream handle context cleanup callback to handle the case where filter is unloaded while application hasn't closed the handle), filter unloads cleanly.
I was really trying to scan a file only when its absolutely needed by creating a section object in PostCreate
and then utilising it in PreAcquireForSectionSynchronization
(i.e. just before execution).
Doing everything in PostCreate
(create section, scan, close) might be wasteful as at this point it cannot be determined if the file will actually be executed later. So it would just result in speculative scanning which I was hoping to avoid - but seems like that's the only avenue left from above.
Thanks