Minifilter, FLT_PREOP_PENDING, FLT_POSTOP_MORE_PROCESSING_REQUIRED

List,

I have a few questions about pended I/O operations from minifilter callbacks.

  1. After returning FLT_PREOP_PENDING from a pre-callback, or FLT_POSTOP_MORE_PROCESSING_REQUIRED from a post-callback, are there any requirements around where FltCompletePendedPreOperation or FltCompletePendedPostOperation are called? I had assumed any context would be permissible (such as from system thread started with PsCreateSystemThread), but an old OSR-related discussion [1] seems to eerily suggest otherwise, and there were other indications that calling FltComplete* from a separate thread could be problematic [2]. However, how else would one be expected to make use of FltComplete* functions if not from another thread?

1a) Are there guarantees (or only incorrect assumptions from developers) related to your thread context in a minifilter driver depending on the IRP and pre/post callbacks, and if so (how) does the Filter Manager handle resuming IRP processing for subsequent minifilters in the chain following a FltComplete* call from a system thread? Or is this left up to the caller of the FltComplete* functions?
1b) Are the context requirements listed here [3] applicable to minifilters calling FltComplete* as well? Are these requirements for all possible CallbackStatus values from FltCompletePendedPreOperation or only a subset of them?

  1. When pending a pre- or post- operation in a minifilter, it seems like you are required to create your own copy (and where appropriate reference counts for some members) of the FLT_RELATED_OBJECTS parameter, as this is a stack-based parameter of the parent function that will not be valid after return your pending status code from your callback. Are you also required to create a copy of the FLT_CALLBACK_DATA data (versus tucking a pointer away into your work queue item)?

Cheers,

Jason V. Miller
Technical Leader, FireAMP
xxxxx@cisco.com

Cisco Systems Canada Co, 181 Bay St.
Suite 3400, Toronto, ON, Canada, M5J 2T3
Phone: 416-306-7000, Fax: 416-306-7099
Preferences?-?Unsubscribe?-?Privacy

[1] http://www.osronline.com/showthread.cfm?link=252309 (specifically discussion around [A])
[2] http://www.osronline.com/showthread.cfm?link=166259
[3] http://msdn.microsoft.com/en-us/library/windows/hardware/ff540124(v=vs.85).aspx

[A]
“”"
However, you might want to worry about the fact that IRP_MJ_CLEANUP must be
called in the context of the process that close that last handle so you must
queue in such a way that the thread that dequeues it either completes the
request or, if it sends it down, it must do so in the same process context.
“”"

  1. In the referenced thread, Alex is referring specifically to the
    cleanup handler, if you are going to pass it down the stack in a worker
    then completion should be handled in the callers thread. I was always
    under the impression that since NtClose is sync wrt to the IOMgr, then
    it doesn’t matter what context you complete the request in, the IO Mgr
    will ‘do the right thing’ and perform final completion in the calling
    thread. If you want to queue a request to a separate worker thread and
    complete it within that thread, there is no issue, with the above
    exception noted. And this holds for any request.

1A) There should be no context assumptions made for any request other
than the pre-create side of request processing. Unless the mini-filter
correctly inherits all security aspects of the calling thread,
pre-creates should not be queued to a worker. As for completion
processing, no context assumptions should be made there either. You can
tell FltrMgr to SYNCHRONIZE the completion callback and this will block
the calling thread in FltrMgr and it will call your post-op routine in
the same context. This can be handy in cases where you want the post-op
callback to be invoked at <= APC IRQL in the calling thread context.

1B) It depends … most of the ‘non arbitrary’ calls are passed a user
mode buffer so if you are going to send the request off to an arbitrary
worker thread then you’ll need to ensure the buffers are backed by an
MDL which can be accessed from arbitrary contexts. Other than that,
completion can be called in an arbitrary context.

  1. There really should no longer be any stack based parameters found in
    the flt_callback data structure. In XP and before there were cases where
    system components would use stack based file objects but I think nearly
    all of that has been removed. For async processing, I always stash away
    the pointer to the callback data and queue it for processing.

