Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
Hi folks, I've read the following articles:
and have the following questions on the sample (https://github.com/microsoft/Windows-driver-samples/blob/main/filesys/miniFilter/swapBuffers/swapBuffers.c):
In read pre-op (SwapPreReadBuffers
) we allocated our own MDL (newMdl
) and swapped it with the IRP's MDL:
L953: iopb->Parameters.Read.MdlAddress = newMdl;
We did not save the original MdlAddress
before overwriting it. If it's not null, then who frees it? The comments at the end of post-op (SwapPostReadBuffers
, L1200) states that "freeing of the MDL (if there is one) is handled by FltMgr". There are 2 MDLs here, and I guess FltMgr handles one of them, so what about the other one?
The aforementioned comments state that the filter manager is the one that does the freeing. However, the IFS FAQ states that it's the I/O Manager that cleans up the MDL:
A normal driver will associate an MDL it creates to describe the user buffer with the IRP. This is useful because it ensures that when the IRP is completed the I/O Manager will clean up these MDLs, which eliminates the need for the driver to provide special handling for such clean-up.
Is this a typo with the code comments, or is this really the case for minifilters?
In read post-op (SwapPostReadBuffers
), we did not call MmProbeAndLockPages
on MdlAddress
, but proceeded to call MmGetSystemAddressForMdlSafe
on it (L1089). How is this safe? The "Master of the Obvious" article states:
When a driver specifies METHOD_DIRECT, the I/O manager guarantees that the driver will receive an MDL that describes the full virtual address range specified by the original requestor and that the MDL has been probed and locked.
Is this the reason why?
In read post-op, handling of the case of user buffer is deferred via FltDoCompletionProcessingWhenSafe
. Instead of doing this, can we do the following?
1. In pre-op, use IoAllocateMdl
to create a MDL for the user buffer
2. Call MmProbeAndLockPages
on it
3. Pass MDL to post-op via completion context
4. In post-op call MmGetSystemAddressForMdlSafe
on it
We would be doing all the work directly in pre and post callbacks, so FltDoCompletionProcessingWhenSafe
is not needed.
If the aforementioned approach is possible, then can we take it a step further by doing all the work of getting the system address of the original buffer (be it a user buffer, system buffer, or MdlAddress
) in read pre-op, and then pass the address to post-op via the completion context? This keeps all the related code in the same scope and thus facilitates comprehension and maintenance. Are there any ptifalls/gotchas with this approach?
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Kernel Debugging | 30 January 2023 | Live, Online |
Developing Minifilters | 20 March 2023 | Live, Online |
Internals & Software Drivers | 17 April 2023 | Live, Online |
Writing WDF Drivers | 22 May 2023 | Live, Online |
Comments
This sample has caused nothing but confusion 😂 I always get questions about it when I teach our minifilter seminar, would probably be a good article to go through and explain what the hell it's doing , why it's doing it (hint: dummy pages), and the behaviors it relies upon...
Q1/2
Those articles you reference are all from the perspective of the core O/S. Remember that minifilters talk to FltMgr and FltMgr can make up whatever rules it wants, which is what leading to the confusion here.
FltMgr "knows" that the MDL address has changed and keeps track of both so that they can be properly freed. This is not clear from any documentation that I'm aware of even though this sample relies heavily upon that behavior.
Q3
There's no need to probe and lock because this MDL is for a non-paged pool buffer and was built using MmBuildMdlForNonPagedPool
Q4
Yes, that would work assuming that you don't need to do anything else in the PostOp that might require < DISPATCH_LEVEL. Also, if you're going to be doing work that takes "a long time" you don't want to do that at DISPATCH_LEVEL ("long time" is subjective and not easily definable, just something to think about).
Q5
Nothing wrong with that...As a general rule I like to do anything that might fail in PreXxx and pass along the results to post. It's nice to keep the majority of failure cases in Pre and not have to worry about failing AFTER the file system has done its work and the affects that might have (e.g. timestamps).
-scott
OSR
Thanks Scott!
For Q4, pre-op did allocate a non-paged pool buffer and built the MDL using
MmBuildMdlForNonPagedPool
. It then swapped theMdlAddress
field with the new MDL. However in post-op, theFLT_PARAMETERS
field would be back to the original values, i.e.MdlAddress
now points to the original MDL, not our swapped one. So to confirm, you're saying we can be sure that the original MDL is also for a non-paged pool buffer and was built usingMmBuildMdlForNonPagedPool
?Ah, sorry, you're asking about the original buffer...
If there was an MDL with the request then it must already be locked by either using MmProbeAndLockPages or MmBuildMdlForNonPagedPool. You could tell by the flags if you wanted but it doesn't really matter, the key point is that the physical pages are locked (which is a requirement prior to mapping)
-scott
OSR