You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Creating a buffer with WdfMemoryCreate of size 4092 (and probably any value between (PAGE_SIZE - 0x7f) and (PAGE_SIZE - 1)) will not create a buffer entirely resident in a single physical page, contradicting WdfMemoryCreate documentation.
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdfmemory/nf-wdfmemory-wdfmemorycreate
The documentation states the following:
If BufferSize is less than PAGE_SIZE, the operating system gives the caller exactly the number of requested bytes of memory. The buffer is not necessarily page-aligned, but it is aligned by the number of bytes that the MEMORY_ALLOCATION_ALIGNMENT constant specifies in Ntdef.h. Buffers of PAGE_SIZE or less do not cross page boundaries.
If BufferSize is PAGE_SIZE or greater, the system allocates a page-aligned buffer. If the PoolType parameter is NonPagedPool, the system allocates the number of pages that are necessary to hold all of the bytes. Any unused bytes on the last-allocated page are essentially wasted.
The sentence issue in question is "Buffers of PAGE_SIZE or less do not cross page boundaries." When allocating a WDFMEMORY of size 4092, I found the buffer begins at offset 0x80 in one page, ending at 0x7c in the next page, and therefore crossing page boundaries. The first 0x80 bytes of the page seem to contain the WDFMEMORY object (type FxMemoryObject). This is important to us as the physical addresses may not necessarily be contiguous if the buffer crosses page boundaries.
Code which encounters this issue looks like so (variable names changed and other code omitted):
#define NUM_ITEMS ((UINT32)(PAGE_SIZE / sizeof(ITEM))) // As many full items as fit in a single page. Change to another, smaller value if desired.
STATIC_ASSERT(NUM_ITEMS * sizeof(ITEM) <= PAGE_SIZE); // Make sure NUM_ITEMS above is sane. Later code relies on items not spanning pages.
// Note: (NUM_ITEMS * sizeof(ITEM)) == 4092. sizeof(ITEM) == 44 and NUM_ITEMS == 93.
status = WdfMemoryCreate(&attributes,
NonPagedPoolNx,
MY_MEM_TAG,
NUM_ITEMS * sizeof(ITEM),
&Ctx->MemObj,
&Ctx->Buffer);
// Omitted: Error handling
physBaseAddr = MmGetPhysicalAddress(Ctx->Buffer);
// An individual item should not span pages. We'll double-check the whole buffer lies in a single
// physical page here.
NT_ASSERT(((physBaseAddr.QuadPart & (PAGE_SIZE-1)) + (NUM_ITEMS * sizeof(ITEM))) <= PAGE_SIZE);
Note, ObjectSize is 0x80 instead of 0x1080 and Buffer ends in 0x000 rather than 0x80.
In the source for FxMemoryObject, I see memory is created from pool (and is therefore page-aligned) rather than along with the Object in the following case:
I believe that 78 will need to be changed to something like:
78 if (BufferSize >= (PAGE_SIZE – sizeof(FxMemoryBuffer))
I would submit a patch myself, but I am not familiar with the process for building and testing the WDF framework, so I would rather leave that up to the maintainers.
The text was updated successfully, but these errors were encountered:
Creating a buffer with WdfMemoryCreate of size 4092 (and probably any value between (PAGE_SIZE - 0x7f) and (PAGE_SIZE - 1)) will not create a buffer entirely resident in a single physical page, contradicting WdfMemoryCreate documentation.
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdfmemory/nf-wdfmemory-wdfmemorycreate
The documentation states the following:
If BufferSize is less than PAGE_SIZE, the operating system gives the caller exactly the number of requested bytes of memory. The buffer is not necessarily page-aligned, but it is aligned by the number of bytes that the MEMORY_ALLOCATION_ALIGNMENT constant specifies in Ntdef.h. Buffers of PAGE_SIZE or less do not cross page boundaries.
If BufferSize is PAGE_SIZE or greater, the system allocates a page-aligned buffer. If the PoolType parameter is NonPagedPool, the system allocates the number of pages that are necessary to hold all of the bytes. Any unused bytes on the last-allocated page are essentially wasted.
The sentence issue in question is "Buffers of PAGE_SIZE or less do not cross page boundaries." When allocating a WDFMEMORY of size 4092, I found the buffer begins at offset 0x80 in one page, ending at 0x7c in the next page, and therefore crossing page boundaries. The first 0x80 bytes of the page seem to contain the WDFMEMORY object (type FxMemoryObject). This is important to us as the physical addresses may not necessarily be contiguous if the buffer crosses page boundaries.
Code which encounters this issue looks like so (variable names changed and other code omitted):
typedef struct ITEM {
char[44] data; // actual fields omitted.
} ITEM, *P_ITEM;
#define NUM_ITEMS ((UINT32)(PAGE_SIZE / sizeof(ITEM))) // As many full items as fit in a single page. Change to another, smaller value if desired.
STATIC_ASSERT(NUM_ITEMS * sizeof(ITEM) <= PAGE_SIZE); // Make sure NUM_ITEMS above is sane. Later code relies on items not spanning pages.
Windbg output (shortened):
kd> dx -r1 ((driver!MY_CONTEXT *)0xffffcd0bd5202750)
...
[+0x0d0] MemObj : 0x32f429df7ff8 [Type: WDFMEMORY__ *]
[+0x0d8] Buffer : 0xffffcd0bd6208080 [Type: void *]
Note, the Buffer is offset from the page boundary by 0x80. Adding 4092 to that address will cross into the next page.
kd> !wdfkd.wdfhandle 0x32f429df7ff8
...
!wdfobject 0xffffcd0bd6208000
Note, the wdfobject address is Ctx->Buffer - 0x80.
kd> dt Wdf01000!FxMemoryObject 0xffffcd0bd6208000
...
+0x00a m_ObjectSize : 0x1080
...
+0x070 m_BufferSize : 0xffc
Creating a buffer of BufferSize == PAGE_SIZE does not result in the same issue:
kd> dx -r1 (*driver!MY_CONTEXT *)0xffffcd0bd484bae0))
...
[+0x0d0] MemObj : 0x32f42bd355a8 [Type: WDFMEMORY__ *]
[+0x0d8] Buffer : 0xffffcd0bd3823000 [Type: void *]
kd> dt Wdf01000!FxMemoryObject 0xffffcd0bd42caa50
...
+0x00a m_ObjectSize : 0x80
...
+0x070 m_BufferSize : 0x1000
Note, ObjectSize is 0x80 instead of 0x1080 and Buffer ends in 0x000 rather than 0x80.
In the source for FxMemoryObject, I see memory is created from pool (and is therefore page-aligned) rather than along with the Object in the following case:
78 if (BufferSize >= PAGE_SIZE ||
79 (FxDriverGlobals->FxVerifierOn && FxDriverGlobals->FxPoolTrackingOn) ||
80 FxIsPagedPoolType(PoolType)) {
I believe that 78 will need to be changed to something like:
78 if (BufferSize >= (PAGE_SIZE – sizeof(FxMemoryBuffer))
I would submit a patch myself, but I am not familiar with the process for building and testing the WDF framework, so I would rather leave that up to the maintainers.
The text was updated successfully, but these errors were encountered: