function IRQL dependency

Hey everyone,
I am new to this type of programming and before I dive into it I am trying
to get a better understanding of IRQLs. I have looked at the documentation
for various functions to see what IRQL they should be called at and for
experiments sake I tried calling them at an IRQL too high. I expected a
crash or something like that but I really didn’t notice anything. Below are
some simple examples of what I’ve been playing with:

KeRaiseIrql(HIGH_LEVEL, &OldIrql);
CurrentIrql = KeGetCurrentIrql();
DbgPrint(“raised IRQL: %d\n”, CurrentIrql);
KeLowerIrql(&OldIrql);

I didn’t expect this to work since the documentation I looked at said
DbgPrint should be called at IRQL <= DIRQL.
However when I look at the DbgView output I see “raised IRQL: 30” clearly.

I also tried running KeDelayExecutionThread in this manner at HIGH_LEVEL to
try to get some effect but it appeared to work fine as well despite the
documentation saying KeDelayExecutionThread needs to run at PASSIVE_LEVEL.

Could someone explain what is going on and why this is working despite
calling the functions at the wrong IRQLs? If I call them at the wrong IRQL
does the IRQL get changed automatically? Can my IRQL change without me
explicitly telling it to with KeLowerIrql/KeRaiseIrql. Any help would be
greatly appreciated!

Thanks a bunch!

Actually, the documentation is confusing here, you can call DbgPrint at any
IRQL as long as you do not use UNICODE and none of your arguments are
pageable.

On the case of KeDelayExecutionThread that will fail, but it needs certain
conditions for it to. When you are running these turn ou driver verfier and
turn on “Force IRQL Checking” this will cause these to fail.

A lot of the IRQL requirements are due to paged memory, so in a simple case
you can call the function and it will work, but if the system is in
contention it will page out the data or code the function needs and the
system will crash.

If at all possible you should move to WinDBG since user space debug tools
will not allow easy debugging of things like crashes.


Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

“Angela Fidler” wrote in message
news:xxxxx@ntdev…
> Hey everyone,
> I am new to this type of programming and before I dive into it I am trying
> to get a better understanding of IRQLs. I have looked at the documentation
> for various functions to see what IRQL they should be called at and for
> experiments sake I tried calling them at an IRQL too high. I expected a
> crash or something like that but I really didn’t notice anything. Below
> are
> some simple examples of what I’ve been playing with:
>
> KeRaiseIrql(HIGH_LEVEL, &OldIrql);
> CurrentIrql = KeGetCurrentIrql();
> DbgPrint(“raised IRQL: %d\n”, CurrentIrql);
> KeLowerIrql(&OldIrql);
>
> I didn’t expect this to work since the documentation I looked at said
> DbgPrint should be called at IRQL <= DIRQL.
> However when I look at the DbgView output I see “raised IRQL: 30” clearly.
>
> I also tried running KeDelayExecutionThread in this manner at HIGH_LEVEL
> to
> try to get some effect but it appeared to work fine as well despite the
> documentation saying KeDelayExecutionThread needs to run at PASSIVE_LEVEL.
>
> Could someone explain what is going on and why this is working despite
> calling the functions at the wrong IRQLs? If I call them at the wrong IRQL
> does the IRQL get changed automatically? Can my IRQL change without me
> explicitly telling it to with KeLowerIrql/KeRaiseIrql. Any help would be
> greatly appreciated!
>
> Thanks a bunch!
>
>
>
> Information from ESET NOD32 Antivirus, version of virus
> signature database 4334 (20090814)

>
> The message was checked by ESET NOD32 Antivirus.
>
> http://www.eset.com
>
>

Information from ESET NOD32 Antivirus, version of virus signature database 4334 (20090814)

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com

Thanks for your reply,
after playing with KeDelayExecutionThread I am still having a hard time understanding why it is working. My code is like the following:

KIRQL CurrentIrql;
KIRQL OldIrql;
LARGE_INTEGER x;

x.QuadPart = -30000000; //3 seconds i think

CurrentIrql = KeGetCurrentIrql();
DbgPrint(“current IRQL: %d\n”, CurrentIrql);

