howto generate 32bit user mode pointers in 64bit drivers

Hello,
I want to pass a pointer from a 64bit driver to a 32bit user mode app.
In the original 32bit driver version it was implemented like that:

Ptr = (ULONG)MmMapLockedPages(Mdl, UserMode);

How can assure that my pointer is below 2GB?
Thanks,
Uwe

uwe kirst wrote:

I want to pass a pointer from a 64bit driver to a 32bit user mode app.
In the original 32bit driver version it was implemented like that:

Ptr = (ULONG)MmMapLockedPages(Mdl, UserMode);

How can assure that my pointer is below 2GB?

You don’t need to do anything more than you’ve already done.

You are mapping the region described by the MDL into the user’s address
space. If the user’s address space is 32-bit, then this will be a
32-bit mapping. If the user’s address space is 64-bit, then this will
be a 64-bit mapping.

In either case, the system handles it for you, given the user address
space setup.

Peter
OSR

Peter Viscarola (OSR) wrote:

uwe kirst wrote:

> I want to pass a pointer from a 64bit driver to a 32bit user mode app.
> In the original 32bit driver version it was implemented like that:
>
> Ptr = (ULONG)MmMapLockedPages(Mdl, UserMode);
>
> How can assure that my pointer is below 2GB?
>

You don’t need to do anything more than you’ve already done.

I think it’s a little bit more complicated. Maybee I have to explain. I
want to share memory between driver and application.
The memory should be allocated in the kernel.
The memory in the original 32bit driver version is allocated during
driver loading in the AddDevice-function.
I’m assuming my user mode app is 32bit right now. But how do I assure
that the Virtual address is below 2GB?
The driver does not know so far that I’m planning to use a 32bit apps.
That’s how the memory is allocated (maybee I have to change this part of
the code?):

deviceExtension->VirtualAddress = ExAllocatePool(PagedPool, NumberOfBytes);
if (deviceExtension->VirtualAddress) {
deviceExtension->Mdl =
IoAllocateMdl(deviceExtension->VirtualAddress, NumberOfBytes, FALSE,
FALSE, NULL);
MmProbeAndLockPages(deviceExtension->Mdl, KernelMode,
IoModifyAccess);

None of the code you show below matters because it’s all about
allocating the memory, not mapping it into the application’s address
space. It doesn’t matter where the memory is allocated.

When you call MmMapLockedPages you must be doing it within the context
of the process you’re sharing the memory with. The memory manager knows
that it’s a 32-bit process, and that user-mode addresses must be below
2GB (actually below 4GB on a 64-bit system I believe) and will map it in
the right spot.

-p

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of uwe kirst
Sent: Thursday, January 06, 2005 7:02 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] howto generate 32bit user mode pointers
in 64bit drivers

Peter Viscarola (OSR) wrote:

> uwe kirst wrote:
>
>> I want to pass a pointer from a 64bit driver to a 32bit
user mode app.
>> In the original 32bit driver version it was implemented like that:
>>
>> Ptr = (ULONG)MmMapLockedPages(Mdl, UserMode);
>>
>> How can assure that my pointer is below 2GB?
>>
>
> You don’t need to do anything more than you’ve already done.
>
I think it’s a little bit more complicated. Maybee I have to
explain. I want to share memory between driver and application.
The memory should be allocated in the kernel.
The memory in the original 32bit driver version is allocated
during driver loading in the AddDevice-function.
I’m assuming my user mode app is 32bit right now. But how do
I assure that the Virtual address is below 2GB?
The driver does not know so far that I’m planning to use a 32bit apps.
That’s how the memory is allocated (maybee I have to change
this part of the code?):

deviceExtension->VirtualAddress = ExAllocatePool(PagedPool,
deviceExtension->NumberOfBytes);
if (deviceExtension->VirtualAddress) {
deviceExtension->Mdl =
IoAllocateMdl(deviceExtension->VirtualAddress, NumberOfBytes,
FALSE, FALSE, NULL);
MmProbeAndLockPages(deviceExtension->Mdl, KernelMode,
IoModifyAccess); …


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as:
xxxxx@windows.microsoft.com To unsubscribe send a blank
email to xxxxx@lists.osr.com

uwe kirst wrote:

>

I think it’s a little bit more complicated.

No, it’s not! Really!

I’m assuming my user mode app is 32bit right now. But how do I assure
that the Virtual address is below 2GB?

Well, let’s back up a couple of steps. You’re dealing with three
addresses for this block of memory:

a) A physical address – This physical address can be anywhere in the
system’s memory space, regardless of address size. So, for the purposes
of our discussion, we don’t care about the physical address, right?

b) A kernel virtual address – This is the address your driver will use
to access the block of (physical) memory, with a mapping set up through
the kernel mode memory management hardware (PDEs and PTEs). This
address will be 32-bits on Windows 32 and 64-bits on Windows 64, because
drivers on Windows 64 systems must be 64-bit capable. This address is
nothing more than the pointer returned form ExAllocatePool(…).

c) A USER virtual address – This is the address into which you’re going
to map the block of (physical) memory that you allocate from pool,
that’s within the user application’s address space. You create this
address when running in the context of the requesting processing, by calling

ULONG_PTR ptr;

ptr = MmMapLockedPages(mdl, UserMode);

As described in your original posting (well, I added the ULONG_PTR data
type, which will be 32-bits on x86 and 64-bits on x64).

Your driver may not know if the caller is 32-bit or 64-bit (it could
find out, if it wanted to, by calling IoIs32BitProcess)… But the
MEMORY MANAGER certainly knows! So, when you call the function
MmMapLockedPages, and tell the Memory Manager to map the buffer
described by the MDL into the user mode address space of the current
process, the Memory Manager knows if the current process is 32-bit or
64-bit and maps the buffer into its address space, automatically
observing all the appropriate restrictions.

It really IS that simple.

deviceExtension->VirtualAddress = ExAllocatePool(PagedPool, NumberOfBytes);
if (deviceExtension->VirtualAddress) {
deviceExtension->Mdl = IoAllocateMdl(deviceExtension->VirtualAddress,
NumberOfBytes, FALSE, FALSE, NULL);
MmProbeAndLockPages(deviceExtension->Mdl, KernelMode,
IoModifyAccess); …

Given your code above, I have a few notes for you:

a) You really might want to re-think the whole idea of mapping POOL into
an application’s address space. This approach can open a complex
security loophole that can endager the system. I’d recommend allocating
memory in a section, and using that. This isn’t entirely free of
potential problems, but it’s better.

b) I personally dislike the idea of allocating paged pool and then
pinning it. Unless the pages are locked into memory for a short period
of time, why not allocate the pages from NON-paged pool in the first
place? In that case you’d call MmBuildMdlForNonPagedPool.

c) You should ALWAYS use ExAllocatePoolWithTag, instead of ExAllocatePool.

d) MmMapLockedPages is an obsolete function – You should certainly be
calling MmMapLockedPagesSpecifyCache.

e) Just to re-emphasize (even if just for the archive): Your approach
working, at least from the code segments you’ve provided thus far, is
entirely dependent on your driver running in the context of the process
into which you wish to map the memory segment, right?? And, for a
random driver in a random stack in the system (such as the storage
stack, just to choose an example) there’s no reason to believe that your
driver will be running in any specific thread/process context. Now, in
your specific driver, it is entirely possible that you KNOW for sure
that your driver runs in a specific thread/process context, and if so,
this is OK. I just wanted to be sure we had this point covered.

HTH,

Peter
OSR

That means it will work right now, because I’m calling MmMapLockedPages
during an IOCTL operation that was caused by my user mode app?
Uwe

Peter Wieland wrote:

None of the code you show below matters because it’s all about
allocating the memory, not mapping it into the application’s address
space. It doesn’t matter where the memory is allocated.

When you call MmMapLockedPages you must be doing it within the context
of the process you’re sharing the memory with. The memory manager knows
that it’s a 32-bit process, and that user-mode addresses must be below
2GB (actually below 4GB on a 64-bit system I believe) and will map it in
the right spot.

-p

>-----Original Message-----
>From: xxxxx@lists.osr.com
>[mailto:xxxxx@lists.osr.com] On Behalf Of uwe kirst
>Sent: Thursday, January 06, 2005 7:02 AM
>To: Windows System Software Devs Interest List
>Subject: Re: [ntdev] howto generate 32bit user mode pointers
>in 64bit drivers
>
>Peter Viscarola (OSR) wrote:
>
>
>
>>uwe kirst wrote:
>>
>>
>>
>>>I want to pass a pointer from a 64bit driver to a 32bit
>>>
>>>
>user mode app.
>
>
>>>In the original 32bit driver version it was implemented like that:
>>>
>>>Ptr = (ULONG)MmMapLockedPages(Mdl, UserMode);
>>>
>>>How can assure that my pointer is below 2GB?
>>>
>>>
>>>
>>You don’t need to do anything more than you’ve already done.
>>
>>
>>
>I think it’s a little bit more complicated. Maybee I have to
>explain. I want to share memory between driver and application.
>The memory should be allocated in the kernel.
>The memory in the original 32bit driver version is allocated
>during driver loading in the AddDevice-function.
>I’m assuming my user mode app is 32bit right now. But how do
>I assure that the Virtual address is below 2GB?
>The driver does not know so far that I’m planning to use a 32bit apps.
>That’s how the memory is allocated (maybee I have to change
>this part of the code?):
>
>deviceExtension->VirtualAddress = ExAllocatePool(PagedPool,
>deviceExtension->NumberOfBytes);
>if (deviceExtension->VirtualAddress) {
> deviceExtension->Mdl =
>IoAllocateMdl(deviceExtension->VirtualAddress, NumberOfBytes,
>FALSE, FALSE, NULL);
> MmProbeAndLockPages(deviceExtension->Mdl, KernelMode,
>IoModifyAccess); …
>
>—
>Questions? First check the Kernel Driver FAQ at
>http://www.osronline.com/article.cfm?id=256
>
>You are currently subscribed to ntdev as:
>xxxxx@windows.microsoft.com To unsubscribe send a blank
>email to xxxxx@lists.osr.com
>
>
>


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

uwe kirst wrote:

That means it will work right now, because I’m calling MmMapLockedPages
during an IOCTL operation that was caused by my user mode app?

Well, dude… Only you would know if it’s already working or not, right?

And, AGAIN… This is all ASSUMING that you KNOW (not guess) that you’re
driver will always be called in the context of the requesting process.

Peter
OSR

> Given your code above, I have a few notes for you:

a) You really might want to re-think the whole idea of
mapping POOL into
an application’s address space. This approach can open a complex
security loophole that can endager the system.

Peter,

what is this security loophole? Do you mean that mapping is done
on page granularity, so the application could get access to the rest of the
page
(pool memory allocated for somebody else)? Will allocating whole page(s) and
checking the page alignment of the allocated address solve this security
problem?
Or one page mapping granularity is not guaranteed?

Dmitriy Budko, VMware

Dmitriy Budko wrote:

what is this security loophole?
>

It is possible for a malicious application to clone your address space,
thus getting a pointer into pool. That’s all well and good… until
the orignal app exits, and your driver returns the block of pool. At
which time the malicious app would have access to pool that’s being used
for … anything … perhaps for system purposes.

Peter
OSR

> > what is this security loophole?

>

It is possible for a malicious application to clone your
address space, thus getting a pointer into pool.

How quaint, fork() on Windows!
Yes, it is a nice subtle security hole.

That’s all well and good… until
the orignal app exits, and your driver returns the block of pool. At
which time the malicious app would have access to pool that’s
being used for … anything … perhaps for system purposes.

On app’s exit the driver should unmap the pool block by calling
MmUnmapLockedPages() and only after that return the block to
the free pool. Would it fix this security problem?

Is there any description what is done to page tables/prototype PTEs
by Windows fork()/NtCreateProcess()? It is not obvious to me that
addresses returned by MmMapLockedPagesSpecifyCache() for a nonpaged pool
would be cloned at all – they are not related to any section.

Dmitriy Budko, VMware

Peter Viscarola (OSR) wrote:

uwe kirst wrote:

> That means it will work right now, because I’m calling
> MmMapLockedPages during an IOCTL operation that was caused by my user
> mode app?

Well, dude… Only you would know if it’s already working or not, right?

I just want to understand why and make sure that it will work in any case.
Thanks for your fast reply
Uwe

As far as I understand it, and I would appreciate if Peter (or someone else
that knows) could confirm/correct this:

When using MmMapLockedPagesSpecifyCache to map into user space, it
MUST BE in the context of that user process, and this would have absolutely
nothing to do with 64-bit OS’s, but just simply that the user-mode mapping
is per process, so if a set of pages are mapped to one process particular,
and if a different user process is running when the MmMapLockedPages is
called, the pages will simply be mapped to this user process, and of course
the intended user process will not be able to access that part of memory.

So if it works in 32-bit, it should work in 64-bit…


Mats

-------- Notice --------
The information in this message is confidential and may be legally
privileged. It is intended solely for the addressee. Access to this
message by anyone else is unauthorized. If you are not the intended
recipient, any disclosure, copying or distribution of the message, or any
action taken by you in reliance on it, is prohibited and may be unlawful.
If you have received this message in error, please delete it and contact
the sender immediately. Thank you.

xxxxx@lists.osr.com wrote on 01/07/2005 08:37:00 AM:

Peter Viscarola (OSR) wrote:

> uwe kirst wrote:
>
>> That means it will work right now, because I’m calling
>> MmMapLockedPages during an IOCTL operation that was caused by my user
>> mode app?
>
>
> Well, dude… Only you would know if it’s already working or not,
right?
>
I just want to understand why and make sure that it will work in any
case.
Thanks for your fast reply
Uwe


Questions? First check the Kernel Driver FAQ at http://www.
osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@3dlabs.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

ForwardSourceID:NT0000A786

>

As far as I understand it, and I would appreciate if Peter (or someone else
that knows) could confirm/correct this:

When using MmMapLockedPagesSpecifyCache to map into user space, it
MUST BE in the context of that user process, and this would have absolutely
nothing to do with 64-bit OS’s, but just simply that the user-mode mapping
is per process, so if a set of pages are mapped to one process particular,
and if a different user process is running when the MmMapLockedPages is
called, the pages will simply be mapped to this user process, and of course
the intended user process will not be able to access that part of memory.

So if it works in 32-bit, it should work in 64-bit…

Exactly correct.

Peter
OSR

Dmitriy Budko wrote:

On app’s exit the driver should unmap the pool block by calling
MmUnmapLockedPages() and only after that return the block to
the free pool. Would it fix this security problem?

Well, sorry, but no. We have two apps: The “good” app and the
“malicious” app. Because the “good” app (presumably) has a handle open
to the driver, the driver will do the unmap during cleanup processing,
and then return the block to pool.

But the malicious app? His mapping remains…

Is there any description what is done to page tables/prototype PTEs
by Windows fork()/NtCreateProcess()?

Not that I am aware of.

Peter
OSR

>How quaint, fork() on Windows!

Interix is now free, and it employes the native fork() of the Windows kernel
which was there for years (NtCreateProcess with SectionHandle == NULL).

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com