IRP_MJ_CREATE - IRQL of Pre and Post Handlers?

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.

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

Now i believe too.

Let’s refocus this:
I need to call a few passive level only routines in PRE create. As such, if
this can ever be called at anything other than passive, I absolutely must
defer in the case where this happens only very rarely as reliability trumps
performance for my use case. I hate to put code in here that will never
execute, but it appears there is a conflict in the community knowledge base
where one says only passive level and another says it can be greater than
in the rare case. Is my reading comprehension so lacking? The MSDN
documentation is explicit about the Post Create, but is ambiguous on the
Pre, perhaps that is the ultimate source of the confusion.

On Monday, October 31, 2016, Anatoly Mikhailov wrote:

> > I believe Tony talked about IRP completion which can happen at IRQL <=
> DISPATCH_LEVEL.
> >
> Now i believe too.
>
>
> — NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis,
> WDF, Windows internals and software drivers! Details at To unsubscribe,
> visit the List Server section of OSR Online at

Tony was talking about postcreate. Hypothetically it can be called above
PASSIVE_LEVEL. But in practice this is rather rare. As for precreate, it is
always called at PASSIVE_LEVEL.

1 нояб. 2016 г. 7:06 AM пользователь “Jesse Conn”
написал:

> Let’s refocus this:
> I need to call a few passive level only routines in PRE create. As such,
> if this can ever be called at anything other than passive, I absolutely
> must defer in the case where this happens only very rarely as reliability
> trumps performance for my use case. I hate to put code in here that will
> never execute, but it appears there is a conflict in the community
> knowledge base where one says only passive level and another says it can be
> greater than in the rare case. Is my reading comprehension so lacking? The
> MSDN documentation is explicit about the Post Create, but is ambiguous on
> the Pre, perhaps that is the ultimate source of the confusion.
>
> On Monday, October 31, 2016, Anatoly Mikhailov
> wrote:
>
>> > I believe Tony talked about IRP completion which can happen at IRQL <=
>> DISPATCH_LEVEL.
>> >
>> Now i believe too.
>>
>>
>> — NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis,
>> WDF, Windows internals and software drivers! Details at To unsubscribe,
>> visit the List Server section of OSR Online at
>
> — NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis,
> WDF, Windows internals and software drivers! Details at To unsubscribe,
> visit the List Server section of OSR Online at

Let’s talk purely in terms of the I/O Manager and leave Filter Manager our
of it for the moment.

The *only* way to generate an IRP_MJ_CREATE request in Windows is to call
ZwCreateFile*. ZwCreateFile will build an IRP and send it to the dispatch
entry point of the target driver. ZwCreateFile does not change the IRQL as
part of the call. According to the ZwCreateFile documentation:

“Callers of ZwCreateFile must be running at IRQL = PASSIVE_LEVEL and
with special kernel APCs enabled.”

Therefore, by design Windows sends IRP_MJ_CREATE requests at PASSIVE_LEVEL.

Filter Manager abstracts out the dispatching of the IRP and calls you at
your PreCreate callback when it receives the IRP. FltMgr does not change the
IRQL, thus your PreCreate callback is called at PASSIVE_LEVEL.

If a driver raises the IRQL and calls ZwCreateFile, they’re hosed. If a
higher altitude minifilter changes the IRQL in PreCreate and doesn’t restore
it, they’re hosed. Trying to defend against this sort of thing leads to
madness. A driver could send me invalid arguments, or call me at a bad IRQL,
or corrupt my data structures, or do any other sorts of horrid things. Yes,
my customers will come to ME with the problems that arise, but that’s life
in the fast lane (and a scan for other third party drivers is usually my
first step in analysis). Note that Verifier should catch these types of
problems and blame the offending driver, so you have that at least.

Going back to IRP talk, if I want to post-process the create IRP I need to
set a completion routine and send it along. When the target driver is done
with the IRP, I get called back at my completion routine at IRQL <=
DISPATCH_LEVEL.

FltMgr *always* synchronizes the call between PreCreate and PostCreate. What
this means is that if the lower driver pends the request, FltMgr will block
in thread context and then call your PostCreate routine when the lower
filter is done. FltMgr does not change the IRQL, thus you are called in
PostCreate at IRQL PASSIVE_LEVEL.

*Building your own create IRP with IoAllocateIrp was never supported and is
a tremendously bad idea these days

-scott
OSR
@OSRDrivers

“Anatoly Mikhailov” wrote in message
news:xxxxx@ntfsd…

Tony was talking about postcreate. Hypothetically it can be called above
PASSIVE_LEVEL. But in practice this is rather rare. As for precreate, it is
always called at PASSIVE_LEVEL.

1 нояб. 2016 г. 7:06 AM пользователь “Jesse Conn”
написал:
Let’s refocus this:
I need to call a few passive level only routines in PRE create. As such, if
this can ever be called at anything other than passive, I absolutely must
defer in the case where this happens only very rarely as reliability trumps
performance for my use case. I hate to put code in here that will never
execute, but it appears there is a conflict in the community knowledge base
where one says only passive level and another says it can be greater than in
the rare case. Is my reading comprehension so lacking? The MSDN
documentation is explicit about the Post Create, but is ambiguous on the
Pre, perhaps that is the ultimate source of the confusion.

On Monday, October 31, 2016, Anatoly Mikhailov wrote:

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

— NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis, WDF,
Windows internals and software drivers! Details at To unsubscribe, visit the
List Server section of OSR Online at
— NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis, WDF,
Windows internals and software drivers! Details at To unsubscribe, visit the
List Server section of OSR Online at

A+! Many thanks for putting it all in context start to finish.

I appreciate all the feedback. I inherited a mess of an undocumented mini
filter driver, which was obviously a copy paste recompile til it compiled
design that was littered with huge architectural problems and “random blue
screens we don’t understand”… I’ve been doing a careful redesign, one
that is hopefully much more maintainable. Thanks for filling in the
knowledge gaps :slight_smile:

On Tuesday, November 1, 2016, Scott Noone wrote:

> Let’s talk purely in terms of the I/O Manager and leave Filter Manager our
> of it for the moment.
>
> The only way to generate an IRP_MJ_CREATE request in Windows is to call
> ZwCreateFile*. ZwCreateFile will build an IRP and send it to the dispatch
> entry point of the target driver. ZwCreateFile does not change the IRQL as
> part of the call. According to the ZwCreateFile documentation:
>
> “Callers of ZwCreateFile must be running at IRQL = PASSIVE_LEVEL and
> with special kernel APCs enabled.”
>
> Therefore, by design Windows sends IRP_MJ_CREATE requests at PASSIVE_LEVEL.
>
> Filter Manager abstracts out the dispatching of the IRP and calls you at
> your PreCreate callback when it receives the IRP. FltMgr does not change
> the IRQL, thus your PreCreate callback is called at PASSIVE_LEVEL.
>
> If a driver raises the IRQL and calls ZwCreateFile, they’re hosed. If a
> higher altitude minifilter changes the IRQL in PreCreate and doesn’t
> restore it, they’re hosed. Trying to defend against this sort of thing
> leads to madness. A driver could send me invalid arguments, or call me at a
> bad IRQL, or corrupt my data structures, or do any other sorts of horrid
> things. Yes, my customers will come to ME with the problems that arise, but
> that’s life in the fast lane (and a scan for other third party drivers is
> usually my first step in analysis). Note that Verifier should catch these
> types of problems and blame the offending driver, so you have that at least.
>
> Going back to IRP talk, if I want to post-process the create IRP I need to
> set a completion routine and send it along. When the target driver is done
> with the IRP, I get called back at my completion routine at IRQL <=
> DISPATCH_LEVEL.
>
> FltMgr always synchronizes the call between PreCreate and PostCreate.
> What this means is that if the lower driver pends the request, FltMgr will
> block in thread context and then call your PostCreate routine when the
> lower filter is done. FltMgr does not change the IRQL, thus you are called
> in PostCreate at IRQL PASSIVE_LEVEL.
>
> *Building your own create IRP with IoAllocateIrp was never supported and
> is a tremendously bad idea these days
>
> -scott
> OSR
> @OSRDrivers
>
> “Anatoly Mikhailov” wrote in message
> news:xxxxx@ntfsd…
>
> Tony was talking about postcreate. Hypothetically it can be called above
> PASSIVE_LEVEL. But in practice this is rather rare. As for precreate, it is
> always called at PASSIVE_LEVEL.
>
>
> 1 нояб. 2016 г. 7:06 AM пользователь “Jesse Conn”
> написал:
> Let’s refocus this:
> I need to call a few passive level only routines in PRE create. As such,
> if this can ever be called at anything other than passive, I absolutely
> must defer in the case where this happens only very rarely as reliability
> trumps performance for my use case. I hate to put code in here that will
> never execute, but it appears there is a conflict in the community
> knowledge base where one says only passive level and another says it can be
> greater than in the rare case. Is my reading comprehension so lacking? The
> MSDN documentation is explicit about the Post Create, but is ambiguous on
> the Pre, perhaps that is the ultimate source of the confusion.
>
> On Monday, October 31, 2016, Anatoly Mikhailov
> wrote:
>
>
> I believe Tony talked about IRP completion which can happen at IRQL <=
>> DISPATCH_LEVEL.
>>
>> Now i believe too.
>
>
>
> — NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis,
> WDF, Windows internals and software drivers! Details at To unsubscribe,
> visit the List Server section of OSR Online at
> — NTFSD is sponsored by OSR MONTHLY seminars on crash dump analysis,
> WDF, Windows internals and software drivers! Details at To unsubscribe,
> visit the List Server section of OSR Online at
>
> —
> 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:>

Pre-Create is called in the context of the I/O Manager operation (so IopParseDevice or IopParseFile calls filter manager, which calls your mini-filter.)

Thus, it is at IRQL == PASSIVE_LEVEL with special kernel APCs enabled (filter manager doesn’t change this). The I/O Manager does not ensure that completion routines (“post create”) are called at passive level - this is a specific feature of Filter Manager.

It’s possible other drivers could violate these restrictions, but then they’re broken as they have not “played by the rules”. If you try to write code to defend against this level of malfunction, you will drive yourself insane.

Tony
OSR

The fact that ZwCreateFile must be called at passive level (*and* with special kernel APCs enabled) is not germane to the IRQL of the completion routine, though. Thus, as I said, it is almost always called at passive level but it is not safe to assume that is the case.

Mini-filters, however, have the added functionality provided by Filter Manager - it handles this case and ensures that the post create function is invoked at passive level, with special kernel APCs enabled. In addition, it also guarantees that it is in the original thread context.

Tony
OSR