Non-alertable wait on PsSetLoadImageNotifyRoutine callback

Greetings,

I’m registering a callback for a module loading notification via PsSetLoadImageNotifyRoutine(). As the documentation states, the callback is called in PASSIVE_LEVEL, sometimes with special kernel APCs disabled. I need to calculate the MD5 of backing file of the module that is loaded, and this operation must be synchronous. I cannot post it to a user-space agent to do it for me(i.e. asynchronous). My question is,
I’m checking whether APCs are disabled in my callback using:

KeAreAllApcsDisabled().

If they are indeed disable, I’m issuing a work item to a queue using:

IoQueueWorkItem()

The callback itself is now waiting for the system worker to run my work-item routine,
with:
KeWaitForSingleObject(…, Executive, KernelMode, FALSE, NULL);

The routine that is called on this work item shall trigger an event, that will notify the callback that the MD5 is calculated by the worker routine.

My question is, is it Ok to wait with a non-alertable state in this callback? I think this callback is called in the context of process that the image is being loaded to, so i’m actually deferring user APCs… but i think it’s fine since waiting is not forever. Eventually the worker routine will signal the event regardless of a successful MD5 computing or not. Also, i’m not checking the return value for KeWaitForSingleObject(), since i provide no timeout, i wait on a non-alertable state in KernelMode so no user-APC can preempt the waiting, and also no alerts can be sent.

Thank you.

I have more of a meta-question:

If APCs are disabled, what are you attempting to accomplish/avoid by doing the checksum in a work-item?

Peter
OSR
@OSRDrivers

Use ZwXXX APIs. In this case, ZwCreateFile() to open the image’s file and compute MD5. As i said, this must be done synchronously. I can’t use a userspace “agent” to do it for me asynchronously.

Why open the file? You get image base and size in the ImageInfo parameter.

– pa

The PE file on the disk looks different in memory as far as i know. Not every section of the PE is loaded into memory… atleast thats how ELF files produced by gcc work.

Well, MY question was related to the fact that you get the HANDLE to the file that’s being loaded – or at least I *think* you do. In any case, ignoring ZwCreateFile you get the same APC issue for reads and writes.

In any case:

is it Ok to wait with a non-alertable state in this callback

I don’t see any reason why this wouldn’t be fine.

i’m not checking the return value for KeWaitForSingleObject()

So, you *expect* the status to be something, but you don’t bother to check it? That’s usually a recipe for a nasty bug in the future. At least get the status and ASSERT that it’s what you expect.

I need to
calculate the MD5 of backing file of the module that is loaded, and this
operation must be synchronous

As a more of a meta-issue, you DO realize that somebody could suspend the process and then change all of its memory, right? So, validating what’s on disk is “nice” but if you’re looking at it as a security measure, it’s not really that secure.

Peter
OSR
@OSRDrivers

> As the documentation states, the callback is called in PASSIVE_LEVEL, sometimes

with special kernel APCs disabled.

I just wonder how something like that may be even possible…

Although you can disable both user and “normal” kernel APC delivery to a thread at PASSIVE_LEVEL by entering a critical region, you cannot do the same with special kernel APCs - they run at APC_LEVEL, and, hence, the only way to disable them is to raise IRQL above PASSIVE_LEVEL .

Therefore, as long as your thread is at PASSIVE_LEVEL special kernel APCs may be delivered to it

Anton Bassov

Server 2003 introduced Guarded Regions to disable SKAPCs at PASSIVE_LEVEL:

https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/critical-regions-and-guarded-regions

This is why it’s important to use KeAreAllApcsDisabled to check if SKAPCs
are disabled instead of just checking the IRQL:

https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-keareallapcsdisabled

-scott
OSR
@OSRDrivers