Pete

On 7/24/2014 3:47 PM, Jason Miller (jasomil2) wrote:

List,

I have a few questions about pended I/O operations from minifilter callbacks.

  1. After returning FLT_PREOP_PENDING from a pre-callback, or FLT_POSTOP_MORE_PROCESSING_REQUIRED from a post-callback, are there any requirements around where FltCompletePendedPreOperation or FltCompletePendedPostOperation are called? I had assumed any context would be permissible (such as from system thread started with PsCreateSystemThread), but an old OSR-related discussion [1] seems to eerily suggest otherwise, and there were other indications that calling FltComplete* from a separate thread could be problematic [2]. However, how else would one be expected to make use of FltComplete* functions if not from another thread?

1a) Are there guarantees (or only incorrect assumptions from developers) related to your thread context in a minifilter driver depending on the IRP and pre/post callbacks, and if so (how) does the Filter Manager handle resuming IRP processing for subsequent minifilters in the chain following a FltComplete* call from a system thread? Or is this left up to the caller of the FltComplete* functions?
1b) Are the context requirements listed here [3] applicable to minifilters calling FltComplete* as well? Are these requirements for all possible CallbackStatus values from FltCompletePendedPreOperation or only a subset of them?

  1. When pending a pre- or post- operation in a minifilter, it seems like you are required to create your own copy (and where appropriate reference counts for some members) of the FLT_RELATED_OBJECTS parameter, as this is a stack-based parameter of the parent function that will not be valid after return your pending status code from your callback. Are you also required to create a copy of the FLT_CALLBACK_DATA data (versus tucking a pointer away into your work queue item)?

Cheers,

Jason V. Miller
Technical Leader, FireAMP
xxxxx@cisco.com

Cisco Systems Canada Co, 181 Bay St.
Suite 3400, Toronto, ON, Canada, M5J 2T3
Phone: 416-306-7000, Fax: 416-306-7099
Preferences - Unsubscribe - Privacy

[1] http://www.osronline.com/showthread.cfm?link=252309 (specifically discussion around [A])
[2] http://www.osronline.com/showthread.cfm?link=166259
[3] http://msdn.microsoft.com/en-us/library/windows/hardware/ff540124(v=vs.85).aspx

[A]
“”"
However, you might want to worry about the fact that IRP_MJ_CLEANUP must be
called in the context of the process that close that last handle so you must
queue in such a way that the thread that dequeues it either completes the
request or, if it sends it down, it must do so in the same process context.
“”"


NTFSD is sponsored by OSR

OSR is hiring!! Info at http://www.osr.com/careers

For our schedule of debugging and file system seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

Peter is (as usual) absolutely right.

I’d just like to add to the answer for your second point that yes, you’re
not supposed to pass the FLT_RELATED_OBJECT pointer itself to your threads
but instead only take the members that you need (which could be all of them
at some point I suppose :)) and reference them where necessary. You do not
need to copy the FLT_CALLBACK_DATA because, unlike the FLT_RELATED_OBJECT
whose “ownership” is dictated by the stack (yeah, sounds weird but you see
where I’m going with this) the FLT_CALLBACK_DATA’s ownership is dictated by
the return value to the preOp or postOp callback so if you return PENDING
or MORE _PROCESSING_REQUIRED then you own it until you give it back to the
system by calling one of the FltComplete* functions.

Does this make sense ?

Thanks,
Alex.

On Thu, Jul 24, 2014 at 3:18 PM, Peter Scott
wrote:

>
> 1) In the referenced thread, Alex is referring specifically to the cleanup
> handler, if you are going to pass it down the stack in a worker then
> completion should be handled in the callers thread. I was always under the
> impression that since NtClose is sync wrt to the IOMgr, then it doesn’t
> matter what context you complete the request in, the IO Mgr will ‘do the
> right thing’ and perform final completion in the calling thread. If you
> want to queue a request to a separate worker thread and complete it within
> that thread, there is no issue, with the above exception noted. And this
> holds for any request.
>
> 1A) There should be no context assumptions made for any request other than
> the pre-create side of request processing. Unless the mini-filter correctly
> inherits all security aspects of the calling thread, pre-creates should not
> be queued to a worker. As for completion processing, no context assumptions
> should be made there either. You can tell FltrMgr to SYNCHRONIZE the
> completion callback and this will block the calling thread in FltrMgr and
> it will call your post-op routine in the same context. This can be handy in
> cases where you want the post-op callback to be invoked at <= APC IRQL in
> the calling thread context.
>
> 1B) It depends … most of the ‘non arbitrary’ calls are passed a user
> mode buffer so if you are going to send the request off to an arbitrary
> worker thread then you’ll need to ensure the buffers are backed by an MDL
> which can be accessed from arbitrary contexts. Other than that, completion
> can be called in an arbitrary context.
>
> 2) There really should no longer be any stack based parameters found in
> the flt_callback data structure. In XP and before there were cases where
> system components would use stack based file objects but I think nearly all
> of that has been removed. For async processing, I always stash away the
> pointer to the callback data and queue it for processing.
>
> Pete
>
>
>
> On 7/24/2014 3:47 PM, Jason Miller (jasomil2) wrote:
>
>> List,
>>
>> I have a few questions about pended I/O operations from minifilter
>> callbacks.
>>
>> 1) After returning FLT_PREOP_PENDING from a pre-callback, or
>> FLT_POSTOP_MORE_PROCESSING_REQUIRED from a post-callback, are there any
>> requirements around where FltCompletePendedPreOperation or
>> FltCompletePendedPostOperation are called? I had assumed any context would
>> be permissible (such as from system thread started with
>> PsCreateSystemThread), but an old OSR-related discussion [1] seems to
>> eerily suggest otherwise, and there were other indications that calling
>> FltComplete* from a separate thread could be problematic [2]. However, how
>> else would one be expected to make use of FltComplete* functions if not
>> from another thread?
>>
>> 1a) Are there guarantees (or only incorrect assumptions from
>> developers) related to your thread context in a minifilter driver depending
>> on the IRP and pre/post callbacks, and if so (how) does the Filter Manager
>> handle resuming IRP processing for subsequent minifilters in the chain
>> following a FltComplete* call from a system thread? Or is this left up to
>> the caller of the FltComplete* functions?
>> 1b) Are the context requirements listed here [3] applicable to
>> minifilters calling FltComplete* as well? Are these requirements for all
>> possible CallbackStatus values from FltCompletePendedPreOperation or only a
>> subset of them?
>>
>> 2) When pending a pre- or post- operation in a minifilter, it seems like
>> you are required to create your own copy (and where appropriate reference
>> counts for some members) of the FLT_RELATED_OBJECTS parameter, as this is a
>> stack-based parameter of the parent function that will not be valid after
>> return your pending status code from your callback. Are you also required
>> to create a copy of the FLT_CALLBACK_DATA data (versus tucking a pointer
>> away into your work queue item)?
>>
>> Cheers,
>>
>> Jason V. Miller
>> Technical Leader, FireAMP
>> xxxxx@cisco.com
>>
>> Cisco Systems Canada Co, 181 Bay St.
>> Suite 3400, Toronto, ON, Canada, M5J 2T3
>> Phone: 416-306-7000, Fax: 416-306-7099
>> Preferences - Unsubscribe - Privacy
>>
>> [1] http://www.osronline.com/showthread.cfm?link=252309 (specifically
>> discussion around [A])
>> [2] http://www.osronline.com/showthread.cfm?link=166259
>> [3] http://msdn.microsoft.com/en-us/library/windows/hardware/
>> ff540124(v=vs.85).aspx
>>
>> [A]
>> “”“
>> However, you might want to worry about the fact that IRP_MJ_CLEANUP must
>> be
>> called in the context of the process that close that last handle so you
>> must
>> queue in such a way that the thread that dequeues it either completes the
>> request or, if it sends it down, it must do so in the same process
>> context.
>> “””
>>
>>
>> —
>> NTFSD is sponsored by OSR
>>
>> OSR is hiring!! Info at http://www.osr.com/careers
>>
>> For our schedule of debugging and file system seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
> –
> Kernel Drivers
> Windows File System and Device Driver Consulting
> www.KernelDrivers.com
> 866.263.9295
>
>
>
> —
> NTFSD is sponsored by OSR
>
> OSR is hiring!! Info at http://www.osr.com/careers
>
> For our schedule of debugging and file system seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Alex and Pete,

Sincerely thanks to the both of you for the responses; both e-mails were tremendously helpful.

I understand most of what’s been said, but I am still struggling with point (1), and specifically Pete’s sentence here:

If you want to queue a request to a separate worker thread and complete it within that thread, there is no issue, with the above exception noted.

I am not sure that I understand the specific case (exception) you’re referring to; in what case(s) might it be wrong to pend and later issue FltComplete* for an IRP_MJ_CLEANUP in a system thread? Just in the post callback (is the post callback implied by the term “final completion”)?

Cheers,

J.

I was wondering about that but after re-reading the answer I ended up
thinking that Pete was specifically talking about IRP_MJ_CLEANUP. Most
others you can work around by doing something to ‘capture’ the context
specific part (for things with buffers you must get the MDL and for
IRP_MJ_CREATE you need to capture the security context) but IRP_MJ_CLOSE I
think just ‘needs’ to be the in the same context (i.e. there is no
workaround to make it work from a different context).

Alex.

On Thu, Jul 24, 2014 at 5:01 PM, Jason Miller (jasomil2) > wrote:

> Alex and Pete,
>
> Sincerely thanks to the both of you for the responses; both e-mails were
> tremendously helpful.
>
> I understand most of what’s been said, but I am still struggling with
> point (1), and specifically Pete’s sentence here:
>
> > If you want to queue a request to a separate worker thread and complete
> it within that thread, there is no issue, with the above exception noted.
>
> I am not sure that I understand the specific case (exception) you’re
> referring to; in what case(s) might it be wrong to pend and later issue
> FltComplete* for an IRP_MJ_CLEANUP in a system thread? Just in the post
> callback (is the post callback implied by the term “final completion”)?
>
> Cheers,
>
> J.
>
>
> —
> NTFSD is sponsored by OSR
>
> OSR is hiring!! Info at http://www.osr.com/careers
>
> For our schedule of debugging and file system seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> I was wondering about that but after re-reading the answer I ended

up thinking that Pete was specifically talking about IRP_MJ_CLEANUP.
Most others you can work around by doing something to ‘capture’ the
context specific part (for things with buffers you must get the MDL
and for IRP_MJ_CREATE you need to capture the security context) but
IRP_MJ_CLOSE I think just ‘needs’ to be the in the same context
(i.e. there is no workaround to make it work from a different context). 

I am trying to read between the lines here; you mentioned both IRP_MJ_CLEANUP and then later IRP_MJ_CLOSE.

Is the concern here that you cannot FltComplete* an IRP_MJ_CLEANUP in a system thread because while processing this an IRP_MJ_CLOSE can be generated, which would be created in the wrong (system versus process) context? If so, does anyone know why this is a problem? Oddly enough MSDN says that CLOSE is arbitrary thread context, but CLEANUP is nonarbitrary, though this could be during IRP processing and not at creation.

And so the rule would be to never pend an IRP_MJ_CLEANUP to a system thread for completion? I wondered if this could be handled gracefully by using KeStackAttachProcess before calling into FltCompletePendedPreOperation, although the Remarks section of the documentation makes this sound pretty dangerous?

Cheers,

J.

