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);
Author: cgutman
Date: Thu Dec 1 23:04:22 2011
New Revision: 54558
URL: http://svn.reactos.org/svn/reactos?rev=54558&view=rev
Log:
[NDIS]
- Call FreeCommonBuffer() synchronously if we're running at PASSIVE_LEVEL to avoid cases where the miniport could be freed before the work item runs
Modified:
trunk/reactos/drivers/network/ndis/ndis/memory.c
Modified: trunk/reactos/drivers/network/ndis/ndis/memory.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/ndis/ndis/…
==============================================================================
--- trunk/reactos/drivers/network/ndis/ndis/memory.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/network/ndis/ndis/memory.c [iso-8859-1] Thu Dec 1 23:04:22 2011
@@ -239,10 +239,32 @@
{
PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
PMINIPORT_SHARED_MEMORY Memory;
+ PDMA_ADAPTER DmaAdapter = Adapter->NdisMiniportBlock.SystemAdapterObject;
NDIS_DbgPrint(MAX_TRACE,("Called.\n"));
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+
+ /* Call FreeCommonBuffer synchronously if we are at PASSIVE_LEVEL */
+ if (KeGetCurrentIrql() == PASSIVE_LEVEL)
+ {
+ /* We need this case because we free shared memory asynchronously
+ * and the miniport (and DMA adapter object) could be freed before
+ * our work item executes. Lucky for us, the scenarios where the
+ * freeing needs to be synchronous (failed init, MiniportHalt,
+ * and driver unload) are all at PASSIVE_LEVEL so we can just
+ * call FreeCommonBuffer synchronously and not have to worry
+ * about the miniport falling out from under us */
+
+ NDIS_DbgPrint(MID_TRACE,("Freeing shared memory synchronously\n"));
+
+ DmaAdapter->DmaOperations->FreeCommonBuffer(DmaAdapter,
+ Length,
+ PhysicalAddress,
+ VirtualAddress,
+ Cached);
+ return;
+ }
/* Must be NonpagedPool because by definition we're at DISPATCH_LEVEL */
Memory = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_SHARED_MEMORY));