From: Cameron Gutman Date: Sat, 3 Dec 2011 10:30:02 +0000 (+0000) Subject: [NTOSKRNL] X-Git-Tag: backups/usb-bringup@55523~3^2~236 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=b3c3a8b9ea3b1dd49a2a837997175f62d8c30ef8 [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). svn path=/trunk/; revision=54565 --- diff --git a/reactos/ntoskrnl/mm/anonmem.c b/reactos/ntoskrnl/mm/anonmem.c index 9aaa9a0ae57..26356048dc0 100644 --- a/reactos/ntoskrnl/mm/anonmem.c +++ b/reactos/ntoskrnl/mm/anonmem.c @@ -1090,8 +1090,6 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, } 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 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, 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) + /* 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) { - Status = STATUS_UNSUCCESSFUL; + 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 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle, 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);