The Filter Manager (FM) terminology confuses things here I think. I’ll throw
my attempt at an explanation in and see what happens :slight_smile: I’ll start at the
(very) high level architectural view and then muddy it with all the
details…

File systems are an example of what we call “highest level drivers”. This
means they are called directly by the I/O Manager as a result of user
requests and, therefore, are called at their I/O entry points in the context
of the requesting thread/process. File system filters sit above the file
systems, therefore they inherit this attribute. Of course, FM sits between
the minifilter and the I/O Manager, so the practical implication would be
that your preoperation callbacks are called in the context of the requesting
thread/process.

Completion processing has no such execution context guarantees. Drivers are
free to *complete* I/O requests in any execution context they choose, thus
when you’re dealing with I/O completion notification you can’t make any
guarantees of the context you’re in. For a minifilter, you’re again seeing
an abstraction of this and the implication is that your postoperation
callbacks are called in an arbitrary thread/process context (though FM has
an option to change that, which I’ll get to).

That’s the perfect world. Of course, we don’t live in a perfect world, so
things get more complicated than that…

As you know, minifilters have the ability to, for example, post their
preoperation to a worker thread in the System process. If they then pass
this operation on to the filters beneath it, we have lost the original
execution context for the lower filters’ preoperation callbacks. It is the
responsibility of the minifilter posting the operation to ensure that the
lower filters can continue to work even though they are no longer in the
requesting context. For example, if this was an IRP_MJ_READ operation, an
MDL must be built for the requestor’s data buffer because the original
buffer descriptor was specific to the requestor’s context (i.e. it’s just a
virtual address in the requestor’s process).

The conventional wisdom is that for IRP_MJ_CREATE and IRP_MJ_CLEANUP, it’s
either impossible or unwise to make things “look” sufficiently like the
original context to not break anything. IRP_MJ_CLEANUP has always had a bit
of a sordid history in this regard as it really *should* be possible, but
it’s frequently avoided (e.g. we’ve had issues in the past with byte range
locks not breaking because someone was trying to break them for the current
process, not the requesting process). IRP_MJ_CLOSE is fine to post as it’s
always sent from the System process anyway.

Of course, completion continues to not matter, because it was never
guaranteed anyway. FM does provide an option to have your postoperation
callback called in the same execution context as your preoperation callback
(FLT_PREOP_SYNCHRONIZE), but that’s just FM synchronously waiting after
calling your preoperation before calling your postoperation.

Now back to FltCompletePendedPreOperation…This name is confusing because
you use it to either pass the request down to the next filter’s preoperation
callback (_SUCCESS_NO_CALLBACK or _SUCCESS_WITH_CALLBACK) OR trigger
completion processing (_COMPLETE). In the former case execution context
possibly matters, in the latter case it does not. A better name might have
been FltResumePendedPreOperation, as you’re really just picking back up
where you left off when you originally posted it.

-scott
OSR
@OSRDrivers

“Jason Miller (jasomil2)” wrote in message news:xxxxx@ntfsd…

I was wondering about that but after re-reading the answer I ended
up thinking that Pete was specifically talking about IRP_MJ_CLEANUP.
Most others you can work around by doing something to ‘capture’ the
context specific part (for things with buffers you must get the MDL
and for IRP_MJ_CREATE you need to capture the security context) but
IRP_MJ_CLOSE I think just ‘needs’ to be the in the same context
(i.e. there is no workaround to make it work from a different context).

I am trying to read between the lines here; you mentioned both
IRP_MJ_CLEANUP and then later IRP_MJ_CLOSE.

Is the concern here that you cannot FltComplete* an IRP_MJ_CLEANUP in a
system thread because while processing this an IRP_MJ_CLOSE can be
generated, which would be created in the wrong (system versus process)
context? If so, does anyone know why this is a problem? Oddly enough MSDN
says that CLOSE is arbitrary thread context, but CLEANUP is nonarbitrary,
though this could be during IRP processing and not at creation.

And so the rule would be to never pend an IRP_MJ_CLEANUP to a system thread
for completion? I wondered if this could be handled gracefully by using
KeStackAttachProcess before calling into FltCompletePendedPreOperation,
although the Remarks section of the documentation makes this sound pretty
dangerous?

Cheers,

J.

Sorry… I don’t know where my head was at. I meant IRP_MJ_CLEANUP the time
I wrote IRP_MJ_CLOSE. Thanks for catching this!

Alex.

On Thu, Jul 24, 2014 at 6:17 PM, Jason Miller (jasomil2) > wrote:

> > I was wondering about that but after re-reading the answer I ended
> > up thinking that Pete was specifically talking about IRP_MJ_CLEANUP.
> > Most others you can work around by doing something to ‘capture’ the
> > context specific part (for things with buffers you must get the MDL
> > and for IRP_MJ_CREATE you need to capture the security context) but
> > IRP_MJ_CLOSE I think just ‘needs’ to be the in the same context
> > (i.e. there is no workaround to make it work from a different context).
>
> I am trying to read between the lines here; you mentioned both
> IRP_MJ_CLEANUP and then later IRP_MJ_CLOSE.
>
> Is the concern here that you cannot FltComplete* an IRP_MJ_CLEANUP in a
> system thread because while processing this an IRP_MJ_CLOSE can be
> generated, which would be created in the wrong (system versus process)
> context? If so, does anyone know why this is a problem? Oddly enough MSDN
> says that CLOSE is arbitrary thread context, but CLEANUP is nonarbitrary,
> though this could be during IRP processing and not at creation.
>
> And so the rule would be to never pend an IRP_MJ_CLEANUP to a system
> thread for completion? I wondered if this could be handled gracefully by
> using KeStackAttachProcess before calling into
> FltCompletePendedPreOperation, although the Remarks section of the
> documentation makes this sound pretty dangerous?
>
> Cheers,
>
> J.
>
>
> —
> NTFSD is sponsored by OSR
>
> OSR is hiring!! Info at http://www.osr.com/careers
>
> For our schedule of debugging and file system seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Scott,

Thank you very much for the detailed response; it clears up remaining dark corner of this discussion nicely for me.

The conventional wisdom is that for IRP_MJ_CREATE and IRP_MJ_CLEANUP, it’s
either impossible or unwise to make things “look” sufficiently like the
original context to not break anything. IRP_MJ_CLEANUP has always had a
bit of a sordid history in this regard as it really *should* be possible,
but it’s frequently avoided (e.g. we’ve had issues in the past with byte
range locks not breaking because someone was trying to break them for the
current process, not the requesting process). IRP_MJ_CLOSE is fine to post
as it’s always sent from the System process anyway.

Context requirements strike me as either a documentation omission (your response made the requirements clear) or a missing case in the Filter Manager, although I bet this is far more clear to those familiar with old-style filter drivers, and only less so to people like me walking into the Minifilter documentation without that background.

Of course, completion continues to not matter, because it was never
guaranteed anyway. FM does provide an option to have your postoperation
callback called in the same execution context as your preoperation
callback (FLT_PREOP_SYNCHRONIZE), but that’s just FM synchronously waiting
after calling your preoperation before calling your postoperation.

If context during the pre-callback execution chain must be preserved in certain circumstances, I would have assumed this would be clearly spelled out in the PFLT_PRE_OPERATION_CALLBACK [1] documentation, or that the Filter Manager would internally wait on an event in the thread returning FLT_PREOP_PENDING so that processing continued in the proper context following FltCompletePendedPreOperation being called with a non-completion (FLT_PREOP_SUCCESS*) CallbackStatus (which I assumed would set said event, not continue processing the chain in the “completing” thread.)

Also, I would assume FM must do a check exactly before the post-callback for every minifilter returning FLT_PREOP_SYNCHONIZE in a pre-callback to ensure that an earlier minifilter didn’t change the context, and that this check and context-switch might occur multiple times for a single IRP if there are multiple minifilters that finish the callback in a different context than it was started in? Or is this another gotcha?

Cheers,

J.

[1] http://msdn.microsoft.com/en-us/library/windows/hardware/ff551109(v=vs.85).aspx, or perhaps in the FltCompletePendedPreOperation.

IRP_MJ_CREATE is the big one and FM does indeed wait. This is stated in the
docs, though you have to know where to find it:

"Minifilter drivers should not return FLT_PREOP_SYNCHRONIZE for create
operations, because these operations are already synchronized by the filter
manager. "

http://msdn.microsoft.com/en-us/library/windows/hardware/ff552037(v=vs.85).aspx

Granted, it’s a pretty large leap from that sentence to a larger
understanding of execution context.

IRP_MJ_CLEANUP is not as straightforward, if you check the FASTFAT source
there is no dependency on the current process (though FAT does assume it can
retrieve the original requestor’s process from the IRP). Other filters or
file systems may not be as forgiving though (or maybe they were historically
not as forgiving). This led to the general guidance of “there’s process
specific teardown that has to be done in IRP_MJ_CLEANUP, don’t post it”.
YMMV, though I suspect (but don’t know) that FM’s lack of synchronization of
this request was a specific decision as opposed to an oversight.

FM just guarantees that you’ll be called in the same context as your
preoperation callback, NOT that you’ll be called in the context of the
original requestor. This is clear in the same docs linked to above:

"The filter manager calls the minifilter driver’s postoperation callback
routine in the same thread context as the preoperation callback, at IRQL <=
APC_LEVEL. (Note that this thread context is not necessarily the context of
the originating thread.) "

-scott
OSR
@OSRDrivers

“Jason Miller (jasomil2)” wrote in message news:xxxxx@ntfsd…

Scott,

Thank you very much for the detailed response; it clears up remaining dark
corner of this discussion nicely for me.

The conventional wisdom is that for IRP_MJ_CREATE and IRP_MJ_CLEANUP, it’s
either impossible or unwise to make things “look” sufficiently like the
original context to not break anything. IRP_MJ_CLEANUP has always had a
bit of a sordid history in this regard as it really *should* be possible,
but it’s frequently avoided (e.g. we’ve had issues in the past with byte
range locks not breaking because someone was trying to break them for the
current process, not the requesting process). IRP_MJ_CLOSE is fine to post
as it’s always sent from the System process anyway.

Context requirements strike me as either a documentation omission (your
response made the requirements clear) or a missing case in the Filter
Manager, although I bet this is far more clear to those familiar with
old-style filter drivers, and only less so to people like me walking into
the Minifilter documentation without that background.

Of course, completion continues to not matter, because it was never
guaranteed anyway. FM does provide an option to have your postoperation
callback called in the same execution context as your preoperation
callback (FLT_PREOP_SYNCHRONIZE), but that’s just FM synchronously waiting
after calling your preoperation before calling your postoperation.

If context during the pre-callback execution chain must be preserved in
certain circumstances, I would have assumed this would be clearly spelled
out in the PFLT_PRE_OPERATION_CALLBACK [1] documentation, or that the
Filter Manager would internally wait on an event in the thread returning
FLT_PREOP_PENDING so that processing continued in the proper context
following FltCompletePendedPreOperation being called with a non-completion
(FLT_PREOP_SUCCESS*) CallbackStatus (which I assumed would set said event,
not continue processing the chain in the “completing” thread.)

Also, I would assume FM must do a check exactly before the post-callback for
every minifilter returning FLT_PREOP_SYNCHONIZE in a pre-callback to
ensure that an earlier minifilter didn’t change the context, and that this
check and context-switch might occur multiple times for a single IRP if
there are multiple minifilters that finish the callback in a different
context than it was started in? Or is this another gotcha?

Cheers,

J.

[1]
http://msdn.microsoft.com/en-us/library/windows/hardware/ff551109(v=vs.85).aspx,
or perhaps in the FltCompletePendedPreOperation.