How often should we check the IRQL? what is the best practice?

@Mark_Roddy said:
the dbgprint restriction is quite simple: don’t use wide string formats in code that can be run at >= DISPATCH_LEVEL. Each api, in general, clearly states its IRQL requirements. You are overthinking the problem, the solution is exactly as Anton stated.

But i have tons of DbgPrints already in my codes that use %ws, and i need to keep these DbgPrints, so the only solutions are to check the IRQL in the start of every dispatch function, OR convert every wide string to ascii string and then pass that ascii to DbgPrint, correct?

Also if i go with the IRQL checking path, do i need to check the IRQL before every DbgPrint that has %ws, or just checking it one time in the start of dispatch function is enough?

In the typical driver, the DISPATCH sections are usually fairly well contained. What are you doing that might have this problem?

@Tim_Roberts said:
In the typical driver, the DISPATCH sections are usually fairly well contained. What are you doing that might have this problem?

Sorry for rookie question but what do you mean by DISPATCH section? do you mean my dispatch functions? because when you say section i think of the sections in the PE structure.

I am trying to make sure my code does not cause any BSOD because of IRQL. just want to write a clean and standard code. so do expert driver developers ever check IRQL in their dispatch functions to make sure is correct, or they just write their code in such a way that there is no need to worry about IRQL? and is it possible that in the middle of my dispatch function IRQL get raised by another kernel module?

dispatch functions: the ‘top level’ callbacks into your driver, contrasted with interrupt and dpc callbacks, all of which run at >= DISPATCH_LEVEL.

IRQL is not going to change within your callbacks unless you change the IRQL, by for example acquiring a spinlock.

By DISPATCH, I mean those parts of the code that run at DISPATCH_LEVEL. There are many kinds of drivers that spend very little time above PASSIVE_LEVEL, and others that have to worry about it. Typically, you won’t be encountering UNICODE_STRINGs above PASSIVE_LEVEL.

@Tim_Roberts said:
By DISPATCH, I mean those parts of the code that run at DISPATCH_LEVEL.

But as i said, i never raise the IRQL myself ?

So to recap, assuming i never raise the IRQL myself, my driver startup and unload function always run at PASSIVE_LEVEL. but my major functions such as the one responsible IRP_MJ_DEVICE_CONTROL, could get called, at a higher IRQL than the PASSIVE_LEVEL. is this correct? if so, how common is this to happen, meaning a major function that i implemented for god knows why getting called at with a IRQL higher than PASSIVE_LEVEL? (again, assume that i never raise the IRQL myself in my code)

If your dispatch routines are being called from user-mode, they will be at PASSIVE_LEVEL. It is possible for a driver to call your dispatch routines after having raised the IRQL, but that would be in violation of your contract.

@Tim_Roberts said:
If your dispatch routines are being called from user-mode, they will be at PASSIVE_LEVEL. It is possible for a driver to call your dispatch routines after having raised the IRQL, but that would be in violation of your contract.

So if none of my major functions (this is what i mean by dispatch functions) are called by another driver, i am fine and there is no need to worry about IRQL being higher than PASSIVE_LEVEL when the major function is called, correct? because in my scenario, my major functions are intended for user mode communication, so i assume no other driver should be calling my major functions (why would they?)

With all due respect, this is a very scary thread.

You are writing kernel-mode code, but you don’t understand the concept of IRQLs. That’s not good, no matter how you look at it. That’s a bit like driving a car, but not understanding the concept of the brake pedal.

Peter

If you are writing a virtual driver that doesn’t have any hardware beneath you, then you will probably not encounter DISPATCH_LEVEL unless you need to grab a spinlock. Such a driver has few reasons to use a DPC. Drivers driving real hardware have many more conditions to worry about.

If you are using the driver framework you can require passive level for all your dispatch callbacks and stop worrying about it.

@“Peter_Viscarola_(OSR)” said:
With all due respect, this is a very scary thread.

You are writing kernel-mode code, but you don’t understand the concept of IRQLs. That’s not good, no matter how you look at it. That’s a bit like driving a car, but not understanding the concept of the brake pedal.

Peter

Sorry Peter, although i did mention in my question that its a rookie one but i apologize again, I am still learning… i would really appreciate if you can suggest a good article/source so i can completely learn everything i need about IRQLs in the context of windows kernel programming.

This is a quote from Windows kernel programming book:

