Problem with mapping more than one page using ZwMapViewOfSection under Vista

Hello,
I have a problem with sharing memory, which is bigger than one page (4 kBytes), between driver and user space application.

In a driver I have allocated static global variable

char myTable[sizeof(__int64)*2044]; //size of it is 16352 bytes

and initialized it with simple loop:

__int64* initPtr = (__int64*)myTable;

for (__int64 i=0; i intPtr[i]=i;

Next I’ve tried to share this table with user mode application. I’ve achieved this by execution of the following code:

void getSharedMemory(void* pVA)
{
HANDLE physicalMemorySectionHandle;
UNICODE_STRING physicalMemorySectionUnicodeString;
OBJECT_ATTRIBUTES physicalMemoryObjectAttributes;
PVOID physicalMemorySection = NULL;
PHYSICAL_ADDRESS physicalAddressBase;
PHYSICAL_ADDRESS viewBase;
NTSTATUS status;
PVOID mappedVirtualAddress;
HANDLE processHandle = ZwCurrentProcess();

if (NULL == pVA)
return;

/* Mapping memmory to user space /
RtlInitUnicodeString (&physicalMemorySectionUnicodeString, L"\Device\PhysicalMemory");

InitializeObjectAttributes (&physicalMemoryObjectAttributes,
&physicalMemorySectionUnicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);

status = ZwOpenSection (&physicalMemorySectionHandle, SECTION_ALL_ACCESS, &physicalMemoryObjectAttributes);
if (!NT_SUCCESS(status))
{
((PVOID)pVA) = NULL;
return;
}

status = ObReferenceObjectByHandle (physicalMemorySectionHandle,
SECTION_MAP_READ,
(POBJECT_TYPE) NULL,
KernelMode,
&physicalMemorySection,
(POBJECT_HANDLE_INFORMATION) NULL);
if (!NT_SUCCESS(status))
{
((PVOID)pVA) = NULL;
ZwClose(physicalMemorySectionHandle);
return;
}

/
convert kernel va to real phisical address /
physicalAddressBase = MmGetPhysicalAddress(myTable);
viewBase = physicalAddressBase;

mappedVirtualAddress = NULL;

ULONG size = sizeof(__int64)2044; //size of global static table

status = ZwMapViewOfSection (physicalMemorySectionHandle,
processHandle,
&mappedVirtualAddress,
0L,
size,
&viewBase,
&size,
ViewShare,
0,
PAGE_READWRITE | PAGE_NOCACHE);

if (!NT_SUCCESS(status))
{
status = ZwMapViewOfSection (physicalMemorySectionHandle,
processHandle,
&mappedVirtualAddress,
0L,
size,
&viewBase,
&size,
ViewShare,
0,
PAGE_READWRITE |PAGE_WRITECOMBINE);
}

if (!NT_SUCCESS(status))
{
status = ZwMapViewOfSection (physicalMemorySectionHandle,
processHandle,
&mappedVirtualAddress,
0L,
size,
&viewBase,
&size,
ViewShare,
0,
PAGE_READWRITE);
}

if (!NT_SUCCESS(status))
{
((PVOID)pVA) = NULL;
ZwClose(physicalMemorySectionHandle);
return;
}

//now size is 20480 – rounded up to 4kB boundary
mappedVirtualAddress = (PVOID)((ULONG)mappedVirtualAddress + (ULONG)physicalAddressBase.LowPart - (ULONG)viewBase.LowPart);

((PVOID
)pVA) = mappedVirtualAddress;
ZwClose(physicalMemorySectionHandle);
return;
};

It looks everything works OK, but when I’m trying to read whole the table from user space application the result is as follow:

[Value] [Mapped Virtual Address (hex)]
0 348b58
1 348b60
2 348b68
3 348b70
4 348b78
5 348b80
6 348b88
7 348b90
8 348b98
9 348ba0
10 348ba8
11 348bb0
……….
652 349fb8
653 349fc0
654 349fc8
655 349fd0
656 349fd8
657 349fe0
658 349fe8
659 349ff0
660 349ff8
14757395258967641088 34a000 <- here is next page and problems begins
14757395258967641292 34a008
1507725027235463051 34a010
5028082440786512726 34a018
17889923897613475068 34a020
23678979336568832 34a028
3640333463937649408 34a030
277895171801089 34a038
……

The problem appears not always but very often. It always lies on the boundary of two pages. Usually first or first two pages are visible properly but third, fourth and next pages are totally wrong. The table is static and allocated in driver so it is for sure NONPAGED memory.
Is it a problem with Virtual Translation Table at user space side?
Why, in spite of usage ZwMapViewOfSection which maps 20480, third, fourth and following pages are not visible form user application?

There is no guarantee that two pages of allocated memory (e.g. your
“myTable” table) are physically contiguous. They are contiguous in the
system VA space, but they are not contiguous in physical memory.

Why are you trying to share a static table between kernel mode and user
mode? Sharing memory between kernel and user (which is by itself VERY
dangerous) should not involve physical addresses. Have you looked at this
article on OSR online about sharing memory between kernel and user mode?

http://www.osronline.com/article.cfm?article=39

Hope it helps
GV


Gianluca Varenni, Windows DDK MVP

CACE Technologies
http://www.cacetech.com

----- Original Message -----
From:
To: “Windows System Software Devs Interest List”
Sent: Monday, April 28, 2008 1:57 PM
Subject: [ntdev] Problem with mapping more than one page using
ZwMapViewOfSection under Vista

Hello,
I have a problem with sharing memory, which is bigger than one page (4
kBytes), between driver and user space application.

In a driver I have allocated static global variable

char myTable[sizeof(__int64)2044]; //size of it is 16352 bytes

and initialized it with simple loop:

__int64
initPtr = (__int64*)myTable;

for (__int64 i=0; i intPtr[i]=i;

Next I’ve tried to share this table with user mode application. I’ve
achieved this by execution of the following code:

void getSharedMemory(void* pVA)
{
HANDLE physicalMemorySectionHandle;
UNICODE_STRING physicalMemorySectionUnicodeString;
OBJECT_ATTRIBUTES physicalMemoryObjectAttributes;
PVOID physicalMemorySection = NULL;
PHYSICAL_ADDRESS physicalAddressBase;
PHYSICAL_ADDRESS viewBase;
NTSTATUS status;
PVOID mappedVirtualAddress;
HANDLE processHandle = ZwCurrentProcess();

if (NULL == pVA)
return;

/* Mapping memmory to user space /
RtlInitUnicodeString (&physicalMemorySectionUnicodeString,
L"\Device\PhysicalMemory");

InitializeObjectAttributes (&physicalMemoryObjectAttributes,
&physicalMemorySectionUnicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);

status = ZwOpenSection (&physicalMemorySectionHandle,
SECTION_ALL_ACCESS, &physicalMemoryObjectAttributes);
if (!NT_SUCCESS(status))
{
((PVOID)pVA) = NULL;
return;
}

status = ObReferenceObjectByHandle (physicalMemorySectionHandle,
SECTION_MAP_READ,
(POBJECT_TYPE) NULL,
KernelMode,
&physicalMemorySection,
(POBJECT_HANDLE_INFORMATION)
NULL);
if (!NT_SUCCESS(status))
{
((PVOID)pVA) = NULL;
ZwClose(physicalMemorySectionHandle);
return;
}

/
convert kernel va to real phisical address /
physicalAddressBase = MmGetPhysicalAddress(myTable);
viewBase = physicalAddressBase;

mappedVirtualAddress = NULL;

ULONG size = sizeof(__int64)2044; //size of global static table

status = ZwMapViewOfSection (physicalMemorySectionHandle,
processHandle,
&mappedVirtualAddress,
0L,
size,
&viewBase,
&size,
ViewShare,
0,
PAGE_READWRITE | PAGE_NOCACHE);

if (!NT_SUCCESS(status))
{
status = ZwMapViewOfSection (physicalMemorySectionHandle,
processHandle,
&mappedVirtualAddress,
0L,
size,
&viewBase,
&size,
ViewShare,
0,
PAGE_READWRITE |PAGE_WRITECOMBINE);
}

if (!NT_SUCCESS(status))
{
status = ZwMapViewOfSection (physicalMemorySectionHandle,
processHandle,
&mappedVirtualAddress,
0L,
size,
&viewBase,
&size,
ViewShare,
0,
PAGE_READWRITE);
}

if (!NT_SUCCESS(status))
{
((PVOID)pVA) = NULL;
ZwClose(physicalMemorySectionHandle);
return;
}

//now size is 20480 – rounded up to 4kB boundary
mappedVirtualAddress = (PVOID)((ULONG)mappedVirtualAddress +
(ULONG)physicalAddressBase.LowPart - (ULONG)viewBase.LowPart);

((PVOID
)pVA) = mappedVirtualAddress;
ZwClose(physicalMemorySectionHandle);
return;
};

It looks everything works OK, but when I’m trying to read whole the table
from user space application the result is as follow:

[Value] [Mapped Virtual Address (hex)]
0 348b58
1 348b60
2 348b68
3 348b70
4 348b78
5 348b80
6 348b88
7 348b90
8 348b98
9 348ba0
10 348ba8
11 348bb0
……….
652 349fb8
653 349fc0
654 349fc8
655 349fd0
656 349fd8
657 349fe0
658 349fe8
659 349ff0
660 349ff8
14757395258967641088 34a000 <- here is next page and
problems begins
14757395258967641292 34a008
1507725027235463051 34a010
5028082440786512726 34a018
17889923897613475068 34a020
23678979336568832 34a028
3640333463937649408 34a030
277895171801089 34a038
……

The problem appears not always but very often. It always lies on the
boundary of two pages. Usually first or first two pages are visible properly
but third, fourth and next pages are totally wrong. The table is static and
allocated in driver so it is for sure NONPAGED memory.
Is it a problem with Virtual Translation Table at user space side?
Why, in spite of usage ZwMapViewOfSection which maps 20480, third, fourth
and following pages are not visible form user application?


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

xxxxx@gmail.com wrote:

I have a problem with sharing memory, which is bigger than one page (4 kBytes), between driver and user space application.

In a driver I have allocated static global variable

char myTable[sizeof(__int64)*2044]; //size of it is 16352 bytes

and initialized it with simple loop:

__int64* initPtr = (__int64*)myTable;

for (__int64 i=0; i> intPtr[i]=i;
>
>
> Next I’ve tried to share this table with user mode application. I’ve achieved this by execution of the following code:
> …
> It looks everything works OK, but when I’m trying to read whole the table from user space application the result is as follow:
> …
>
> The problem appears not always but very often. It always lies on the boundary of two pages. Usually first or first two pages are visible properly but third, fourth and next pages are totally wrong. The table is static and allocated in driver so it is for sure NONPAGED memory.
> Is it a problem with Virtual Translation Table at user space side?
> Why, in spite of usage ZwMapViewOfSection which maps 20480, third, fourth and following pages are not visible form user application?
>

It is because you are assuming that your table lives in contiguous pages
in physical memory. You get the physical address of the start of the
table, then map multiple pages starting at that physical address. Once
the system has been running for a relatively short period, physical
memory gets wildly scrambled, so that you get assigned multiple pages
from all over the physical address space.

What you are handing to the user are random pages belonging to someone else.

Try creating an MDL for your structure, then use
MmMapLockedPagesSpecifyCache to map it to user mode


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

> I have a problem with sharing memory, which is bigger than one page (4 kBytes),

between driver and user space application. In a driver I have allocated static
global variable char myTable[sizeof(__int64)*2044]; //size of it is 16352 bytes

Are you trying to win “the most unreasonable design in history” prize???

Concerning your actual problem, it lies with the fact that memory your array describes is not guaranteed to be (in fact, almost guaranteed not to be) physically contigious. When you map the address returned by MmGetPhysicalAddress(), you map the *physical* range with the first page corresponding to the beginning of your array and the remaining ones totally unrelated to it…

Anton Bassov

Thanks for your responses. Now it is obvious for me why I see totally wrong values. I know that it is very dangerous, but I am going to use shared memory only for diagnostic purposes (internal usage) and I need for it more than 4kB of memory.

xxxxx@gmail.com wrote:

Thanks for your responses. Now it is obvious for me why I see totally wrong values. I know that it is very dangerous, but I am going to use shared memory only for diagnostic purposes (internal usage) and I need for it more than 4kB of memory.

That’s fine, as long as you know the dangers. The only issue is that
you need to use the proper tools for the job!


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