OldProtect != NewProtect)
{
ULONG i;
+ PMM_PAGEOP PageOp;
+ PMEMORY_AREA MArea;
+ char* addr = (char*)BaseAddress;
for (i=0; i < PAGE_ROUND_UP(RegionSize)/PAGE_SIZE; i++)
{
- if (MmIsPagePresent(Process,
- (char*)BaseAddress + (i*PAGE_SIZE)))
+ MArea = MmLocateMemoryAreaByAddress(AddressSpace, addr);
+ do
{
- MmSetPageProtect(Process,
- (char*)BaseAddress + (i*PAGE_SIZE),
- NewProtect);
+ PageOp = MmGetPageOp(MArea, Process->UniqueProcessId, addr,
+ NULL, 0, MM_PAGEOP_CHANGEPROTECT, TRUE);
+ } while(PageOp == NULL);
+
+ /* Should we enable/disable virtual mapping? */
+ if((NewProtect & PAGE_NOACCESS) &&
+ !(OldProtect & PAGE_NOACCESS) &&
+ (MmIsPagePresent(Process, addr)))
+ {
+ /* Set other flags if any */
+ if(NewProtect != PAGE_NOACCESS)
+ MmSetPageProtect(Process, addr, NewProtect & ~PAGE_NOACCESS);
+ MmDisableVirtualMapping(Process, addr, NULL, NULL);
+ }
+ else if((OldProtect & PAGE_NOACCESS) && !(NewProtect & PAGE_NOACCESS))
+ {
+ MmEnableVirtualMapping(Process, addr);
}
+
+ /* Set new protection flags */
+ if(MmIsPagePresent(Process, addr))
+ {
+ MmSetPageProtect(Process, addr, NewProtect);
+ }
+ KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ MmReleasePageOp(PageOp);
+ addr += PAGE_SIZE;
}
}
}
{
/* Fail without it */
DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
+ if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return STATUS_PRIVILEGE_NOT_HELD;
}
(Protect & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY)))
{
DPRINT1("Copy on write is not supported by VirtualAlloc\n");
+ if (Attached) KeUnstackDetachProcess(&ApcState);
+ if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return STATUS_INVALID_PAGE_PROTECTION;
}
/* Check for user-mode parameters */
if (PreviousMode != KernelMode)
{
- /* Make sure they are writable */
+ /* Make sure they are writeable */
ProbeForWritePointer(UBaseAddress);
ProbeForWriteUlong(URegionSize);
}
-
+
/* Capture their values */
PBaseAddress = *UBaseAddress;
PRegionSize = *URegionSize;
}
BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
- RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
- PAGE_ROUND_DOWN((PBaseAddress));
AddressSpace = &Process->Vm;
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)
+ {
+ 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)
{
- Status = STATUS_UNSUCCESSFUL;
+ 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) ?
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:
+ /* Enter SEH */
+ _SEH2_TRY
+ {
+ /* Copy rounded values back in success case */
+ *UBaseAddress = BaseAddress;
+ *URegionSize = RegionSize;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ DPRINT1("Failed to copy values back! (Status: 0x%x)\n", Status);
+ }
+ _SEH2_END;
+unlock_deref_and_return:
MmUnlockAddressSpace(AddressSpace);
if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);