KeRaiseIrql(HIGH_LEVEL, &OldIrql);
CurrentIrql = KeGetCurrentIrql();
DbgPrint(“raised IRQL: %d\n”, CurrentIrql);

CurrentIrql = KeGetCurrentIrql();
DbgPrint(“IRQL before KeDelayExecutionThread: %d\n”, CurrentIrql);
KeDelayExecutionThread(KernelMode, FALSE, &x);

CurrentIrql = KeGetCurrentIrql();
DbgPrint(“IRQL AFTER KeDelayExecutionThread: %d\n”, CurrentIrql);
KeLowerIrql(&OldIrql);

I would expect this not to work since If I am really running at HIGH_LEVEL aren’t I running about the system clock and so sleep functions based on time should fail? Here is the output I get:

current IRQL: 0
raised IRQL: 30
IRQL before KeDelayExecutionThread: 29
IRQL AFTER KeDelayExecutionThread: 29

Another question is why is my IRQL dropping before KeDelayExecutionThread?

Thanks in advance!
Angela

The result of calling these APIs at an elevated IRQL is undefined. You might
find some that work sometimes, some that don’t work at all, or some that end
up doing weird things.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> Thanks for your reply,
> after playing with KeDelayExecutionThread I am still having a hard time
> understanding why it is working. My code is like the following:
>
> KIRQL CurrentIrql;
> KIRQL OldIrql;
> LARGE_INTEGER x;
>
> x.QuadPart = -30000000; //3 seconds i think
>
> CurrentIrql = KeGetCurrentIrql();
> DbgPrint(“current IRQL: %d\n”, CurrentIrql);
>
> KeRaiseIrql(HIGH_LEVEL, &OldIrql);
> CurrentIrql = KeGetCurrentIrql();
> DbgPrint(“raised IRQL: %d\n”, CurrentIrql);
>
> CurrentIrql = KeGetCurrentIrql();
> DbgPrint(“IRQL before KeDelayExecutionThread: %d\n”, CurrentIrql);
> KeDelayExecutionThread(KernelMode, FALSE, &x);
>
> CurrentIrql = KeGetCurrentIrql();
> DbgPrint(“IRQL AFTER KeDelayExecutionThread: %d\n”, CurrentIrql);
> KeLowerIrql(&OldIrql);
>
> I would expect this not to work since If I am really running at HIGH_LEVEL
> aren’t I running about the system clock and so sleep functions based on
> time should fail? Here is the output I get:
>
> current IRQL: 0
> raised IRQL: 30
> IRQL before KeDelayExecutionThread: 29
> IRQL AFTER KeDelayExecutionThread: 29
>
> Another question is why is my IRQL dropping before KeDelayExecutionThread?
>
> Thanks in advance!
> Angela
>
>
>
>

>like that but I really didn’t notice anything.

So what? in your small test, it was OK.

But it is not guaranteed to be OK in any scenario, which means that such code is a bug waiting to happen.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

> So what? in your small test, it was OK. But it is not guaranteed to be OK in any scenario,

I would understand why the test was successful if he tried to access pageable memory, i.e. he was just lucky on this particular occasion because the target page was resident in RAM. However, I just refuse to understand how he managed to successfully make a blocking call in atomic context - there is a good chance that the OP has accedintally discovered a bug in Windows dispatcher…

Anton Bassov

wrote in message news:xxxxx@ntdev…
> I would understand why the test was successful if he tried to access
> pageable memory, i.e. he was just lucky on this particular occasion
> because the target page was resident in RAM. However, I just refuse to
> understand how he managed to successfully make a blocking call in atomic
> context - there is a good chance that the OP has accedintally discovered a
> bug in Windows dispatcher…
>

While the rule is that we are not allowed to wait at DISPATCH_LEVEL we have
seen in previous discussions and tests in which you were also involved that
the scheduler is well equipped to sleep a thread running at DISPATCH_LEVEL
and add it to the waiting list for a dispatcher object and resume if the
object is signalled. The only problem with this approach is that it “breaks
the contract” that a thread running at DISPATCH_LEVEL cannot be preempted
and with this the driver verifier and checked build sanity checks.

//Daniel

BTW what is discussed here is not an ISR or DPC but a regular thread
self-raised to HIGH_LEVEL. Also there is no spinlock held otherwise one
could easily deadlock here.

//Daniel

wrote in message news:xxxxx@ntdev…
> While the rule is that we are not allowed to wait at DISPATCH_LEVEL we
> have seen in previous discussions and tests in which you were also
> involved that the scheduler is well equipped to sleep a thread running at
> DISPATCH_LEVEL and add it to the waiting list for a dispatcher object and
> resume if the object is signalled. The only problem with this approach is
> that it “breaks the contract” that a thread running at DISPATCH_LEVEL
> cannot be preempted and with this the driver verifier and checked build
> sanity checks.
>
> //Daniel
>

> The only problem with this approach is that it “breaks the contract” that a thread running at >DISPATCH_LEVEL cannot be preempted

Elevated IRQL is just a Windows notion of atomic context - by raising IRQL >=DPC level you tell the dispatcher “please don’t perform context switches on this CPU because doing so may have disastrous consequences, until I indicate that it can get safely done”. Consider what can happen if you hold a spinlock or run DPC routine and some other thread is schedules on CPU meanwhile. Dispatcher has no means of knowing that performing context switch at the moment is unsafe, does it. This is what the concept of elevated IRQL is all about - to let dispatcher know that it should not perform context switches at the moment. This is just a convention that system dispatcher is build around.

Although , as we can see, Windows does not seem to enforce this “contract” in some situations, it is
obviously just a bug that they will (hopefully) fix…

Anton Bassov

> Thanks for your reply,

after playing with KeDelayExecutionThread I am still having a hard
time
understanding why it is working. My code is like the following:

KIRQL CurrentIrql;
KIRQL OldIrql;
LARGE_INTEGER x;

x.QuadPart = -30000000; //3 seconds i think

CurrentIrql = KeGetCurrentIrql();
DbgPrint(“current IRQL: %d\n”, CurrentIrql);

KeRaiseIrql(HIGH_LEVEL, &OldIrql);
CurrentIrql = KeGetCurrentIrql();
DbgPrint(“raised IRQL: %d\n”, CurrentIrql);

CurrentIrql = KeGetCurrentIrql();
DbgPrint(“IRQL before KeDelayExecutionThread: %d\n”,
CurrentIrql);
KeDelayExecutionThread(KernelMode, FALSE, &x);

CurrentIrql = KeGetCurrentIrql();
DbgPrint(“IRQL AFTER KeDelayExecutionThread: %d\n”,
CurrentIrql);
KeLowerIrql(&OldIrql);

I would expect this not to work since If I am really running at
HIGH_LEVEL
aren’t I running about the system clock and so sleep functions based
on time
should fail? Here is the output I get:

current IRQL: 0
raised IRQL: 30
IRQL before KeDelayExecutionThread: 29
IRQL AFTER KeDelayExecutionThread: 29

Another question is why is my IRQL dropping before
KeDelayExecutionThread?

I think the answer to all those questions (and more) is that if you do
things that Windows explicitly states are not allowed, you will either
crash or get unexpected results. If windows were to check every input
condition every single time a call was made it would run much slower -
that is why we have the verifier. So it assumes that the caller is doing
the right thing.

