IRP_MJ_CREATE - IRQL of Pre and Post Handlers?

Struggling to find consistent documentation on what IRQL the pre and post IRP_MJ_CREATE handlers are called at. What I need to do is call some PASSIVE_LEVEL only routines on the create path, and I’m trying to determine if I need to defer the work to a passive level worker, or if I can call the routines directly in the handlers.

Is the following true?
“If a minifilter driver has registered preoperation and postoperation callback routines for IRP_MJ_CREATE operations, the post-create callback routine is called at IRQL = PASSIVE_LEVEL, in the same thread context as the pre-create callback routine.”

The MSDN documentation led me to believe that pre-routines can be called at both PASSIVE_LEVEL and APC_LEVEL. Is this true though for the Create pre routine, or will the create pre only be called at PASSIVE_LEVEL? If the create pre can be called at APC_LEVEL, I don’t understand how the previous statement could be true. If it’s running in the same thread context as the pre-create, which may be at APC_LEVEL, then the post routine would also be running at APC_LEVEL…

I did find the following necro thread which somewhat discusses this, but does not clarify the IRQL of the Pre-Create routine: http://www.osronline.com/showthread.cfm?link=136072
Rather large discussion for something that should be pretty clear, I still can’t decipher an answer.

IRP_MJ_CREATE is always sent at PASSIVE_LEVEL by IO manager. You can consider this as a design feature. If you observe IRP_MJ_CREATE at APC_LEVEL you can bet there is a faulty driver in the system.

FilterManager guaranties that post callback is also called at PASSIVE_LEVEL.

Okay! That being said, a misbehaving higher level filter driver could pend and raise the IRQL… I suppose defensively I could detect that condition, and lower the IRQL myself. This may cause issues in the faulty filter, but at least I get to operate as planned?

There is no code flow at APC_LEVEL that results in issuing IRP_MJ_CREATE . This provides a guarantee of PASSIVE_LEVEL for IRP_MJ_CREATE.

You must not lower IRQL if you have not raised it. If you detected a wrong condition complete request with an error.

Some requests are synchronous and other are asynchronous. IRP_MJ_CREATE
request is synchronous one. That means a thread sent this request will
block until this request is completed. IRP_MJ_CREATE request is sent always
at PASSIVE_LEVEL. For this reason all filters forward request down the
stack and wait for event to be signaled on request completion by all lower
drivers of the stack. Thus before forwarding you are at PASSIVE_LEVEL and
after request completion by lower drivers you are at PASSIVE_LEVEL again.
No one forward this request at IRQL above PASSIVE_LEVEL because this leads
to faulty behavior of FSD first of all. You can queue work to some thread
to continue request processing. But it’ll be at PASSIVE_LEVEL again. This
is what filters usually do including filter manager. So you can be sure
your pre and post routines would be called at PASSIVE_LEVEL.

2016-10-31 21:42 GMT+03:00 :

> Struggling to find consistent documentation on what IRQL the pre and post
> IRP_MJ_CREATE handlers are called at. What I need to do is call some
> PASSIVE_LEVEL only routines on the create path, and I’m trying to determine
> if I need to defer the work to a passive level worker, or if I can call the
> routines directly in the handlers.
>
> Is the following true?
> “If a minifilter driver has registered preoperation and postoperation
> callback routines for IRP_MJ_CREATE operations, the post-create callback
> routine is called at IRQL = PASSIVE_LEVEL, in the same thread context as
> the pre-create callback routine.”
>
> The MSDN documentation led me to believe that pre-routines can be called
> at both PASSIVE_LEVEL and APC_LEVEL. Is this true though for the Create pre
> routine, or will the create pre only be called at PASSIVE_LEVEL? If the
> create pre can be called at APC_LEVEL, I don’t understand how the previous
> statement could be true. If it’s running in the same thread context as the
> pre-create, which may be at APC_LEVEL, then the post routine would also be
> running at APC_LEVEL…
>
>
>
> —
> NTFSD is sponsored by OSR
>
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at <
> http://www.osronline.com/page.cfm?name=ListServer&gt;
></http:>

You will queue work to a thread if you want to be protected from such
drivers. But in my practice i never saw this. As it was told by slavaim you
can’t lower IRQL if you didn’t raise it.

This might not work with some FSDs. Network redirectors( e.g. RDPDR and Citrix ) might associate session information with a user process. If they are called in SYSTEM thread context for create request then PATH_NOT_FOUND is returned. KeStackAttachProcess might help but it is beyond this discussion.

Trying not to get wrapped up in this worst case scenario, so please add some clarification to this.

Could a faulty driver that would raise the IRQL in the create path seemingly operate on a system with no obvious side effects, and only cause an error in my filter, thus making my driver appear to be at fault… or will it be obvious the other driver is at fault?

As for the “thou shall not lower IRQL if you did not raise it”, the same goes for “thou shall not raise the irql in the create path, and not lower it to the previous before passing it along the stack”. The fatal design flaw was in the faulty driver.

https://msdn.microsoft.com/en-us/library/windows/hardware/ff537942(v=vs.85).aspx
This shows what I believe to be a valid example of safely lowering the IRQL? Would it really be so terrible to correct the fault of a driver up the stack, as opposed to just erroring out?

Floating-point is a special case. You should study IRQL role first. If you
lower IRQL you can for example cause deadlock.

2016-10-31 22:59 GMT+03:00 :

> Trying not to get wrapped up in this worst case scenario, so please add
> some clarification to this.
>
> Could a faulty driver that would raise the IRQL in the create path
> seemingly operate on a system with no obvious side effects, and only cause
> an error in my filter, thus making my driver appear to be at fault… or
> will it be obvious the other driver is at fault?
>
> As for the “thou shall not lower IRQL if you did not raise it”, the same
> goes for “thou shall not raise the irql in the create path, and not lower
> it to the previous before passing it along the stack”. The fatal design
> flaw was in the faulty driver.
>
> https://msdn.microsoft.com/en-us/library/windows/hardware/
> ff537942%28v=vs.85%29.aspx
> This shows what I believe to be a valid example of safely lowering the
> IRQL? Would it really be so terrible to correct the fault of a driver up
> the stack, as opposed to just erroring out?
>
>
> —
> NTFSD is sponsored by OSR
>
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at <
> http://www.osronline.com/page.cfm?name=ListServer&gt;
></http:>

So you don’t support or condone this code in a PreCreate handler? I agree this should largely not even need to be present, but I have seen several posts by people who have allegedly seen the PreCreate handler called at IRQL > PASSIVE_LEVEL. This seems to be completely insane to have to consider this case. The implications of defensively coding everything because you can’t trust what’s running the kernel seems ludicrous.

FLT_ASSERT(PASSIVE_LEVEL == KeGetCurrentIrql());
if (PASSIVE_LEVEL != KeGetCurrentIrql()) {
//
// By design the IO manager should call this at PASSIVE_LEVEL; however, a faulty driver in the
// stack could elevate the IRQ level which would cause us to fault in our below routines.
// Allegedly the only sane thing to do is to add the complexity of deferring this processing
// to a passive level worker thread… but this condition would cause a general instability of
// the file system.
//

// TODO: Log this error condition!!!
// TODO: if we ever see the condition, defer processing to a PASSIVE_LEVEL worker

//
// Hack here, though this is just cleaning up the faulty state set by a previous faulty driver.
//
KeLowerIrql(PASSIVE_LEVEL);
}

There must not be such implementations of preCreate you just showed.

but I have seen several posts by people who have allegedly seen the
PreCreate handler called at IRQL > PASSIVE_LEVEL

Could they make mistake? I think yes.

Thanks again for the added clarity!

Don’t conflate filter manager behavior with I/O Manager behavior. Filter Manager guarantees that post create is called at passive level. The I/O manager makes no such guarantee - though the reality is that it is *almost always* called at passive level.

This is documented here: http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/filterdriverdeveloperguide.doc

This is also discussed here - https://www.osronline.com/showthread.cfm?link=237151

Tony
OSR

Tony,

After reading the guide, and the thread, I suppose I’m reverting back to my previous conclusion.

In my PRE create handler:

  1. If IRQL == PASSIVE_LEVEL, do my processing.
  2. Else If IRQL > PASSIVE_LEVEL, push onto a callback data queue for deferred processing, and return FLT_PREOP_PENDING.

I had implemented this but it seemed to be an over design, now I’m led to believe this was the appropriate solution?

As for the differences between the IO manager, and the Filter manager… are you suggesting that the Pre Create handler is in the domain of the IO manager, and the Post Create is within the Filter manager? That was not clear. You stated the filter manager will enforce the post create it called as passive, what of the pre create?

> The I/O manager makes no such guarantee - though the reality is that it
is *almost always* called at passive level.

But ZwCreateFile, for example, must be called at PASSIVE_LEVEL as
documented on MSDN.

As for the differences between the IO manager, and the Filter manager…

I/O manager is windows subsystem which give you interface to send I/O
requests. Filter Manager is filter driver which gives you framework for
file system filtering.

This was redundant. If a filter receives create at APC_LEVEL the system is already crippling and you make a bad situation worse by deferring IRP_MJ_CREATE in a worker thread.

I believe Tony talked about IRP completion which can happen at IRQL <= DISPATCH_LEVEL.

Pre and Post are both the responsibility of the Filter Manager, IO Manager knows nothing about these callbacks.