Why cann't use MmMapLockedPagesSpecifyCache in CREATE_PROCESS_NOTIFY_ROUTINE?

When I use MmMapLockedPagesSpecifyCache to map a piece of kernel memory into user space in a LOAD_IMAGE_NOTIFY_ROUTINE, it seems the call hangs forever.

Let’s look at documentation first:

[begin quote]

The driver’s process-creation notify routine runs at IRQL PASSIVE_LEVEL, either in the context of the initial thread within a newly created process or in the context of a system thread.

[end quote]

Now consider what happens when callback is invoked in context of a system thread (which does not have its UM representation) and you specify UserMode in a call to MmMapLockedPagesSpecifyCache(), which does not allow you to map MDL into the address space of your interest- instead, it maps it into the address space of a caller process. What would you expect to happen here???

In other words, your design is faulty in itself - you’ve got to change it…

Anton Bassov

Thank you Anton.

Is there the same reason that this call hangs in LOAD_IMAGE_NOTIFY_ROUTINE? I mean LOAD_IMAGE_NOTIFY_ROUTINE as well as CREATE_PROCESS_NOTIFY_ROUTINE are both under an improper IRQL to call MmMapLockedPagesSpecifyCache.

> LOAD_IMAGE_NOTIFY_ROUTINE as well as CREATE_PROCESS_NOTIFY_ROUTINE

are both under an improper IRQL to call MmMapLockedPagesSpecifyCache.

This is simply wrong - MmMapLockedPagesSpecifyCache() may be called at any IRQL that is <= DPC level, so that, once your callback gets invoked at PASSIVE_LEVEL, there is no IRQL-related problem here whatsoever…

Anton Bassov

> When I use MmMapLockedPagesSpecifyCache to map a piece

of kernel memory into user space in a LOAD_IMAGE_NOTIFY_ROUTINE,
it seems the call hangs forever.

I think this is because the image load callback is invoked with the
process address space lock held, and mapping memory into user
space also requires this lock. A callstack from debugger (with good
symbols) should confirm this.


This posting is provided “AS IS” with no warranties, and confers no
rights.

> A callstack from debugger (with good symbols) should confirm this.

Well, I would say it just does not really matter why he deadlocks - his design is just faulty in itself, so that he just has to change it. As simple as that…

Anton Bassov

Anton, do you mean it is impossible to map system memory into user mode space in a system thread?

Now consider what happens when callback is invoked in context of a system thread
(which does not have its UM representation) and you specify UserMode in a call
to MmMapLockedPagesSpecifyCache()

I am confused with “system thread context”. When it is OK to call MmMapLockedPagesSpecifyCache?

> Let’s look at documentation first:

[begin quote]

The driver’s process-creation notify routine runs at IRQL
PASSIVE_LEVEL, either in the context of the initial thread
within a newly created process or in the context of a system thread.

[end quote]

This is from an older version of the docs, and it’s incorrect. The latest
online docs correctly state that the create callback runs in the context
of the parent (creator) process.

Now consider what happens when callback is invoked in context of
a system thread (which does not have its UM representation) and
you specify UserMode in a call to MmMapLockedPagesSpecifyCache(),
which does not allow you to map MDL into the address space
of your interest- instead, it maps it into the address space of a
caller process. What would you expect to happen here???

As I said, this situation should not happen for process creation callbacks.
(The original message actually mentioned image load callbacks,
despite the subject being about process creation. However, image load
callbacks for user images are also never delivered on a system thread).

Regarding the question of what would happen if MmMapLockedPages
(UserMode) was called from a system thread, I would expect it to
succeed. Just like ZwAllocateVirtualMemory in the system context,
this should create a VAD in the user mode part of the system process.
Whether or not this is a good (or even supported) thing to do is a
separate question.


This posting is provided “AS IS” with no warranties, and confers no
rights.

I am sorry I have made a mistake with the title of the first post .

My problem is when MmMapLockedPagesSpecifyCache was called in a LoadImageNotifyRoutine(Set by PsSetLoadImageNotifyRoutine), the call never return.

VOID LoadImageNotifyRoutine(
IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo)
{
PVOID Buffer = NULL;
PMDL Mdl;
PVOID UserBufferAddress;

Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ‘0XYZ’);

Mdl = IoAllocateMdl(Buffer PAGE_SIZE, FALSE, FALSE, NULL);

MmBuildMdlForNonPagedPool(Mdl);

UserAddress = MmMapLockedPagesSpecifyCache(Mdl,
UserMode,
MmCached,
NULL,
FALSE,
NormalPagePriority);


}

Mapping non-paged system memory into user space succeed in CreateProcessNotifyRoutine, but MmMapLockedPagesSpecifyCache blocks when called in a LoadImageNotifyRoutine.

I think Anton is telling me that CreateProcessNotifyRoutine running in the context of the parent process rather than the new created process.

(Set by PsSetLoadImageNotifyRoutine)

Don’t trust a damn thing the documentation says about that function. Be very
weary of it.

The callback can and will come in an arbitrary context.

Regarding MmMapLockedPagesSpecifyCache, MmProbeAndLockPages should be
called after your call
to MmBuildMdlForNonPagedPool if my understanding is correct.

Non paged memory is always in physical memory, why need probe and lock it?

Hell if I know…

MmMapLockedPagesSpecifyCache
The MmMapLockedPagesSpecifyCache routine maps the physical pages that are
described by an MDL and enables the caller to specify the cache attribute
that is used to create the mapping.

NTKERNELAPI PVOID
MmMapLockedPagesSpecifyCache(
IN PMDL MemoryDescriptorList,
IN KPROCESSOR_MODE AccessMode,
IN MEMORY_CACHING_TYPE CacheType,
IN PVOID BaseAddress,
IN ULONG BugCheckOnFailure,
IN MM_PAGE_PRIORITY Priority
);

Parameters:

MemoryDescriptorList

Specifies the MDL to be mapped. The caller must already have probed and
locked the MDL by using the MmProbeAndLockPages routine.

I am assuming that this is being done when the executable is loaded, if so
you have an incomplete PROCESS_OBJECT and using it in the call will cause
various problems, hangs being one of them.

The more important question is why you think you need to map kernel memory
to a user process, most of the reasons presented on the various forums over
the years are incorrect with better approaches to do it. So why do you
think you need this?


Don Burn (MVP, Windows DDK)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

wrote in message news:xxxxx@ntdev…
> When I use MmMapLockedPagesSpecifyCache to map a piece of kernel memory
> into user space in a LOAD_IMAGE_NOTIFY_ROUTINE, it seems the call hangs
> forever.
>

> My problem is when MmMapLockedPagesSpecifyCache was called in a LoadImageNotifyRoutine

(Set by PsSetLoadImageNotifyRoutine), the call never return.

And what is the stack?


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

> Non paged memory is always in physical memory, why need probe and lock it?

No need whatsoever- this is why normally you would use MmBuildMdlForNonpagedPool(), rather than MmProbaAndLockPages(). The only situation why you may want to use it on non-paged address is when you want to map it to a different address, effectively making two virtual addresses describe the same physical memory (whether it is good or bad thing to do is another question). Please check the archives for our discussion with Scott on the topic - he explained to me sufficiently enough why it is better to use MmBuildMdlForNonpagedPool() on memory that you pass to MmMapLockedPagesSpecifyCache() even if memory that MDL describes it is not pageable…

Anton Bassov

> why it is better to use MmBuildMdlForNonpagedPool() on memory that you pass to >MmMapLockedPagesSpecifyCache() even if memory that MDL describes it is not pageable

A small correction - I meant MmProbaAndLockPages(), rather than MmBuildMdlForNonpagedPool() in the above quoted paragraph in my previous post…

Anton Bassov

Pavel,

Regarding the question of what would happen if MmMapLockedPages (UserMode) was
called from a system thread, I would expect it to succeed. Just like ZwAllocateVirtualMemory
in the system context, this should create a VAD in the user mode part of the system process.

In order to do something like that, a system process must have its own page directory. Does it have any??? It does not really seem to need the one, does it - in fact, giving it its own page directory and updating CR3 on every switch to a system thread in quite a few cases may result in absolutely unnecessary TLB invalidations…

For example, consider the scenario when “regular” thread gets preempted by a system thread that falls into RT priority range before its quantum expires. IIRC, in such case the preempted thread does not get removed from the run list, so that it will immediately resume execution when RT-priority thread yields the CPU. If you update CR3 under these circumstances, you will invalidate TLB entries for all non-global (i.e. UM) addresses for no reason whatsoever - after all, once kernel address space is the same for all processes, the system thread will be able to run without updating CR3…

Anton Bassov

>> called from a system thread, I would expect it to succeed. Just like ZwAllocateVirtualMemory

> in the system context, this should create a VAD in the user mode part of the system process.

In order to do something like that, a system process must have its own page directory. Does it have
any???

Yes, it has. The thing really works, at least worked on NT4 and w2k. ZwMapViewOfFile to system process also works.


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