-/* $Id: virtual.c,v 1.57 2002/05/13 18:10:41 chorns Exp $
+/* $Id$
*
- * COPYRIGHT: See COPYING in the top directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/mm/virtual.c
- * PURPOSE: implementing the Virtualxxx section of the win32 api
- * PROGRAMMER: David Welch
- * UPDATE HISTORY:
- * 09/4/98: Created
- * 10/6/98: Corrections from Iwan Fatahi (i_fatahi@hotmail.com)
- * 30/9/98: Implemented ZwxxxVirtualMemory functions
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/virtual.c
+ * PURPOSE: Implementing operations on virtual memory.
+ *
+ * PROGRAMMERS: David Welch
*/
-
+
/* INCLUDE *****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/mm.h>
-#include <internal/ob.h>
-#include <internal/io.h>
-#include <internal/ps.h>
-#include <internal/pool.h>
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
-/* TYPES *********************************************************************/
-
-typedef struct _MM_SEGMENT
-{
- ULONG Type;
- ULONG Protect;
- ULONG Length;
- LIST_ENTRY SegmentListEntry;
-} MM_SEGMENT, *PMM_SEGMENT;
-
-/* GLOBALS *******************************************************************/
-
-#define TAG_MM_SEGMENT TAG('M', 'S', 'E', 'G')
-
/* FUNCTIONS *****************************************************************/
-PMM_SEGMENT
-MmGetSegmentForAddress(PMEMORY_AREA MArea,
- PVOID Address,
- PVOID* PCurrentAddress)
+NTSTATUS STDCALL
+NtFlushVirtualMemory(IN HANDLE ProcessHandle,
+ IN PVOID BaseAddress,
+ IN ULONG NumberOfBytesToFlush,
+ OUT PULONG NumberOfBytesFlushed OPTIONAL)
/*
- * FUNCTION: Get the segment corresponding to a particular memory area and
- * address.
+ * FUNCTION: Flushes virtual memory to file
* ARGUMENTS:
- * MArea (IN) = The memory area
- * Address (IN) = The address to get the segment for
- * PCurrentAddress (OUT) = The start of the segment
- * RETURNS:
- * The corresponding segment or NULL if an error occurred
+ * ProcessHandle = Points to the process that allocated the virtual
+ * memory
+ * BaseAddress = Points to the memory address
+ * NumberOfBytesToFlush = Limits the range to flush,
+ * NumberOfBytesFlushed = Actual number of bytes flushed
+ * RETURNS: Status
*/
{
- PVOID CurrentAddress;
- PMM_SEGMENT CurrentSegment;
- PLIST_ENTRY Current;
-
- if (Address < MArea->BaseAddress ||
- Address >= (MArea->BaseAddress + MArea->Length))
- {
- KeBugCheck(0);
- *PCurrentAddress = NULL;
- return(NULL);
- }
-
- Current = MArea->Data.VirtualMemoryData.SegmentListHead.Flink;
- CurrentAddress = MArea->BaseAddress;
- while (Current != &MArea->Data.VirtualMemoryData.SegmentListHead)
- {
- CurrentSegment = CONTAINING_RECORD(Current,
- MM_SEGMENT,
- SegmentListEntry);
- if (Address >= CurrentAddress &&
- Address < (CurrentAddress + CurrentSegment->Length))
- {
- *PCurrentAddress = CurrentAddress;
- return(CurrentSegment);
- }
- CurrentAddress = CurrentAddress + CurrentSegment->Length;
- Current = Current->Flink;
- }
- KeBugCheck(0);
- return(NULL);
+ /* This should be implemented once we support network filesystems */
+ DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n");
+ return(STATUS_SUCCESS);
}
-NTSTATUS
-MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
- PMEMORY_AREA MArea,
- PVOID Address)
+
+NTSTATUS STDCALL
+MiLockVirtualMemory(HANDLE ProcessHandle,
+ PVOID BaseAddress,
+ ULONG NumberOfBytesToLock,
+ PULONG NumberOfBytesLocked,
+ PObReferenceObjectByHandle pObReferenceObjectByHandle,
+ PMmCreateMdl pMmCreateMdl,
+ PObDereferenceObject pObDereferenceObject,
+ PMmProbeAndLockPages pMmProbeAndLockPages,
+ PExFreePool pExFreePool)
{
- return(STATUS_UNSUCCESSFUL);
+ PEPROCESS Process;
+ NTSTATUS Status;
+ PMDL Mdl;
+
+ Status = pObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_VM_WRITE,
+ NULL,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return(Status);
+
+ Mdl = pMmCreateMdl(NULL,
+ BaseAddress,
+ NumberOfBytesToLock);
+ if (Mdl == NULL)
+ {
+ pObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
+
+ pMmProbeAndLockPages(Mdl,
+ UserMode,
+ IoWriteAccess);
+
+ pExFreePool(Mdl);
+
+ pObDereferenceObject(Process);
+
+ *NumberOfBytesLocked = NumberOfBytesToLock;
+ return(STATUS_SUCCESS);
}
-NTSTATUS
-MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
- PMEMORY_AREA MemoryArea,
- PVOID Address,
- PMM_PAGEOP PageOp)
+NTSTATUS STDCALL
+NtLockVirtualMemory(HANDLE ProcessHandle,
+ PVOID BaseAddress,
+ ULONG NumberOfBytesToLock,
+ PULONG NumberOfBytesLocked)
{
- ULONG_PTR PhysicalAddress;
- BOOLEAN WasDirty;
- SWAPENTRY SwapEntry;
- NTSTATUS Status;
- PMDL Mdl;
+ DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+ "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
+ ProcessHandle,
+ BaseAddress,
+ NumberOfBytesToLock,
+ NumberOfBytesLocked);
+
+ return MiLockVirtualMemory(ProcessHandle,
+ BaseAddress,
+ NumberOfBytesToLock,
+ NumberOfBytesLocked,
+ ObReferenceObjectByHandle,
+ MmCreateMdl,
+ ObfDereferenceObject,
+ MmProbeAndLockPages,
+ ExFreePool);
+}
- DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
- Address, MemoryArea->Process->UniqueProcessId);
- /*
- * Paging out code or readonly data is easy.
- */
- if ((MemoryArea->Attributes & PAGE_READONLY) ||
- (MemoryArea->Attributes & PAGE_EXECUTE_READ))
- {
- MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE,
- NULL, (PULONG)&PhysicalAddress);
- MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
- if (MmGetSavedSwapEntryPage(PhysicalAddress) != 0)
- {
- DPRINT1("Read-only page was swapped out.\n");
- KeBugCheck(0);
- }
- MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
-
- PageOp->Status = STATUS_SUCCESS;
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
- return(STATUS_SUCCESS);
- }
+NTSTATUS FASTCALL
+MiQueryVirtualMemory (IN HANDLE ProcessHandle,
+ IN PVOID Address,
+ IN CINT VirtualMemoryInformationClass,
+ OUT PVOID VirtualMemoryInformation,
+ IN ULONG Length,
+ OUT PULONG ResultLength)
+{
+ NTSTATUS Status;
+ PEPROCESS Process;
+ MEMORY_AREA* MemoryArea;
+ PMADDRESS_SPACE AddressSpace;
- /*
- * Otherwise this is read-write data
- */
- MmDisableVirtualMapping(MemoryArea->Process, Address,
- &WasDirty, (PULONG_PTR)&PhysicalAddress);
- if (PhysicalAddress == 0)
- {
- KeBugCheck(0);
- }
- if (!WasDirty)
- {
- MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
- MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
- if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0)
- {
- MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
- MmSetSavedSwapEntryPage(PhysicalAddress, 0);
- }
- MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
- PageOp->Status = STATUS_SUCCESS;
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
- return(STATUS_SUCCESS);
- }
+ if (Address < MmSystemRangeStart)
+ {
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ NULL,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("NtQueryVirtualMemory() = %x\n",Status);
+ return(Status);
+ }
+ AddressSpace = &Process->AddressSpace;
+ }
+ else
+ {
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+ switch(VirtualMemoryInformationClass)
+ {
+ case MemoryBasicInformation:
+ {
+ PMEMORY_BASIC_INFORMATION Info =
+ (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
+ if (Length != sizeof(MEMORY_BASIC_INFORMATION))
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ ObDereferenceObject(Process);
+ return(STATUS_INFO_LENGTH_MISMATCH);
+ }
+
+ if (MemoryArea == NULL)
+ {
+ Info->Type = 0;
+ Info->State = MEM_FREE;
+ Info->Protect = PAGE_NOACCESS;
+ Info->AllocationProtect = 0;
+ Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
+ Info->AllocationBase = NULL;
+ Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ }
+ else
+ {
+ switch(MemoryArea->Type)
+ {
+ case MEMORY_AREA_VIRTUAL_MEMORY:
+ case MEMORY_AREA_PEB_OR_TEB:
+ Status = MmQueryAnonMem(MemoryArea, Address, Info,
+ ResultLength);
+ break;
+ case MEMORY_AREA_SECTION_VIEW:
+ Status = MmQuerySectionView(MemoryArea, Address, Info,
+ ResultLength);
+ break;
+ case MEMORY_AREA_NO_ACCESS:
+ Info->Type = MEM_PRIVATE;
+ Info->State = MEM_RESERVE;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->StartingAddress;
+ Info->AllocationBase = MemoryArea->StartingAddress;
+ Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+ (ULONG_PTR)MemoryArea->StartingAddress;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_SHARED_DATA:
+ Info->Type = MEM_PRIVATE;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->StartingAddress;
+ Info->AllocationBase = MemoryArea->StartingAddress;
+ Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+ (ULONG_PTR)MemoryArea->StartingAddress;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_SYSTEM:
+ Info->Type = 0;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->StartingAddress;
+ Info->AllocationBase = MemoryArea->StartingAddress;
+ Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+ (ULONG_PTR)MemoryArea->StartingAddress;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_KERNEL_STACK:
+ Info->Type = 0;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->StartingAddress;
+ Info->AllocationBase = MemoryArea->StartingAddress;
+ Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+ (ULONG_PTR)MemoryArea->StartingAddress;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ case MEMORY_AREA_PAGED_POOL:
+ Info->Type = 0;
+ Info->State = MEM_COMMIT;
+ Info->Protect = MemoryArea->Attributes;
+ Info->AllocationProtect = MemoryArea->Attributes;
+ Info->BaseAddress = MemoryArea->StartingAddress;
+ Info->AllocationBase = MemoryArea->StartingAddress;
+ Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+ (ULONG_PTR)MemoryArea->StartingAddress;
+ Status = STATUS_SUCCESS;
+ *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
+ break;
+ default:
+ DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
+ Status = STATUS_UNSUCCESSFUL;
+ *ResultLength = 0;
+ }
+ }
+ break;
+ }
- /*
- * If necessary, allocate an entry in the paging file for this page
- */
- SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
- if (SwapEntry == 0)
- {
- SwapEntry = MmAllocSwapPage();
- if (SwapEntry == 0)
- {
- MmEnableVirtualMapping(MemoryArea->Process, Address);
- PageOp->Status = STATUS_UNSUCCESSFUL;
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
- return(STATUS_UNSUCCESSFUL);
- }
- }
+ default:
+ {
+ Status = STATUS_INVALID_INFO_CLASS;
+ *ResultLength = 0;
+ break;
+ }
+ }
- /*
- * Write the page to the pagefile
- */
- Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
- MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
- Status = MmWriteToSwapPage(SwapEntry, Mdl);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
- Status);
- MmEnableVirtualMapping(MemoryArea->Process, Address);
- PageOp->Status = STATUS_UNSUCCESSFUL;
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
- return(STATUS_UNSUCCESSFUL);
- }
+ MmUnlockAddressSpace(AddressSpace);
+ if (Address < MmSystemRangeStart)
+ {
+ ObDereferenceObject(Process);
+ }
- /*
- * Otherwise we have succeeded, free the page
- */
- DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress);
- MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
- MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
- MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
- MmSetSavedSwapEntryPage(PhysicalAddress, 0);
- MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
- PageOp->Status = STATUS_SUCCESS;
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
- return(STATUS_SUCCESS);
+ return Status;
}
-NTSTATUS
-MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
- MEMORY_AREA* MemoryArea,
- PVOID Address,
- BOOLEAN Locked)
-/*
- * FUNCTION: Move data into memory to satisfy a page not present fault
- * ARGUMENTS:
- * AddressSpace = Address space within which the fault occurred
- * MemoryArea = The memory area within which the fault occurred
- * Address = The absolute address of fault
- * RETURNS: Status
- * NOTES: This function is called with the address space lock held.
+/* (tMk 2004.II.4)
+ * FUNCTION:
+ * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
+ *
*/
+NTSTATUS STDCALL
+NtQueryVirtualMemory (IN HANDLE ProcessHandle,
+ IN PVOID Address,
+ IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
+ OUT PVOID VirtualMemoryInformation,
+ IN ULONG Length,
+ OUT PULONG UnsafeResultLength)
{
- ULONG_PTR Page;
- NTSTATUS Status;
- PMM_SEGMENT Segment;
- PVOID CurrentAddress;
- PMM_PAGEOP PageOp;
-
- /*
- * There is a window between taking the page fault and locking the
- * address space when another thread could load the page so we check
- * that.
- */
- if (MmIsPagePresent(NULL, Address))
- {
- if (Locked)
- {
- MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
- }
- return(STATUS_SUCCESS);
- }
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG ResultLength = 0;
+ KPROCESSOR_MODE PreviousMode;
+ union
+ {
+ MEMORY_BASIC_INFORMATION BasicInfo;
+ }
+ VirtualMemoryInfo;
- /*
- * Get the segment corresponding to the virtual address
- */
- Segment = MmGetSegmentForAddress(MemoryArea, Address, &CurrentAddress);
- if (Segment == NULL)
- {
- return(STATUS_UNSUCCESSFUL);
- }
- if (Segment->Type == MEM_RESERVE)
- {
- return(STATUS_UNSUCCESSFUL);
- }
-
- /*
- * Get or create a page operation
- */
- PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(),
- (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
- MM_PAGEOP_PAGEIN);
- if (PageOp == NULL)
- {
- DPRINT1("MmGetPageOp failed");
- KeBugCheck(0);
- }
+ DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
+ "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
+ "Length %lu ResultLength %x)\n",ProcessHandle,Address,
+ VirtualMemoryInformationClass,VirtualMemoryInformation,
+ Length,ResultLength);
- /*
- * Check if someone else is already handling this fault, if so wait
- * for them
- */
- if (PageOp->Thread != PsGetCurrentThread())
- {
- MmUnlockAddressSpace(AddressSpace);
- Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
- 0,
- KernelMode,
- FALSE,
- NULL);
- /*
- * Check for various strange conditions
- */
- if (Status != STATUS_SUCCESS)
- {
- DPRINT1("Failed to wait for page op\n");
- KeBugCheck(0);
- }
- if (PageOp->Status == STATUS_PENDING)
- {
- DPRINT1("Woke for page op before completion\n");
- KeBugCheck(0);
- }
- /*
- * If this wasn't a pagein then we need to restart the handling
- */
- if (PageOp->OpType != MM_PAGEOP_PAGEIN)
- {
- MmLockAddressSpace(AddressSpace);
- MmReleasePageOp(PageOp);
- return(STATUS_MM_RESTART_OPERATION);
- }
- /*
- * If the thread handling this fault has failed then we don't retry
- */
- if (!NT_SUCCESS(PageOp->Status))
- {
- MmLockAddressSpace(AddressSpace);
- MmReleasePageOp(PageOp);
- return(Status);
- }
- MmLockAddressSpace(AddressSpace);
- if (Locked)
- {
- MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
- }
- MmReleasePageOp(PageOp);
- return(STATUS_SUCCESS);
- }
+ PreviousMode = ExGetPreviousMode();
- /*
- * Try to allocate a page
- */
- Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
- if (Status == STATUS_NO_MEMORY)
+ if (PreviousMode != KernelMode && UnsafeResultLength != NULL)
{
- MmUnlockAddressSpace(AddressSpace);
- Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
- MmLockAddressSpace(AddressSpace);
+ _SEH_TRY
+ {
+ ProbeForWriteUlong(UnsafeResultLength);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
}
- /*
- * Handle swapped out pages.
- */
- if (MmIsPageSwapEntry(NULL, Address))
- {
- SWAPENTRY SwapEntry;
- PMDL Mdl;
+ if (Address >= MmSystemRangeStart)
+ {
+ DPRINT1("Invalid parameter\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Status = MiQueryVirtualMemory ( ProcessHandle,
+ Address,
+ VirtualMemoryInformationClass,
+ &VirtualMemoryInfo,
+ Length,
+ &ResultLength );
+
+ if (NT_SUCCESS(Status))
+ {
+ if (PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ if (ResultLength > 0)
+ {
+ ProbeForWrite(VirtualMemoryInformation,
+ ResultLength,
+ 1);
+ RtlCopyMemory(VirtualMemoryInformation,
+ &VirtualMemoryInfo,
+ ResultLength);
+ }
+ if (UnsafeResultLength != NULL)
+ {
+ *UnsafeResultLength = ResultLength;
+ }
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ else
+ {
+ if (ResultLength > 0)
+ {
+ RtlCopyMemory(VirtualMemoryInformation,
+ &VirtualMemoryInfo,
+ ResultLength);
+ }
+
+ if (UnsafeResultLength != NULL)
+ {
+ *UnsafeResultLength = ResultLength;
+ }
+ }
+ }
+
+ return(Status);
+}
- MmDeletePageFileMapping(NULL, Address, &SwapEntry);
- Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
- MmBuildMdlFromPages(Mdl, (PULONG)&Page);
- Status = MmReadFromSwapPage(SwapEntry, Mdl);
- if (!NT_SUCCESS(Status))
- {
- KeBugCheck(0);
- }
- MmSetSavedSwapEntryPage(Page, SwapEntry);
- }
-
- /*
- * Set the page. If we fail because we are out of memory then
- * try again
- */
- Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
- Address,
- MemoryArea->Attributes,
- (ULONG)Page,
- FALSE);
- while (Status == STATUS_NO_MEMORY)
- {
- MmUnlockAddressSpace(AddressSpace);
- Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
- Address,
- MemoryArea->Attributes,
- (ULONG)Page,
- TRUE);
- MmLockAddressSpace(AddressSpace);
- }
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
- KeBugCheck(0);
- return(Status);
- }
- /*
- * Add the page to the process's working set
- */
- MmInsertRmap(Page, PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address));
+NTSTATUS STDCALL
+MiProtectVirtualMemory(IN PEPROCESS Process,
+ IN OUT PVOID *BaseAddress,
+ IN OUT PULONG NumberOfBytesToProtect,
+ IN ULONG NewAccessProtection,
+ OUT PULONG OldAccessProtection OPTIONAL)
+{
+ PMEMORY_AREA MemoryArea;
+ PMADDRESS_SPACE AddressSpace;
+ ULONG OldAccessProtection_;
+ NTSTATUS Status;
- /*
- * Finish the operation
- */
- if (Locked)
- {
- MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
- }
- PageOp->Status = STATUS_SUCCESS;
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
- return(STATUS_SUCCESS);
-}
+ *NumberOfBytesToProtect =
+ PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
+ PAGE_ROUND_DOWN(*BaseAddress);
+ *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
-VOID STATIC
-MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
- PVOID BaseAddress,
- ULONG RegionSize,
- ULONG OldType,
- ULONG OldProtect,
- ULONG NewType,
- ULONG NewProtect)
-/*
- * FUNCTION: Modify the attributes of a memory region
- */
-{
- /*
- * If we are switching a previously committed region to reserved then
- * free any allocated pages within the region
- */
- if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
- {
- ULONG i;
-
- for (i=0; i <= (RegionSize/PAGESIZE); i++)
- {
- LARGE_INTEGER PhysicalAddr;
-
- if (MmIsPageSwapEntry(AddressSpace->Process,
- BaseAddress + (i * PAGESIZE)))
- {
- SWAPENTRY SwapEntry;
+ AddressSpace = &Process->AddressSpace;
- MmDeletePageFileMapping(AddressSpace->Process,
- BaseAddress + (i * PAGESIZE),
- &SwapEntry);
- MmFreeSwapPage(SwapEntry);
- }
- else
- {
- PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE));
- MmDeleteVirtualMapping(AddressSpace->Process,
- BaseAddress + (i*PAGESIZE),
- FALSE, NULL, NULL);
- if (PhysicalAddr.u.LowPart != 0)
- {
- MmDeleteRmap((ULONG_PTR)PhysicalAddr.u.LowPart, AddressSpace->Process,
- BaseAddress + (i * PAGESIZE));
- MmDereferencePage((ULONG_PTR)(PhysicalAddr.u.LowPart));
- }
- }
- }
- }
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
+ if (MemoryArea == NULL)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (OldAccessProtection == NULL)
+ OldAccessProtection = &OldAccessProtection_;
+
+ if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
+ {
+ Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
+ *NumberOfBytesToProtect, NewAccessProtection,
+ OldAccessProtection);
+ }
+ else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
+ {
+ Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
+ *NumberOfBytesToProtect,
+ NewAccessProtection,
+ OldAccessProtection);
+ }
+ else
+ {
+ /* FIXME: Should we return failure or success in this case? */
+ Status = STATUS_CONFLICTING_ADDRESSES;
+ }
- /*
- * If we are changing the protection attributes of a committed region then
- * alter the attributes for any allocated pages within the region
- */
- if (NewType == MEM_COMMIT && OldType == MEM_COMMIT &&
- OldProtect != NewProtect)
- {
- ULONG i;
-
- for (i=0; i <= (RegionSize/PAGESIZE); i++)
- {
- if (MmIsPagePresent(AddressSpace->Process,
- BaseAddress + (i*PAGESIZE)))
- {
- MmSetPageProtect(AddressSpace->Process,
- BaseAddress + (i*PAGESIZE),
- NewProtect);
- }
- }
- }
-}
+ MmUnlockAddressSpace(AddressSpace);
-VOID STATIC
-InsertAfterEntry(PLIST_ENTRY Previous,
- PLIST_ENTRY Entry)
-/*
- * FUNCTION: Insert a list entry after another entry in the list
- */
-{
- Previous->Flink->Blink = Entry;
-
- Entry->Flink = Previous->Flink;
- Entry->Blink = Previous;
-
- Previous->Flink = Entry;
+ return Status;
}
-#if 0
-VOID STATIC
-MmDumpSegmentsMemoryArea(PMEMORY_AREA MemoryArea)
-{
- PVOID CurrentAddress;
- PLIST_ENTRY CurrentEntry;
- PMM_SEGMENT CurrentSegment;
- PLIST_ENTRY ListHead;
-
- CurrentEntry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink;
- ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead;
-
- CurrentAddress = MemoryArea->BaseAddress;
- while (CurrentEntry != ListHead)
- {
- CurrentSegment = CONTAINING_RECORD(CurrentEntry,
- MM_SEGMENT,
- SegmentListEntry);
-
- DbgPrint("0x%x 0x%x %d %d\n",
- CurrentAddress,
- CurrentSegment->Length,
- CurrentSegment->Type,
- CurrentSegment->Protect);
-
- CurrentAddress = CurrentAddress + CurrentSegment->Length;
- CurrentEntry = CurrentEntry->Flink;
- }
-}
-#endif
-
-NTSTATUS
-MmSplitSegment(PMADDRESS_SPACE AddressSpace,
- PMEMORY_AREA MemoryArea,
- PVOID RegionAddress,
- ULONG RegionLength,
- ULONG Type,
- ULONG Protect,
- PMM_SEGMENT FirstSegment,
- PVOID FirstAddress)
-/*
- * FUNCTION: Split a memory segment internally
+
+/* (tMk 2004.II.5)
+ * FUNCTION:
+ * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
+ *
*/
+NTSTATUS STDCALL
+NtProtectVirtualMemory(IN HANDLE ProcessHandle,
+ IN OUT PVOID *UnsafeBaseAddress,
+ IN OUT ULONG *UnsafeNumberOfBytesToProtect,
+ IN ULONG NewAccessProtection,
+ OUT PULONG UnsafeOldAccessProtection)
{
- PMM_SEGMENT NewTopSegment;
- PMM_SEGMENT RegionSegment;
- ULONG OldType;
- ULONG OldProtect;
- ULONG OldLength;
-
- DPRINT("MmSplitSegment()\n");
- /*
- * Save the type and protection and length of the current segment
- */
- OldType = FirstSegment->Type;
- OldProtect = FirstSegment->Protect;
- OldLength = FirstSegment->Length;
-
- /*
- * If the segment is already of the right type and protection then
- * there is nothing to do.
- */
- if (FirstSegment->Type == Type && FirstSegment->Protect == Protect)
- {
- return(STATUS_SUCCESS);
- }
-
- /*
- * Allocate the segment we might need here because if the allocation
- * fails below it will be difficult to undo what we've done already.
- */
- NewTopSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
- TAG_MM_SEGMENT);
- if (NewTopSegment == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
+ PEPROCESS Process;
+ ULONG OldAccessProtection;
+ PVOID BaseAddress = NULL;
+ ULONG NumberOfBytesToProtect = 0;
+ KPROCESSOR_MODE PreviousMode;
+ NTSTATUS Status = STATUS_SUCCESS;
- if (FirstAddress < RegionAddress)
- {
- /*
- * If the region to be affected starts at a higher address than
- * the current segment then create a new segment for the
- * affected portion
- */
- RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
- TAG_MM_SEGMENT);
- if (RegionSegment == NULL)
- {
- ExFreePool(NewTopSegment);
- return(STATUS_NO_MEMORY);
- }
-
- RegionSegment->Type = Type;
- RegionSegment->Protect = Protect;
- RegionSegment->Length = RegionLength;
-
- FirstSegment->Length = RegionAddress - FirstAddress;
-
- InsertAfterEntry(&FirstSegment->SegmentListEntry,
- &RegionSegment->SegmentListEntry);
- }
- else
- {
- /*
- * Otherwise just set its type and protection and length
- */
-
- FirstSegment->Type = Type;
- FirstSegment->Protect = Protect;
- FirstSegment->Length = RegionLength;
-
- RegionSegment = FirstSegment;
- }
+ PreviousMode = ExGetPreviousMode();
- if ((FirstAddress + OldLength) > (RegionAddress + RegionLength))
+ if (PreviousMode != KernelMode)
{
- /*
- * If the top of the current segment extends after the affected
- * region then create a segment for the unaffected portion
- */
-
- NewTopSegment->Type = OldType;
- NewTopSegment->Protect = OldProtect;
- NewTopSegment->Length = (FirstAddress + OldLength) -
- (RegionAddress + RegionLength);
-
- InsertAfterEntry(&RegionSegment->SegmentListEntry,
- &NewTopSegment->SegmentListEntry);
+ _SEH_TRY
+ {
+ ProbeForWritePointer(UnsafeBaseAddress);
+ ProbeForWriteUlong(UnsafeNumberOfBytesToProtect);
+ ProbeForWriteUlong(UnsafeOldAccessProtection);
+
+ BaseAddress = *UnsafeBaseAddress;
+ NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
}
else
{
- ExFreePool(NewTopSegment);
- NewTopSegment = NULL;
+ BaseAddress = *UnsafeBaseAddress;
+ NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
}
-
- /*
- * Actually set the type and protection of the affected region
- */
- MmModifyAttributes(AddressSpace,
- RegionAddress,
- RegionLength,
- OldType,
- OldProtect,
- Type,
- Protect);
- return(STATUS_SUCCESS);
-}
-NTSTATUS MmGatherSegment(PMADDRESS_SPACE AddressSpace,
- PMEMORY_AREA MemoryArea,
- PVOID RegionAddress,
- ULONG RegionLength,
- ULONG Type,
- ULONG Protect,
- PMM_SEGMENT FirstSegment,
- PVOID FirstAddress)
-/*
- * FUNCTION: Do a virtual memory operation that will effect several
- * memory segments.
- * ARGUMENTS:
- * AddressSpace (IN) = Address space to affect
- * MemoryArea (IN) = Memory area to affect
- * BaseAddress (IN) = Base address of the region to affect
- * RegionSize (IN) = Size of the region to affect
- * Type (IN) = New type of the region
- * Protect (IN) = New protection of the region
- * CurrentSegment (IN) = First segment intersecting with the region
- * CurrentAddress (IN) = Start address of the first segment
- * interesting with the region
- * RETURNS: Status
- */
-{
- PMM_SEGMENT RegionSegment;
- PVOID CurrentAddress;
- ULONG RemainingLength;
- PLIST_ENTRY CurrentEntry;
- PLIST_ENTRY ListHead;
- PMM_SEGMENT CurrentSegment;
-
- if (FirstAddress < RegionAddress)
- {
- /*
- * If a portion of the first segment is not covered by the region then
- * we need to split it into two segments
- */
-
- RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
- TAG_MM_SEGMENT);
- if (RegionSegment == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
-
- RegionSegment->Type = Type;
- RegionSegment->Protect = Protect;
- RegionSegment->Length = (FirstAddress + FirstSegment->Length) -
- RegionAddress;
-
- FirstSegment->Length = RegionAddress - FirstAddress;
-
- InsertAfterEntry(&FirstSegment->SegmentListEntry,
- &RegionSegment->SegmentListEntry);
-
- MmModifyAttributes(AddressSpace,
- RegionAddress,
- RegionSegment->Length,
- FirstSegment->Type,
- FirstSegment->Protect,
- Type,
- Protect);
-
- CurrentAddress = FirstAddress + FirstSegment->Length +
- RegionSegment->Length;
- }
- else
- {
- /*
- * Otherwise just change the attributes of the segment
- */
-
- ULONG OldType;
- ULONG OldProtect;
-
- OldType = FirstSegment->Type;
- OldProtect = FirstSegment->Protect;
-
- FirstSegment->Type = Type;
- FirstSegment->Protect = Protect;
-
- RegionSegment = FirstSegment;
-
- MmModifyAttributes(AddressSpace,
- RegionAddress,
- FirstSegment->Length,
- OldType,
- OldProtect,
- Type,
- Protect);
-
- CurrentAddress = FirstAddress + RegionSegment->Length;
- }
-
- /*
- * Change the attributes of all the complete segments lying inside the
- * affected region
- */
- RemainingLength = RegionLength - RegionSegment->Length;
- CurrentEntry = RegionSegment->SegmentListEntry.Flink;
- CurrentSegment = CONTAINING_RECORD(CurrentEntry,
- MM_SEGMENT,
- SegmentListEntry);
- ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead;
-
- while (CurrentEntry != ListHead && RemainingLength > 0)
+ if ((ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 < (ULONG_PTR)BaseAddress ||
+ (ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 >= MmUserProbeAddress)
{
- ULONG OldType;
- ULONG OldProtect;
- ULONG OldLength;
-
- /*
- * If this segment will not be completely covered by the
- * affected region then break
- */
- if (CurrentSegment->Length > RemainingLength)
- {
- break;
- }
-
- OldType = CurrentSegment->Type;
- OldProtect = CurrentSegment->Protect;
- OldLength = CurrentSegment->Length;
-
- /*
- * Extend the length of the previous segment to cover this one
- */
- RegionSegment->Length = RegionSegment->Length + OldLength;
- RemainingLength = RemainingLength - OldLength;
- CurrentAddress = CurrentAddress + OldLength;
- CurrentEntry = CurrentEntry->Flink;
-
- /*
- * Remove the current segment from the list
- */
- RemoveEntryList(&CurrentSegment->SegmentListEntry);
- ExFreePool(CurrentSegment);
-
- MmModifyAttributes(AddressSpace,
- CurrentAddress,
- OldLength,
- OldType,
- OldProtect,
- Type,
- Protect);
-
- CurrentSegment = CONTAINING_RECORD(CurrentEntry,
- MM_SEGMENT,
- SegmentListEntry);
+ /* Don't allow to change the protection of a kernel mode address */
+ return STATUS_INVALID_PARAMETER_2;
}
-
- /*
- * If we've run off the top of the memory area then bug check
- */
- if (CurrentEntry == ListHead && RemainingLength > 0)
- {
- KeBugCheck(0);
- }
-
- /*
- * We've only affected a portion of a segment then split it in two
+
+ /* (tMk 2004.II.5) in Microsoft SDK I read:
+ * 'if this parameter is NULL or does not point to a valid variable, the function fails'
*/
- if (RemainingLength > 0)
- {
- CurrentSegment->Length = CurrentSegment->Length - RemainingLength;
-
- RegionSegment->Length = RegionSegment->Length + RemainingLength;
-
- MmModifyAttributes(AddressSpace,
- CurrentAddress,
- RemainingLength,
- CurrentSegment->Type,
- CurrentSegment->Protect,
- Type,
- Protect);
- }
-
- return(STATUS_SUCCESS);
-}
+ if(UnsafeOldAccessProtection == NULL)
+ {
+ return(STATUS_INVALID_PARAMETER);
+ }
-NTSTATUS MmComplexVirtualMemoryOperation(PMADDRESS_SPACE AddressSpace,
- PMEMORY_AREA MemoryArea,
- PVOID BaseAddress,
- ULONG RegionSize,
- ULONG Type,
- ULONG Protect)
-{
- PMM_SEGMENT CurrentSegment;
- PVOID CurrentAddress;
-
- CurrentSegment = MmGetSegmentForAddress(MemoryArea,
- BaseAddress,
- &CurrentAddress);
- if (CurrentSegment == NULL)
- {
- KeBugCheck(0);
- }
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_VM_OPERATION,
+ PsProcessType,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("NtProtectVirtualMemory() = %x\n",Status);
+ return(Status);
+ }
+
+ Status = MiProtectVirtualMemory(Process,
+ &BaseAddress,
+ &NumberOfBytesToProtect,
+ NewAccessProtection,
+ &OldAccessProtection);
+
+ ObDereferenceObject(Process);
- if (BaseAddress >= CurrentAddress &&
- (BaseAddress + RegionSize) <= (CurrentAddress + CurrentSegment->Length))
+ if (PreviousMode != KernelMode)
{
- return((MmSplitSegment(AddressSpace,
- MemoryArea,
- BaseAddress,
- RegionSize,
- Type,
- Protect,
- CurrentSegment,
- CurrentAddress)));
+ _SEH_TRY
+ {
+ *UnsafeOldAccessProtection = OldAccessProtection;
+ *UnsafeBaseAddress = BaseAddress;
+ *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
}
else
{
- return((MmGatherSegment(AddressSpace,
- MemoryArea,
- BaseAddress,
- RegionSize,
- Type,
- Protect,
- CurrentSegment,
- CurrentAddress)));
+ *UnsafeOldAccessProtection = OldAccessProtection;
+ *UnsafeBaseAddress = BaseAddress;
+ *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
}
+
+ return(Status);
}
-NTSTATUS STDCALL
-NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
- IN OUT PVOID* UBaseAddress,
- IN ULONG ZeroBits,
- IN OUT PULONG URegionSize,
- IN ULONG AllocationType,
- IN ULONG Protect)
-/*
- * FUNCTION: Allocates a block of virtual memory in the process address space
- * ARGUMENTS:
- * ProcessHandle = The handle of the process which owns the virtual memory
- * BaseAddress = A pointer to the virtual memory allocated. If you
- * supply a non zero value the system will try to
- * allocate the memory at the address supplied. It round
- * it down to a multiple of the page size.
- * ZeroBits = (OPTIONAL) You can specify the number of high order bits
- * that must be zero, ensuring that the memory will be
- * allocated at a address below a certain value.
- * RegionSize = The number of bytes to allocate
- * AllocationType = Indicates the type of virtual memory you like to
- * allocated, can be a combination of MEM_COMMIT,
- * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
- * Protect = Indicates the protection type of the pages allocated, can be
- * a combination of PAGE_READONLY, PAGE_READWRITE,
- * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
- * PAGE_NOACCESS
- * REMARKS:
- * This function maps to the win32 VirtualAllocEx. Virtual memory is
- * process based so the protocol starts with a ProcessHandle. I
- * splitted the functionality of obtaining the actual address and
- * specifying the start address in two parameters ( BaseAddress and
- * StartAddress ) The NumberOfBytesAllocated specify the range and the
- * AllocationType and ProctectionType map to the other two parameters.
- * RETURNS: Status
+/* (tMk 2004.II.05)
+ * FUNCTION:
+ * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
+ *
+ * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
*/
+NTSTATUS STDCALL
+NtReadVirtualMemory(IN HANDLE ProcessHandle,
+ IN PVOID BaseAddress,
+ OUT PVOID Buffer,
+ IN ULONG NumberOfBytesToRead,
+ OUT PULONG NumberOfBytesRead OPTIONAL)
{
- PEPROCESS Process;
- MEMORY_AREA* MemoryArea;
- ULONG Type;
- NTSTATUS Status;
- PMADDRESS_SPACE AddressSpace;
- PMM_SEGMENT Segment;
- PVOID BaseAddress;
- ULONG RegionSize;
- PVOID PBaseAddress;
- ULONG PRegionSize;
-
- DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
- "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
- *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
- Protect);
-
- /*
- * Check the validity of the parameters
- */
- if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
- {
- return(STATUS_INVALID_PAGE_PROTECTION);
- }
- if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
+ PMDL Mdl;
+ PVOID SystemAddress;
+ KPROCESSOR_MODE PreviousMode;
+ PEPROCESS Process, CurrentProcess;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+ "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
+ Buffer,NumberOfBytesToRead);
+
+ if ((ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 < (ULONG_PTR)BaseAddress ||
+ (ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
{
- return(STATUS_INVALID_PARAMETER);
+ /* Don't allow to read from kernel space */
+ return STATUS_ACCESS_VIOLATION;
}
- if (((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == MEM_COMMIT) &&
- (*UBaseAddress == 0))
+
+ PreviousMode = ExGetPreviousMode();
+
+ if (PreviousMode != KernelMode)
{
- /* Fix for badly behaved vc applications. */
- AllocationType |= MEM_RESERVE;
+ if ((ULONG_PTR)Buffer + NumberOfBytesToRead - 1 < (ULONG_PTR)Buffer ||
+ (ULONG_PTR)Buffer + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
+ {
+ /* Don't allow to write into kernel space */
+ return STATUS_ACCESS_VIOLATION;
+ }
}
-
- PBaseAddress = *UBaseAddress;
- PRegionSize = *URegionSize;
-
- BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
- RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
- PAGE_ROUND_DOWN(PBaseAddress);
-
Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_OPERATION,
- NULL,
- UserMode,
- (PVOID*)(&Process),
- NULL);
+ PROCESS_VM_READ,
+ NULL,
+ PreviousMode,
+ (PVOID*)(&Process),
+ NULL);
if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ CurrentProcess = PsGetCurrentProcess();
+
+ if(PreviousMode != KernelMode)
+ {
+ _SEH_TRY
{
- DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
- return(Status);
+ if(NumberOfBytesRead != NULL)
+ {
+ ProbeForWriteUlong(NumberOfBytesRead);
+ }
}
-
- Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
- DPRINT("Type %x\n", Type);
-
- AddressSpace = &Process->AddressSpace;
- MmLockAddressSpace(AddressSpace);
-
- if ((PBaseAddress != 0) &&
- ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == MEM_COMMIT))
+ _SEH_HANDLE
{
- MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace,
- BaseAddress);
-
- if (MemoryArea != NULL &&
- MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
- MemoryArea->Length >= RegionSize)
- {
- Status = MmComplexVirtualMemoryOperation(AddressSpace,
- MemoryArea,
- BaseAddress,
- RegionSize,
- Type,
- Protect);
- /* FIXME: Reserve/dereserve swap pages */
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
- return(Status);
- }
- else if (MemoryArea != NULL)
- {
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_UNSUCCESSFUL);
- }
+ Status = _SEH_GetExceptionCode();
}
-
- Segment = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(MM_SEGMENT),
- TAG_MM_SEGMENT);
- if (Segment == NULL)
+ _SEH_END;
+
+ if(!NT_SUCCESS(Status))
{
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_UNSUCCESSFUL);
+ return Status;
}
+ }
+
+
+ if (Process == CurrentProcess)
+ {
+ _SEH_TRY
+ {
+ RtlCopyMemory(Buffer, BaseAddress, NumberOfBytesToRead);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ else
+ {
+ Mdl = MmCreateMdl(NULL,
+ Buffer,
+ NumberOfBytesToRead);
+ if(Mdl == NULL)
+ {
+ ObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
+ _SEH_TRY
+ {
+ MmProbeAndLockPages(Mdl,
+ PreviousMode,
+ IoWriteAccess);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if(NT_SUCCESS(Status))
+ {
+ KeAttachProcess(&Process->Pcb);
+
+ SystemAddress = MmGetSystemAddressForMdl(Mdl);
+
+ Status = STATUS_SUCCESS;
+ _SEH_TRY {
+ Status = STATUS_PARTIAL_COPY;
+ RtlCopyMemory(SystemAddress, BaseAddress, NumberOfBytesToRead);
+ Status = STATUS_SUCCESS;
+ } _SEH_HANDLE {
+ if(Status != STATUS_PARTIAL_COPY)
+ Status = _SEH_GetExceptionCode();
+ } _SEH_END;
+
+ KeDetachProcess();
+
+ if (Mdl->MappedSystemVa != NULL)
+ {
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ }
+ MmUnlockPages(Mdl);
+ }
+ ExFreePool(Mdl);
+ }
- Status = MmCreateMemoryArea(Process,
- &Process->AddressSpace,
- MEMORY_AREA_VIRTUAL_MEMORY,
- &BaseAddress,
- RegionSize,
- Protect,
- &MemoryArea,
- PBaseAddress != 0);
-
- if (!NT_SUCCESS(Status))
+ ObDereferenceObject(Process);
+
+ if((NT_SUCCESS(Status) || Status == STATUS_PARTIAL_COPY) &&
+ NumberOfBytesRead != NULL)
+ {
+ _SEH_TRY
{
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
- return(Status);
+ *NumberOfBytesRead = NumberOfBytesToRead;
}
-
- InitializeListHead(&MemoryArea->Data.VirtualMemoryData.SegmentListHead);
-
- Segment->Type = Type;
- Segment->Protect = Protect;
- Segment->Length = RegionSize;
- InsertTailList(&MemoryArea->Data.VirtualMemoryData.SegmentListHead,
- &Segment->SegmentListEntry);
-
- if ((AllocationType & MEM_COMMIT) &&
- ((Protect & PAGE_READWRITE) ||
- (Protect & PAGE_EXECUTE_READWRITE)))
+ _SEH_HANDLE
{
- MmReserveSwapPages(RegionSize);
+ Status = _SEH_GetExceptionCode();
}
+ _SEH_END;
+ }
- *UBaseAddress = BaseAddress;
- *URegionSize = RegionSize;
- DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
-
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_SUCCESS);
+ return(Status);
}
-
-NTSTATUS STDCALL
-NtFlushVirtualMemory(IN HANDLE ProcessHandle,
- IN PVOID BaseAddress,
- IN ULONG NumberOfBytesToFlush,
- OUT PULONG NumberOfBytesFlushed OPTIONAL)
-/*
- * FUNCTION: Flushes virtual memory to file
- * ARGUMENTS:
- * ProcessHandle = Points to the process that allocated the virtual
- * memory
- * BaseAddress = Points to the memory address
- * NumberOfBytesToFlush = Limits the range to flush,
- * NumberOfBytesFlushed = Actual number of bytes flushed
- * RETURNS: Status
+/* (tMk 2004.II.05)
+ * FUNCTION: THIS function doesn't make a sense...
+ * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
*/
+NTSTATUS STDCALL
+NtUnlockVirtualMemory(HANDLE ProcessHandle,
+ PVOID BaseAddress,
+ ULONG NumberOfBytesToUnlock,
+ PULONG NumberOfBytesUnlocked OPTIONAL)
{
- UNIMPLEMENTED;
-}
-VOID
-MmFreeVirtualMemoryPage (IN BOOLEAN Before,
- IN PVOID Context,
- IN PMEMORY_AREA MemoryArea,
- IN PVOID Address,
- IN ULONG_PTR PhysicalAddress,
- IN SWAPENTRY SwapEntry,
- IN BOOLEAN Dirty)
-{
- PEPROCESS Process = (PEPROCESS)Context;
-
- if (Before)
- return;
-
- if (PhysicalAddress != 0)
- {
- MmDeleteRmap(PhysicalAddress, Process, Address);
- MmDereferencePage(PhysicalAddress);
- }
- else if (SwapEntry != 0)
- {
- MmFreeSwapPage(SwapEntry);
- }
-}
-
-VOID
-MmFreeVirtualMemory(PEPROCESS Process,
- PMEMORY_AREA MemoryArea)
-{
- PLIST_ENTRY current_entry;
- PMM_SEGMENT current;
-
- DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process, MemoryArea);
-
- current_entry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink;
- while (current_entry != &MemoryArea->Data.VirtualMemoryData.SegmentListHead)
- {
- current = CONTAINING_RECORD(current_entry, MM_SEGMENT, SegmentListEntry);
- current_entry = current_entry->Flink;
- DPRINT("ExFreePool(%p)\n", current);
- ExFreePool(current);
- }
-
- MmFreeMemoryArea(&Process->AddressSpace,
- MemoryArea->BaseAddress,
- 0,
- MmFreeVirtualMemoryPage,
- (PVOID)Process);
-}
+ // AG [08-20-03] : I have *no* idea if this is correct, I just used the
+ // other functions as a template and made a few intelligent guesses...
-NTSTATUS STDCALL
-NtFreeVirtualMemory(IN HANDLE ProcessHandle,
- IN PVOID* PBaseAddress,
- IN PULONG PRegionSize,
- IN ULONG FreeType)
-/*
- * FUNCTION: Frees a range of virtual memory
- * ARGUMENTS:
- * ProcessHandle = Points to the process that allocated the virtual
- * memory
- * BaseAddress = Points to the memory address, rounded down to a
- * multiple of the pagesize
- * RegionSize = Limits the range to free, rounded up to a multiple of
- * the paging size
- * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
- * RETURNS: Status
- */
-{
- MEMORY_AREA* MemoryArea;
NTSTATUS Status;
+ PMDL Mdl;
PEPROCESS Process;
- PMADDRESS_SPACE AddressSpace;
- PVOID BaseAddress;
- ULONG RegionSize;
-
- DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
- "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
- *PRegionSize,FreeType);
-
- BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
- RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) -
- PAGE_ROUND_DOWN((*PBaseAddress));
-
+
+ DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+ "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
+ NumberOfBytesToUnlock, NumberOfBytesUnlocked);
+
Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_OPERATION,
- PsProcessType,
- UserMode,
- (PVOID*)(&Process),
- NULL);
+ PROCESS_VM_WRITE,
+ NULL,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- AddressSpace = &Process->AddressSpace;
-
- MmLockAddressSpace(AddressSpace);
- MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
- BaseAddress);
- if (MemoryArea == NULL)
- {
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_UNSUCCESSFUL);
- }
-
- switch (FreeType)
- {
- case MEM_RELEASE:
- if (MemoryArea->BaseAddress != BaseAddress)
- {
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_UNSUCCESSFUL);
- }
-#if 0
- if ((MemoryArea->Type == MEMORY_AREA_COMMIT) &&
- ((MemoryArea->Attributes & PAGE_READWRITE) ||
- (MemoryArea->Attributes & PAGE_EXECUTE_READWRITE)))
- {
- MmDereserveSwapPages(PAGE_ROUND_UP(MemoryArea->Length));
- }
-#endif
-
- MmFreeVirtualMemory(Process, MemoryArea);
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_SUCCESS);
-
- case MEM_DECOMMIT:
- Status = MmComplexVirtualMemoryOperation(AddressSpace,
- MemoryArea,
- BaseAddress,
- RegionSize,
- MEM_RESERVE,
- PAGE_NOACCESS);
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(Status);
- }
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_NOT_IMPLEMENTED);
-}
+ {
+ return(Status);
+ }
+
+ Mdl = MmCreateMdl(NULL,
+ BaseAddress,
+ NumberOfBytesToUnlock);
+ if(Mdl == NULL)
+ {
+ ObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
+ ObDereferenceObject(Process);
-NTSTATUS STDCALL
-NtLockVirtualMemory(HANDLE ProcessHandle,
- PVOID BaseAddress,
- ULONG NumberOfBytesToLock,
- PULONG NumberOfBytesLocked)
-{
- UNIMPLEMENTED;
-}
+ if (Mdl->MappedSystemVa != NULL)
+ {
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ }
+ MmUnlockPages(Mdl);
+ ExFreePool(Mdl);
+ *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
-VOID
-MmChangeAreaProtection(PEPROCESS Process,
- PVOID BaseAddress,
- ULONG Length,
- ULONG Protect)
-{
- ULONG i;
-
- for (i=0; i<(Length/PAGESIZE); i++)
- {
- if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
- {
- MmSetPageProtect(Process,
- BaseAddress + (i*PAGESIZE),
- Protect);
- }
- }
+ return(STATUS_SUCCESS);
}
+/* (tMk 2004.II.05)
+ * FUNCTION:
+ * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
+ *
+ * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
+ */
NTSTATUS STDCALL
-NtProtectVirtualMemory(IN HANDLE ProcessHandle,
- IN PVOID BaseAddress,
- IN ULONG NumberOfBytesToProtect,
- IN ULONG NewAccessProtection,
- OUT PULONG OldAccessProtection)
+NtWriteVirtualMemory(IN HANDLE ProcessHandle,
+ IN PVOID BaseAddress,
+ IN PVOID Buffer,
+ IN ULONG NumberOfBytesToWrite,
+ OUT PULONG NumberOfBytesWritten OPTIONAL)
{
- PMEMORY_AREA MemoryArea;
+ PMDL Mdl;
+ PVOID SystemAddress;
PEPROCESS Process;
- NTSTATUS Status;
- PMADDRESS_SPACE AddressSpace;
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_OPERATION,
- PsProcessType,
- UserMode,
- (PVOID*)(&Process),
- NULL);
- if (Status != STATUS_SUCCESS)
+ KPROCESSOR_MODE PreviousMode;
+ NTSTATUS CopyStatus, Status = STATUS_SUCCESS;
+
+ DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
+ "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
+ Buffer,NumberOfBytesToWrite);
+
+ if ((ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 < (ULONG_PTR)BaseAddress ||
+ (ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
{
- DPRINT("NtProtectVirtualMemory() = %x\n",Status);
- return(Status);
+ /* Don't allow to write into kernel space */
+ return STATUS_ACCESS_VIOLATION;
}
- AddressSpace = &Process->AddressSpace;
+ PreviousMode = ExGetPreviousMode();
- MmLockAddressSpace(AddressSpace);
- MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
- BaseAddress);
- if (MemoryArea == NULL)
+ if (PreviousMode != KernelMode)
{
- DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_UNSUCCESSFUL);
+ if ((ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 < (ULONG_PTR)Buffer ||
+ (ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
+ {
+ /* Don't allow to read from kernel space */
+ return STATUS_ACCESS_VIOLATION;
+ }
+ if (NumberOfBytesWritten != NULL)
+ {
+ _SEH_TRY
+ {
+ ProbeForWriteUlong(NumberOfBytesWritten);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
}
-#if 0
- *OldAccessProtection = MemoryArea->Attributes;
- if (MemoryArea->BaseAddress == BaseAddress &&
- MemoryArea->Length == NumberOfBytesToProtect)
- {
- MemoryArea->Attributes = NewAccessProtection;
- }
+ Status = ObReferenceObjectByHandle(ProcessHandle,
+ PROCESS_VM_WRITE,
+ NULL,
+ UserMode,
+ (PVOID*)(&Process),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ CopyStatus = STATUS_SUCCESS;
+
+ /* Write memory */
+ if (Process == PsGetCurrentProcess())
+ {
+ if (PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
+ }
+ _SEH_HANDLE
+ {
+ CopyStatus = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ else
+ {
+ memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
+ }
+ }
else
- {
- MemoryArea = MmSplitMemoryArea(Process,
- &Process->AddressSpace,
- MemoryArea,
- BaseAddress,
- NumberOfBytesToProtect,
- MemoryArea->Type,
- NewAccessProtection);
- }
- MmChangeAreaProtection(Process,
- BaseAddress,
- NumberOfBytesToProtect,
- NewAccessProtection);
-#endif
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return(STATUS_SUCCESS);
-}
-
-
-NTSTATUS STDCALL NtQueryVirtualMemory (IN HANDLE ProcessHandle,
- IN PVOID Address,
- IN CINT VirtualMemoryInformationClass,
- OUT PVOID VirtualMemoryInformation,
- IN ULONG Length,
- OUT PULONG ResultLength)
-{
- NTSTATUS Status;
- PEPROCESS Process;
- MEMORY_AREA* MemoryArea;
+ {
+ /* Create MDL describing the source buffer. */
+ Mdl = MmCreateMdl(NULL,
+ Buffer,
+ NumberOfBytesToWrite);
+ if(Mdl == NULL)
+ {
+ ObDereferenceObject(Process);
+ return(STATUS_NO_MEMORY);
+ }
+ _SEH_TRY
+ {
+ /* Map the MDL. */
+ MmProbeAndLockPages(Mdl,
+ UserMode,
+ IoReadAccess);
+ }
+ _SEH_HANDLE
+ {
+ CopyStatus = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if (NT_SUCCESS(CopyStatus))
+ {
+ /* Copy memory from the mapped MDL into the target buffer. */
+ KeAttachProcess(&Process->Pcb);
+
+ SystemAddress = MmGetSystemAddressForMdl(Mdl);
+ if (PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
+ }
+ _SEH_HANDLE
+ {
+ CopyStatus = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ else
+ {
+ memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
+ }
+
+ KeDetachProcess();
+ }
- DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
- "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
- "Length %lu ResultLength %x)\n",ProcessHandle,Address,
- VirtualMemoryInformationClass,VirtualMemoryInformation,
- Length,ResultLength);
+ /* Free the MDL. */
+ if (Mdl->MappedSystemVa != NULL)
+ {
+ MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
+ }
+ MmUnlockPages(Mdl);
+ ExFreePool(Mdl);
+ }
+ ObDereferenceObject(Process);
- switch(VirtualMemoryInformationClass)
+ if (NT_SUCCESS(CopyStatus) && NumberOfBytesWritten != NULL)
{
- case MemoryBasicInformation:
- {
- PMEMORY_BASIC_INFORMATION Info =
- (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
- PMADDRESS_SPACE AddressSpace;
-
- if (Length < sizeof(MEMORY_BASIC_INFORMATION))
- {
- ObDereferenceObject(Process);
- return STATUS_INFO_LENGTH_MISMATCH;
- }
-
- if (ResultLength)
- {
- *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
- }
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_QUERY_INFORMATION,
- NULL,
- UserMode,
- (PVOID*)(&Process),
- NULL);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NtQueryVirtualMemory() = %x\n",Status);
- return(Status);
- }
-
- AddressSpace = &Process->AddressSpace;
- MmLockAddressSpace(AddressSpace);
- MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
- Address);
-
- if (MemoryArea == NULL)
- {
- Info->State = MEM_FREE;
- DPRINT("Virtual memory at %p is free.\n", Address);
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return (STATUS_SUCCESS);
- }
-
-#if 0
- if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
- {
- Info->State = MEM_COMMIT;
- }
- else
- {
- Info->State = MEM_RESERVE;
- }
-#endif
-
- Info->BaseAddress = MemoryArea->BaseAddress;
- Info->RegionSize = MemoryArea->Length;
-
- DPRINT("BaseAddress %p, RegionSize %x State %x\n",
- Info->BaseAddress, Info->RegionSize, Info->State);
-
- MmUnlockAddressSpace(AddressSpace);
- ObDereferenceObject(Process);
- return STATUS_SUCCESS;
- }
- break;
+ if (PreviousMode != KernelMode)
+ {
+ _SEH_TRY
+ {
+ *NumberOfBytesWritten = NumberOfBytesToWrite;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ else
+ {
+ *NumberOfBytesWritten = NumberOfBytesToWrite;
+ }
}
- return STATUS_INVALID_INFO_CLASS;
+ return(NT_SUCCESS(CopyStatus) ? Status : CopyStatus);
}
+/*
+ * @unimplemented
+ */
-NTSTATUS STDCALL
-NtReadVirtualMemory(IN HANDLE ProcessHandle,
- IN PVOID BaseAddress,
- OUT PVOID Buffer,
- IN ULONG NumberOfBytesToRead,
- OUT PULONG NumberOfBytesRead)
+PVOID
+STDCALL
+MmGetVirtualForPhysical (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
{
- NTSTATUS Status;
- PMDL Mdl;
- PVOID SystemAddress;
- PEPROCESS Process;
-
- DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
- "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
- Buffer,NumberOfBytesToRead);
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_WRITE,
- NULL,
- UserMode,
- (PVOID*)(&Process),
- NULL);
- if (Status != STATUS_SUCCESS)
- {
- return(Status);
- }
-
- Mdl = MmCreateMdl(NULL,
- Buffer,
- NumberOfBytesToRead);
- MmProbeAndLockPages(Mdl,
- UserMode,
- IoWriteAccess);
-
- KeAttachProcess(Process);
-
- SystemAddress = MmGetSystemAddressForMdl(Mdl);
- memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
-
- KeDetachProcess();
-
- if (Mdl->MappedSystemVa != NULL)
- {
- MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
- }
- MmUnlockPages(Mdl);
- ExFreePool(Mdl);
-
- ObDereferenceObject(Process);
-
- *NumberOfBytesRead = NumberOfBytesToRead;
- return(STATUS_SUCCESS);
+ UNIMPLEMENTED;
+ return 0;
}
-
-NTSTATUS STDCALL
-NtUnlockVirtualMemory(HANDLE ProcessHandle,
- PVOID BaseAddress,
- ULONG NumberOfBytesToUnlock,
- PULONG NumberOfBytesUnlocked OPTIONAL)
+/* FUNCTION:
+ * Called from EngSecureMem (subsys\win32k\eng\mem.c)
+ * @unimplemented
+ */
+PVOID STDCALL
+MmSecureVirtualMemory (PVOID Address,
+ SIZE_T Length,
+ ULONG Mode)
{
- UNIMPLEMENTED;
+ /* Only works for user space */
+ if (MmHighestUserAddress < Address)
+ {
+ return NULL;
+ }
+
+ UNIMPLEMENTED;
+
+ return 0;
}
-NTSTATUS STDCALL
-NtWriteVirtualMemory(IN HANDLE ProcessHandle,
- IN PVOID BaseAddress,
- IN PVOID Buffer,
- IN ULONG NumberOfBytesToWrite,
- OUT PULONG NumberOfBytesWritten)
+/* FUNCTION:
+ * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
+ * @unimplemented
+ */
+VOID STDCALL
+MmUnsecureVirtualMemory(PVOID SecureMem)
{
- NTSTATUS Status;
- PMDL Mdl;
- PVOID SystemAddress;
- PEPROCESS Process;
-
- DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
- "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
- Buffer,NumberOfBytesToWrite);
-
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_VM_WRITE,
- NULL,
- UserMode,
- (PVOID*)(&Process),
- NULL);
- if (Status != STATUS_SUCCESS)
- {
- return(Status);
- }
-
- Mdl = MmCreateMdl(NULL,
- Buffer,
- NumberOfBytesToWrite);
- MmProbeAndLockPages(Mdl,
- UserMode,
- IoReadAccess);
-
- KeAttachProcess(Process);
-
- DPRINT("Attached to process copying memory\n");
-
- SystemAddress = MmGetSystemAddressForMdl(Mdl);
- memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
-
- DPRINT("Done copy\n");
-
- KeDetachProcess();
-
- ObDereferenceObject(Process);
+ if (NULL == SecureMem)
+ {
+ return;
+ }
- if (Mdl->MappedSystemVa != NULL)
- {
- MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
- }
- MmUnlockPages(Mdl);
- ExFreePool(Mdl);
-
- *NumberOfBytesWritten = NumberOfBytesToWrite;
-
- DPRINT("Finished NtWriteVirtualMemory()\n");
-
- return(STATUS_SUCCESS);
+ UNIMPLEMENTED;
}
-DWORD
-STDCALL
-MmSecureVirtualMemory (
- DWORD Unknown0,
- DWORD Unknown1,
- DWORD Unknown2
- )
+/*
+ * @implemented
+ */
+VOID STDCALL
+ProbeForRead (IN CONST VOID *Address,
+ IN ULONG Length,
+ IN ULONG Alignment)
{
- UNIMPLEMENTED;
- return 0;
+ ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+
+ if (Length == 0)
+ return;
+
+ if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
+ {
+ ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
+ }
+ else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address ||
+ (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress)
+ {
+ ExRaiseStatus (STATUS_ACCESS_VIOLATION);
+ }
}
-VOID
-STDCALL
-MmUnsecureVirtualMemory (
- DWORD Unknown0
- )
+/*
+ * @implemented
+ */
+VOID STDCALL
+ProbeForWrite (IN CONST VOID *Address,
+ IN ULONG Length,
+ IN ULONG Alignment)
{
- UNIMPLEMENTED;
+ volatile CHAR *Current;
+ PCHAR Last;
+
+ ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
+
+ if (Length == 0)
+ return;
+
+ if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
+ {
+ ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
+ }
+
+ Last = (CHAR*)((ULONG_PTR)Address + Length - 1);
+ if ((ULONG_PTR)Last < (ULONG_PTR)Address ||
+ (ULONG_PTR)Last >= (ULONG_PTR)MmUserProbeAddress)
+ {
+ ExRaiseStatus (STATUS_ACCESS_VIOLATION);
+ }
+
+ /* Check for accessible pages */
+ Current = (CHAR*)Address;
+ *Current = *Current;
+ Current = (PCHAR)((ULONG_PTR)PAGE_ROUND_DOWN(Current) + PAGE_SIZE);
+ while (Current <= Last)
+ {
+ *Current = *Current;
+ Current = (CHAR*)((ULONG_PTR)Current + PAGE_SIZE);
+ }
}
/* EOF */