I am writing a minifilter to catch NotifyDirectory IRPs as they travel down
and up the filter stack. I have observed some very odd behavior in how the
buffer is handled. Consider the following code:
MyPreOperationCallback( … )
{
if (Data->Iopb->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
return FLT_PREOP_SUCCESS_NO_CALLBACK;
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
MyPostOperationCallback( … )
{
PVOID buffer;
FltLockUserBuffer(Data);
buffer = MmGetSystemAddressForMdlSafe(
Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress,
NormalPagePriority);
return FLT_POSTOP_FINISHED_PROCESSING;
}
If I run this filter and examine the contents of buffer in my PostOp
callback, it always contains the file that changed on the previous trip
through the filter chain. This is kind of hard to explain so let me provide
an example:
- With the filter loaded and attached (altitude 430000 for testing
purposes), I start a user-mode app that monitors a directory for changes. - My PreOp callback gets called as the user-mode app sends down an IRP for
NotifyDirectory. - I create subdirectory ‘1234’
- My PostOp callback gets called, buffer contains junk.
- My PreOp callback gets called as the user-mode app sends down another
IRP. - I create subdirectory ‘5678’
- My PostOp callback gets called, buffer contains ‘1234’ !!
I believe that I’m seeing a delayed version of the buffer because the
user-mode app is reusing the buffer from the previous trip and my filter is
somehow always seeing the pre-modified buffer. My first guess for why this
was happening was that a lower-level filter was swapping buffers and I was
seeing only the original buffer, so I rewrote the code as such:
MyPostOperationCallback( … )
{
PVOID buffer;
PMDL mdl;
mdl = FltGetSwappedBufferMdlAddress(Data);
if (mdl)
buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
}
This modification resulted in buffer never being set because mdl was always
NULL.
Next, I modified the code so that the user buffer was locked during the
PreOp:
MyPreOperationCallback( … )
{
if (Data->Iopb->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
return FLT_PREOP_SUCCESS_NO_CALLBACK;
FltLockUserBuffer(Data);
return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
MyPostOperationCallback( … )
{
PVOID buffer;
buffer = MmGetSystemAddressForMdlSafe(
Data->Iopb->Parameters.DirectoryControl.NotifyDirectory.MdlAddress,
NormalPagePriority);
return FLT_POSTOP_FINISHED_PROCESSING;
}
This solution actually worked!! I was able to see the filename without the
one trip delay through the filter chain. Apparently, I need to lock the
buffer during the PreOp so I can see it during the PostOp…?
I am trying to understand why I am observing this behavior before I move on
to the next phase of my project. I’ve read through all of the WDK
documentation, the Filter Driver Developer Guide, and searched through the
osr archives and so far I can’t figure out what’s going on here. Can anybody
shed some light on this?
Best Regards,
Michael Carr