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/
Microsoft's regfltr example uses the terminology of "Probed Parameters" and "Captured Parameters", which is documented here:
https://github.com/microsoft/Windows-driver-samples/blob/0e92e35395ee3dbc2852f3ab6d9c1f7350c2bd85/general/registry/regfltr/sys/capture.c#L33
As far as I understand, a probed buffer is a buffer which was verified for validity and access rights, and a a captured buffer is just a buffer which was copied to a system allocated memory.
If my understanding is correct, I'm not sure I understand the motivation for mentioning the probed parameters at all - while the buffer was accessible at the time of the check, it wasn't e.g. locked or something, so it might be invalid just a moment afterwards. And indeed the code probes the buffer on access (if I understand the term "probe" at all):
https://github.com/microsoft/Windows-driver-samples/blob/0e92e35395ee3dbc2852f3ab6d9c1f7350c2bd85/general/registry/regfltr/sys/capture.c#L459
Can you please clarify it for me? Thanks.
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! | ||
Writing WDF Drivers | 7 Dec 2020 | LIVE ONLINE |
Internals & Software Drivers | 25 Jan 2021 | LIVE ONLINE |
Developing Minifilters | 8 March 2021 | LIVE ONLINE |
Comments
Well, the copy in the snippet you cited on GitHub accesses the buffer within a try/except... which is required.
I think your understanding is correct. However... capturing the contents of a user data buffer requires that we first probe that buffer for accessibility (within a try/except block) and then access the user data buffer in a manner that matches what we probed for... and that access also needs to be done in a try/except block.
So, doing the capture implies that SOMEbody has to do the probe and deref the user virtual address.
You can avoid your DRIVER doing the probe by using an access method other than Neither I/O (so Buffered I/O or Direct I/O.... both of which involve the I/O Manager doing the probe for you... and Buffered I/O also capturing the users data buffer for you).
We typically "capture" user data buffers when it matters if the contents of the buffer changes during our processing of a request. If the data buffer contains "just data" (the driver driver is going to write to disk, for example) it doesn't really matter (to the driver) if that data is the same or different between the time the user's data buffer is probed and the time the data is written. It might matter to the user, but it doesn't to the driver.
OTOH, if the driver is uses the contents of the data buffer in some meaningful way -- consider a buffer that comprises a description of a series of strings... with the offset and length to each one passed a sequence of ULONG_PTRs in the buffer -- we will want to capture the whole buffer and validate it once it's inaccessible to the user. So we know when we go back to process the data in the buffer the user can't have changed it.
Does that answer your question??
Peter
Peter Viscarola
OSR
@OSRDrivers
There are a dizzying number of attacks that malicious usermode can spring on a driver. Probing protects against some of them, although as you've observed, probing is certainly not going to protect against every sort of attack.
Probing protects against:
But as you've observed, the probe doesn't really mean very much, since usermode can change out the page protections on its own virtual addresses at any time. So your driver still needs to access the buffer under
__try
/__except
. (Or as this sample spells them,try
/except
, which is equivalent, but doesn't work in C++ code, so is discouraged.)When the docs say that a buffer is captured, that gives you a much stronger guarantee. That protects against the attacks listed above, as well as:
My misunderstanding was in the difference between probing and accessing the data withing
try
/except
. The short answer is: a check for kernel addresses and alignment. Thank you for the elaborate answers, in addition to answering my question I got better understanding overall.Just in case your head doesn't hurt enough, note that capturing can actually be a lot harder than it seems. Classic guest article about the problems with capturing here:
https://www.osronline.com/article.cfm^article=514.htm
-scott
OSR
Just to be sure - how does it prevent the user mode code from changing the contents while your code is reading/writing from it? I presume you mean the captured buffer, but user mode can still change the original buffer while you are writing to it (the original buffer).
Yes, sorry about the confusion; that's what I meant. Usermode can change its buffers as much as it wants. But when a lower layer captures the buffer, you get a single, unchanging snapshot of the contents of the buffer. Usermode can continue to scribble on its own buffers, but it won't be reflected in the kernel's captured buffer.
This general definition of "capture" applies to the registry parameters discussed at the start of this thread, and also
METHOD_BUFFERED
ioctls captured by the I/O manager.And you can capture values yourself. Capturing basically amounts to small amounts of compiler magic, wrapped around a simple memcpy: