Author: cgutman
Date: Sat Dec 3 10:30:02 2011
New Revision: 54565
URL:
http://svn.reactos.org/svn/reactos?rev=54565&view=rev
Log:
[NTOSKRNL]
NtFreeVirtualMemory:
- Handle the case where a region size of 0 is passed in
- Return the correct error status for failure
- Copy back the rounded values
- Add checks and prints to catch callers doing nasty things (one is commented out because
csrsrv triggers it trying to release the first 1 MB of RAM during video init, not sure
what to do there)
- There is a heap bug where calling RtlReAllocateHeap on a large block allocation
(HEAP_ENTRY_VIRTUAL_ALLOC is set) will cause a call to NtFreeVirtualMemory with an offset
base (illegal) and a length smaller than the total pages reserved in the VM region (also
illegal). This bug is exposed by setupapi when it parses large INF files (like the
PRO/1000 driver INF).
Modified:
trunk/reactos/ntoskrnl/mm/anonmem.c
Modified: trunk/reactos/ntoskrnl/mm/anonmem.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/anonmem.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/anonmem.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/anonmem.c [iso-8859-1] Sat Dec 3 10:30:02 2011
@@ -1090,8 +1090,6 @@
}
BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
- RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
- PAGE_ROUND_DOWN((PBaseAddress));
AddressSpace = &Process->Vm;
@@ -1099,26 +1097,69 @@
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
if (MemoryArea == NULL)
{
- Status = STATUS_UNSUCCESSFUL;
+ DPRINT1("Unable to find memory area from address 0x%p\n",
BaseAddress);
+ Status = STATUS_UNABLE_TO_FREE_VM;
goto unlock_deref_and_return;
}
+ if (PRegionSize != 0)
+ {
+ /* Use the region the caller wanted, rounded to whole pages */
+ RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
+ PAGE_ROUND_DOWN((PBaseAddress));
+ }
+ else
+ {
+ /* The caller wanted the whole memory area */
+ RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+ (ULONG_PTR)MemoryArea->StartingAddress;
+ }
+
switch (FreeType)
{
case MEM_RELEASE:
- /* We can only free a memory area in one step. */
- if (MemoryArea->StartingAddress != BaseAddress ||
- MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
- {
- Status = STATUS_UNSUCCESSFUL;
+ /* MEM_RELEASE must be used with the exact base and length
+ * that was returned by NtAllocateVirtualMemory */
+
+ /* Verify the base address is correct */
+ if (MemoryArea->StartingAddress != BaseAddress)
+ {
+ DPRINT1("Base address is illegal for MEM_RELEASE (0x%p !=
0x%p)\n",
+ MemoryArea->StartingAddress,
+ BaseAddress);
+ Status = STATUS_UNABLE_TO_FREE_VM;
+ goto unlock_deref_and_return;
+ }
+
+ /* Verify the region size is correct */
+ if ((ULONG_PTR)MemoryArea->StartingAddress + RegionSize !=
+ (ULONG_PTR)MemoryArea->EndingAddress)
+ {
+ DPRINT1("Region size is illegal for MEM_RELEASE (0x%x)\n",
RegionSize);
+ Status = STATUS_UNABLE_TO_FREE_VM;
+ //goto unlock_deref_and_return;
+ }
+
+ if (MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
+ {
+ DPRINT1("Memory area is not VM\n");
+ Status = STATUS_UNABLE_TO_FREE_VM;
goto unlock_deref_and_return;
}
MmFreeVirtualMemory(Process, MemoryArea);
Status = STATUS_SUCCESS;
- goto unlock_deref_and_return;
+ break;
case MEM_DECOMMIT:
+ if ((ULONG_PTR)BaseAddress + RegionSize >
+ (ULONG_PTR)MemoryArea->EndingAddress)
+ {
+ DPRINT1("Invald base address (0x%p) and region size (0x%x) for
MEM_DECOMMIT\n",
+ BaseAddress, RegionSize);
+ Status = STATUS_UNABLE_TO_FREE_VM;
+ goto unlock_deref_and_return;
+ }
Status = MmAlterRegion(AddressSpace,
MemoryArea->StartingAddress,
(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) ?
@@ -1129,13 +1170,24 @@
MEM_RESERVE,
PAGE_NOACCESS,
MmModifyAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MmAlterRegion failed with status 0x%x\n", Status);
+ Status = STATUS_UNABLE_TO_FREE_VM;
+ goto unlock_deref_and_return;
+ }
+ break;
+
+ default:
+ Status = STATUS_NOT_IMPLEMENTED;
goto unlock_deref_and_return;
}
- Status = STATUS_NOT_IMPLEMENTED;
-
- unlock_deref_and_return:
-
+ /* Copy rounded values back in success case */
+ *UBaseAddress = BaseAddress;
+ *URegionSize = RegionSize;
+
+unlock_deref_and_return:
MmUnlockAddressSpace(AddressSpace);
if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);