You are calling DbgPrint at >= DIRQL, which the docs say you can’t do,
and it would appear that one side-effect of doing so is that your IRQL
is changed. (either that or KeGetCurrentIrql() isn’t doing what you
expected… maybe change your code to:

KIRQL CurrentIrql, CurrentIrql2;

KeRaiseIrql(HIGH_LEVEL, &OldIrql);
CurrentIrql = KeGetCurrentIrql();
CurrentIrql2 = KeGetCurrentIrql();
DbgPrint(“raised IRQL: %d or %d\n”, CurrentIrql, CurrentIrql2);

Which would determine if it is the second call to KeGetCurrentIrql() or
the DbgPrint which is dropping the Irql.

It would be useful to check the return value of KeDelayExecutionThread()
and see if it returned STATUS_SUCCESS or some other value.

It might also be fun[1] to break into the debugger and watch exactly
what is happening during the call to KeDelayExecutionThread()… but
simply checking the return value might tell you something.

James

[1] if stepping through code in the debugger is your thing that is…

James Harper wrote:

I think the answer to all those questions (and more) is that if you do
things that Windows explicitly states are not allowed, you will either
crash or get unexpected results. If windows were to check every input
condition every single time a call was made it would run much slower -
that is why we have the verifier. So it assumes that the caller is doing
the right thing.

This is an excellent point, and one that might not be obvious to
newcomers. In Windows, kernel code is trusted code. It is assumed that
a kernel module knows what it is doing. If you violate the rules,
things explode, not because there is an explicit check, but because you
violate the assumptions of others.

In user-mode, we “trust but verify”. If you violate the rules, you get
an error.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>

> The only problem with this approach is that it “breaks the
contract” that a
thread running at >DISPATCH_LEVEL cannot be preempted

Elevated IRQL is just a Windows notion of atomic context - by raising
IRQL
>=DPC level you tell the dispatcher “please don’t perform context
switches on
this CPU because doing so may have disastrous consequences, until I
indicate
that it can get safely done”. Consider what can happen if you hold a
spinlock
or run DPC routine and some other thread is schedules on CPU
meanwhile.
Dispatcher has no means of knowing that performing context switch at
the
moment is unsafe, does it. This is what the concept of elevated IRQL
is all
about - to let dispatcher know that it should not perform context
switches
at the moment. This is just a convention that system dispatcher is
build
around.

Although , as we can see, Windows does not seem to enforce this
“contract” in
some situations, it is obviously just a bug that they will (hopefully)
fix…

If the contract says you can’t do it, and you do it anyway, is the
resulting behaviour really a bug? This is kernel space not user space,
so it is up to the caller to check the inputs, not the callee.

That said, the docs for KeRaiseIrql say “If the new IRQL is less than
the current IRQL, a bug check occurs”, and it clearly doesn’t under 2K3,
even when the verifier is running (just tried it [1]). If the first line
in KeDelayExecutionThread was KeRaiseIrql(APC_LEVEL, &old_irql) and
KeDelayExecutionThread was called at HIGH_LEVEL, the the current IRQL
would be changed to APC_LEVEL and old_irql = HIGH_LEVEL without any fuss
at all (aside from the obvious :slight_smile:

[1] The code I tested this with, which starts at APC_LEVEL is:

KIRQL old_irql1, old_irql2;
KdPrint((" A Irql = %d\n", KeGetCurrentIrql()));
KeRaiseIrql(HIGH_LEVEL, &old_irql1);
KdPrint((" B Irql = %d\n", KeGetCurrentIrql()));
KeRaiseIrql(PASSIVE_LEVEL, &old_irql2);
KdPrint((" C Irql = %d\n", KeGetCurrentIrql()));
KeLowerIrql(old_irql2);
KdPrint((" D Irql = %d\n", KeGetCurrentIrql()));
KeLowerIrql(old_irql1);
KdPrint((" E Irql = %d\n", KeGetCurrentIrql()));

And the output was:

A Irql = 1
B Irql = 31
C Irql = 0
D Irql = 31
E Irql = 1

James

And to add to this, one of the reasons some of us push so hard on using the
checked build. Since many of the checks needed for these things are in
ASSERTS that are present in the checked build of Windows.


Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

“Tim Roberts” wrote in message news:xxxxx@ntdev…
> James Harper wrote:
>> I think the answer to all those questions (and more) is that if you do
>> things that Windows explicitly states are not allowed, you will either
>> crash or get unexpected results. If windows were to check every input
>> condition every single time a call was made it would run much slower -
>> that is why we have the verifier. So it assumes that the caller is doing
>> the right thing.
>>
>
> This is an excellent point, and one that might not be obvious to
> newcomers. In Windows, kernel code is trusted code. It is assumed that
> a kernel module knows what it is doing. If you violate the rules,
> things explode, not because there is an explicit check, but because you
> violate the assumptions of others.
>
> In user-mode, we “trust but verify”. If you violate the rules, you get
> an error.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
>
> Information from ESET NOD32 Antivirus, version of virus
> signature database 4336 (20090814)

>
> The message was checked by ESET NOD32 Antivirus.
>
> http://www.eset.com
>
>
>

Information from ESET NOD32 Antivirus, version of virus signature database 4336 (20090814)

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com

The contract is that code running at raise IRQL not do anything which could cause a context switch, like call a blocking kernel-function. The caller is violating the contract, not the kernel.

That’s a bug in the caller, not in the kernel.

-p

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Friday, August 14, 2009 4:04 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] function IRQL dependency

The only problem with this approach is that it “breaks the contract” that a thread running at >DISPATCH_LEVEL cannot be preempted

Elevated IRQL is just a Windows notion of atomic context - by raising IRQL >=DPC level you tell the dispatcher “please don’t perform context switches on this CPU because doing so may have disastrous consequences, until I indicate that it can get safely done”. Consider what can happen if you hold a spinlock or run DPC routine and some other thread is schedules on CPU meanwhile. Dispatcher has no means of knowing that performing context switch at the moment is unsafe, does it. This is what the concept of elevated IRQL is all about - to let dispatcher know that it should not perform context switches at the moment. This is just a convention that system dispatcher is build around.

Although , as we can see, Windows does not seem to enforce this “contract” in some situations, it is
obviously just a bug that they will (hopefully) fix…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other 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

>condition every single time a call was made it would run much slower -

that is why we have the verifier.

Can Verifier catch such things?


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

James, did you try that on an x64 system? I expect Verifier to catch this kind of problem on x86, but not on x64.

Unfortunately, Verifier IRQL Checking is indeed less effective on x64, compared with x86, because for example KeRaiseIrql is inlined. Verifier doesn’t have (yet?) a way to hook these inline function calls, and therefore these calls don’t get verified. Here’s the entire implementation of KeRaiseIrql/KfRaiseIrql, from my copy of wdm.h:

KIRQL OldIrql;

OldIrql = KeGetCurrentIrql();

NT_ASSERT(OldIrql <= NewIrql);

WriteCR8(NewIrql);
return OldIrql;

So you would have to build a checked driver to catch this bug, using the assertion above.

BTW, another example of x64 Verifier being less useful than the x86 version is: until recently Verifier had no way to capture stack traces at DISPATCH_LEVEL or above. Therefore, the information displayed by some of the !verifier commands on x64 was not as useful as on x86. Capturing stack traces at DISPATCH_LEVEL on x64 works pretty well starting with Windows 7 though.

Thanks,
Dan

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of James Harper
Sent: Friday, August 14, 2009 4:25 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] function IRQL dependency

> The only problem with this approach is that it “breaks the
contract” that a
thread running at >DISPATCH_LEVEL cannot be preempted

Elevated IRQL is just a Windows notion of atomic context - by raising
IRQL
>=DPC level you tell the dispatcher “please don’t perform context
switches on
this CPU because doing so may have disastrous consequences, until I
indicate
that it can get safely done”. Consider what can happen if you hold a
spinlock
or run DPC routine and some other thread is schedules on CPU
meanwhile.
Dispatcher has no means of knowing that performing context switch at
the
moment is unsafe, does it. This is what the concept of elevated IRQL
is all
about - to let dispatcher know that it should not perform context
switches
at the moment. This is just a convention that system dispatcher is
build
around.

Although , as we can see, Windows does not seem to enforce this
“contract” in
some situations, it is obviously just a bug that they will (hopefully)
fix…

If the contract says you can’t do it, and you do it anyway, is the
resulting behaviour really a bug? This is kernel space not user space,
so it is up to the caller to check the inputs, not the callee.

That said, the docs for KeRaiseIrql say “If the new IRQL is less than
the current IRQL, a bug check occurs”, and it clearly doesn’t under 2K3,
even when the verifier is running (just tried it [1]). If the first line
in KeDelayExecutionThread was KeRaiseIrql(APC_LEVEL, &old_irql) and
KeDelayExecutionThread was called at HIGH_LEVEL, the the current IRQL
would be changed to APC_LEVEL and old_irql = HIGH_LEVEL without any fuss
at all (aside from the obvious :slight_smile:

[1] The code I tested this with, which starts at APC_LEVEL is:

KIRQL old_irql1, old_irql2;
KdPrint((" A Irql = %d\n", KeGetCurrentIrql()));
KeRaiseIrql(HIGH_LEVEL, &old_irql1);
KdPrint((" B Irql = %d\n", KeGetCurrentIrql()));
KeRaiseIrql(PASSIVE_LEVEL, &old_irql2);
KdPrint((" C Irql = %d\n", KeGetCurrentIrql()));
KeLowerIrql(old_irql2);
KdPrint((" D Irql = %d\n", KeGetCurrentIrql()));
KeLowerIrql(old_irql1);
KdPrint((" E Irql = %d\n", KeGetCurrentIrql()));

And the output was:

A Irql = 1
B Irql = 31
C Irql = 0
D Irql = 31
E Irql = 1

James


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other 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

> If the contract says you can’t do it, and you do it anyway, is the resulting behaviour really a bug?

I would say “yes, it is”…

Once the system has detected some “abnormality” in the KM it has to do something about it in order to ensure that damage does not get get spread further , because otherwise you may end up with long-term damage to user data (and, probably, even to the hardware). This is why normally Windows bugchecks whenever it encounters any “abnormality” in the KM - this is a standard Windows behavior in such situation.

Do you see anything special about the situation that we discuss??? As far as atomic context is concerned, what makes yielding with KeDelayExecutionThread() so terribly different from exactly the same operation performed by KeWaitXXX()??? Why does not the system bugcheck in the former scenario although it bugchecks in the latter one then???

Therefore, I don’t really think that it was done on purpose - I think they just overlooked something somehow, so that this is not an intentional behavior. This is why I say that it is apparently a bug …

Anton Bassov

wrote in message news:xxxxx@ntdev…
> Once the system has detected some “abnormality” in the KM it has to do
> something about it in order to ensure that damage does not get get spread
> further , because otherwise you may end up with long-term damage to user
> data (and, probably, even to the hardware). This is why normally Windows
> bugchecks whenever it encounters any “abnormality” in the KM - this is a
> standard Windows behavior in such situation.
>
> Do you see anything special about the situation that we discuss??? As far
> as atomic context is concerned, what makes yielding with
> KeDelayExecutionThread() so terribly different from exactly the same
> operation performed by KeWaitXXX()??? Why does not the system bugcheck in
> the former scenario although it bugchecks in the latter one then???
>
>

It doesn’t. This is what we have verifier and checked builds for. I am glad
Windows doesn’t check IRQL with every function call I make. Apart from IRQL
I can imagine a long list of sanity checks the OS could make to encounter
“abnormalities”. If it would not detect these on a free build or verifier
would you call all of these bugs too ?

//Daniel

> Apart from IRQL I can imagine a long list of sanity checks the OS could make

to encounter “abnormalities”.

In actuality, this list is much shorter than it seems to be at the first glance…

Please note that not every call that “violates the contract” results in “abnormalities”, from the kernel perspective (by the term "abnormality " I mean a situation that may potentially cause a long-term damage to the data and/or to the hardware).

One can think of validating calls that are made by KM code as of “last line of defence”, i.e. the last point when the OS can guarantee that a long-term damage to the system is not yet done. If this line gets broken through by a buggy caller long-term damage to the system may be done, so that the system has to react somehow straight away

For example, if you make ZwXXX call while holding a spinlock there is no immediate danger to the system in so far, so that there is no need for checking IRQL at the time a call is made. However, when (and if) the call results in blocking, a need for checking IRQL will arise. If it does not get done at this point
and you hold a spinlock, there is a potential for a deadlock which may leave the hardware in inconsistent state, and the OS cannot guarantee that it will be able to do something before damage gets done…

Anton Bassov

>

>condition every single time a call was made it would run much slower

>that is why we have the verifier.

Can Verifier catch such things?

As it turns out, not in this case, as per the explanation in Daniel’s
case. Despite what the docs say.

James