The relevant dispatch routine (based on the major function code) is the first routine in a driver that sees the request. Normally, it’s called by the requesting thread context, i.e. the thread that called the relevant API (e.g. ReadFile) in IRQL PASSIVE_LEVEL (0). However, it’s possible that a filter driver sitting on top of this device sent the request down in a different context - it may be some other thread unrelated to the original requestor and even in higher IRQL, such as DISPATCH_LEVEL (2).

This is whats confusing me, why would a filter driver raise the IRQL but before reverting it, calls another driver? this seems to be something very rare too if i am not mistaken, because i myself have never encountered any BSOD in my drivers even tho i never assumed my dispatch routines could be called at a higher IRQL than passive…

@Tim_Roberts said:
If you are writing a virtual driver that doesn’t have any hardware beneath you, then you will probably not encounter DISPATCH_LEVEL unless you need to grab a spinlock.

Tim what are your thoughts on the quote from kernel programming book? so this means that the only way that the dispatch routine in my virtual driver gets called with a higher IRQL than passive is if a filter driver that is attached to the device raises the IRQL and “forgets” to lower it before calling my dispatch routine, correct? still doesn’t make any sense, because why would anyone raise the IRQL and call another driver before lowering it… the same book says that we should never do this and always revert the IRQL after we are done in the same function.

@Mark_Roddy said:
If you are using the driver framework you can require passive level for all your dispatch callbacks and stop worrying about it.

I have never used the driver framework, but how does it stop other drivers such as upper filter drivers from calling my dispatch routine after raising IRQL? also sorry for wasting your time by asking these rookie questions, as i said i am still learning and never claimed to be an expert in this area.

The filter (or any other kernel mode component sending the IRP to your driver) could be sending the IO request from a DPC. Another scenario, however unlikely and potentially incorrect, is that the caller is sending the IO while hold a spinlock. In both cases, sender of the IO is not forgetting to lower IRQL while you are processing the IO.

The framework queues a work item to defer execution to passive level in the case the IO arrives at IRQL > PASSIVE_LEVEL. The source for WDF is available on github, you can see for yourself how it is implemented.

I have never used the driver framework, but how does it stop other drivers such as upper filter drivers from calling my dispatch routine after raising IRQL?

The point is, you establish a contract that your dispatch routines are called as PASSIVE_LEVEL. If some moron filter driver send you an IRP at DISPATCH_LEVEL, then the BSOD is their fault. You could defend against it, but is it really worth the trouble? Any cooperative filter driver is going to comply.

but is it really worth the trouble?

WDF. PASSIVE_LEVEL Execution Constraint. Problem solved.

Peter

or just don’t use those format specifiers.

This is whats confusing me, why would a filter driver raise the IRQL but before reverting it, calls another driver

Simply because it may submit an IRP in context of a DPC…

For example, consider the following scenario. Say, you are in the middle of the stack, and the driver at the bottom of the stack completes a request at DISPATCH_LEVEL. This will result in invocation of all completion routines registered by the drivers. Therefore, all these calls will be made at DISPATCH_LEVEL.

Now consider what happens if some driver above yours on the stack decides to submit a new IRP in context of a completion routine, so that this IRP traverses down the stack, eventually reaching your driver. This is just one possible scenario when you may potentially receive an IRP at elevated IRQL

how does it stop other drivers such as upper filter drivers from calling my dispatch routine after raising IRQL?

As long as all the requests to your driver have to pass through some framework, this framework can simply queue a workitem. As a result, the request will be actually sent to your driver in context of a system thread, no matter in which context it was submitted…

Anton Bassov

@“Peter_Viscarola_(OSR)” said:
WDF. PASSIVE_LEVEL Execution Constraint. Problem solved.

@Tim_Roberts said:
The point is, you establish a contract that your dispatch routines are called as PASSIVE_LEVEL. If some moron filter driver send you an IRP at DISPATCH_LEVEL, then the BSOD is their fault. You could defend against it, but is it really worth the trouble? Any cooperative filter driver is going to comply.

So if i use WDF with PASSIVE_LEVEL Execution Constraint, will it cause my major functions to all execute at PASSIVE_LEVEL? or is it just for switching the blame for the BSOD to the faulting filter driver?

will it cause my major functions to all execute at PASSIVE_LEVEL

Yes. Well, no. Well… huh?? What do you mean by “major functions” – that’s not a WDM or WDF term, as far as I know?

If you mean I/O Event Processing Callbacks for Requests (such as Read, Write, and DeviceControl)? Then, yes. It will entirely avoid your EvtIoRead, EvtIoWrite, or EvtIoDeviceControl ever being called at an IRQL other than IRQL PASSIVE_LEVEL. So, you’ll be 100% good to go.

Peter