- Multiple Virtual Memory API fixes:

- MiDoMappedcopy: The MDL should have 16 pages total, so MI_MAPPED_COPY_PAGES should be 14, not 16, to account for the MDL page itself, and the extra add-on page.
  - MiDoMappedCopy: Check for working set quota exception.
  - NtRead/WriteVirtualMemory: Do not attempt to do any work if the size is 0.
  - NtRead/WriteVirtualMemory: Do not return SEH status if we fail to write the number of bytes read/written -- return the function status.
  - NtProtectVirtualMemory: Protect the memory while attached to the target process.
  - NtProtectVirtualMemory: Do not return SEH status if we fail to write the number of bytes protected -- return the function status.
  - NtLock/UnlockVirtualMemory: Fix incorrect function definition. The last parameter is a bitfield. The middle two parameters are pointers, not values.
  - VirtualLock/Unlock: Fix calling NtLock/UnlockVirtualMemory with new correct function definitions. Call with MAP_PROCESS.
  - NtLock/UnlockVirtualMemory: Apply SEH. Validate flags. Validate parameters.
  - NtLock/UnlockVirtualMemory: Attach to the process while doing the operation. Reference the process.
  - NtLock/UnlockVirtualMemory: Check for SE_LOCK_MEMORY_PRIVILEGE if MAP_SYSTEM is specified.
  - Move MAP_SYSTEM and MAP_PROCESS from ntifs.h to mmtypes.h in NDK.
  - NtLock/UnlockVirtualMemory: Return success and semi-legitimate return values saying nothing was actually done.
  - NtFlushVirtualMemory: Apply SEH. Validate flags. Validate parameters. Call MmFlushVirtualMemory.
  - NtFlushVirtualMemory: Reference the process.
  - NtFlushVirtualMemory: Return success and semi-legitimate return values indicating nothing was flushed.
  - NtGetWriteWatch: Fix function prototype.
  - NtGet/ResetWriteWatch: Apply SEH instead of hacked parameter checks. Validate parameters.
  - NtGet/ResetWriteWatch: Reference the process.
  - NtGet/ResetWriteWatch: Return semi-legitimate return values indicating nothing was written to.
- These APIs are now owned by ARM3.


svn path=/trunk/; revision=43480
This commit is contained in:
ReactOS Portable Systems Group 2009-10-15 16:50:49 +00:00
parent e3d56ce220
commit c04d1d038e
7 changed files with 1790 additions and 813 deletions

View file

@ -170,14 +170,15 @@ NTAPI
VirtualLock(IN LPVOID lpAddress,
IN SIZE_T dwSize)
{
ULONG BytesLocked;
NTSTATUS Status;
ULONG RegionSize = dwSize;
PVOID BaseAddress = lpAddress;
/* Lock the memory */
Status = NtLockVirtualMemory(NtCurrentProcess(),
lpAddress,
dwSize,
&BytesLocked);
&BaseAddress,
&RegionSize,
MAP_PROCESS);
if (!NT_SUCCESS(Status))
{
/* We failed */
@ -244,14 +245,15 @@ NTAPI
VirtualUnlock(IN LPVOID lpAddress,
IN SIZE_T dwSize)
{
ULONG BytesLocked;
NTSTATUS Status;
/* Unlock the memory */
ULONG RegionSize = dwSize;
PVOID BaseAddress = lpAddress;
/* Lock the memory */
Status = NtUnlockVirtualMemory(NtCurrentProcess(),
lpAddress,
dwSize,
&BytesLocked);
&BaseAddress,
&RegionSize,
MAP_PROCESS);
if (!NT_SUCCESS(Status))
{
/* We failed */

View file

@ -329,8 +329,6 @@ typedef enum _SECURITY_LOGON_TYPE
#define MAILSLOT_SIZE_AUTO 0
#define MAP_PROCESS 1L
#define MAP_SYSTEM 2L
#define MEM_DOS_LIM 0x40000000
#define MCB_FLAG_RAISE_ON_ALLOCATION_FAILURE 1

View file

@ -173,10 +173,10 @@ NTSYSCALLAPI
NTSTATUS
NTAPI
NtLockVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
SIZE_T NumberOfBytesToLock,
PSIZE_T NumberOfBytesLocked
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T NumberOfBytesToLock,
IN ULONG MapType
);
NTSTATUS
@ -278,9 +278,9 @@ NTSTATUS
NTAPI
NtUnlockVirtualMemory(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN SIZE_T NumberOfBytesToUnlock,
OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T NumberOfBytesToUnlock,
IN ULONG MapType
);
NTSYSCALLAPI
@ -367,10 +367,10 @@ NTSYSAPI
NTSTATUS
NTAPI
ZwLockVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
SIZE_T NumberOfBytesToLock,
PSIZE_T NumberOfBytesLocked
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T NumberOfBytesToLock,
IN ULONG MapType
);
NTSYSAPI
@ -448,9 +448,9 @@ NTSTATUS
NTAPI
ZwUnlockVirtualMemory(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN SIZE_T NumberOfBytesToUnlock,
OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T NumberOfBytesToUnlock,
IN ULONG MapType
);
NTSYSAPI

View file

@ -57,6 +57,12 @@ Author:
#define MMPFNUSE_DRIVERLOCKPAGE 10
#define MMPFNUSE_KERNELSTACK 11
//
// Lock/Unlock Virtuam Memory Flags
//
#define MAP_PROCESS 1
#define MAP_SYSTEM 2
#ifndef NTOS_MODE_USER
//

File diff suppressed because it is too large Load diff

View file

@ -13,392 +13,8 @@
#define NDEBUG
#include <debug.h>
#define MI_MAPPED_COPY_PAGES 16
#define MI_POOL_COPY_BYTES 512
#define MI_MAX_TRANSFER_SIZE 64 * 1024
#define TAG_VM 'wRmV'
/* PRIVATE FUNCTIONS **********************************************************/
LONG
MiGetExceptionInfo(EXCEPTION_POINTERS *ExceptionInfo, BOOLEAN * HaveBadAddress, ULONG_PTR * BadAddress)
{
PEXCEPTION_RECORD ExceptionRecord;
PAGED_CODE();
/* Assume default */
*HaveBadAddress = FALSE;
/* Get the exception record */
ExceptionRecord = ExceptionInfo->ExceptionRecord;
/* Look at the exception code */
if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
(ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
(ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
{
/* We can tell the address if we have more than one parameter */
if (ExceptionRecord->NumberParameters > 1)
{
/* Return the address */
*HaveBadAddress = TRUE;
*BadAddress = ExceptionRecord->ExceptionInformation[1];
}
}
/* Continue executing the next handler */
return EXCEPTION_EXECUTE_HANDLER;
}
NTSTATUS
NTAPI
MiDoMappedCopy(IN PEPROCESS SourceProcess,
IN PVOID SourceAddress,
IN PEPROCESS TargetProcess,
OUT PVOID TargetAddress,
IN SIZE_T BufferSize,
IN KPROCESSOR_MODE PreviousMode,
OUT PSIZE_T ReturnSize)
{
PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
PMDL Mdl = (PMDL)MdlBuffer;
SIZE_T TotalSize, CurrentSize, RemainingSize;
volatile BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving;
volatile BOOLEAN PagesLocked;
PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
volatile PVOID MdlAddress;
KAPC_STATE ApcState;
BOOLEAN HaveBadAddress;
ULONG_PTR BadAddress;
PAGED_CODE();
/* Calculate the maximum amount of data to move */
TotalSize = (MI_MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
if (BufferSize <= TotalSize) TotalSize = BufferSize;
CurrentSize = TotalSize;
RemainingSize = BufferSize;
/* Loop as long as there is still data */
while (RemainingSize > 0)
{
/* Check if this transfer will finish everything off */
if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
/* Attach to the source address space */
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
/* Reset state for this pass */
MdlAddress = NULL;
PagesLocked = FALSE;
FailedInMoving = FALSE;
ASSERT(FailedInProbe == FALSE);
/* Protect user-mode copy */
_SEH2_TRY
{
/* If this is our first time, probe the buffer */
if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
{
/* Catch a failure here */
FailedInProbe = TRUE;
/* Do the probe */
ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
/* Passed */
FailedInProbe = FALSE;
}
/* Initialize and probe and lock the MDL */
MmInitializeMdl (Mdl, CurrentAddress, CurrentSize);
MmProbeAndLockPages (Mdl, PreviousMode, IoReadAccess);
PagesLocked = TRUE;
/* Now map the pages */
MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
KernelMode,
MmCached,
NULL,
FALSE,
HighPagePriority);
if (!MdlAddress)
{
/* Use our SEH handler to pick this up */
FailedInMapping = TRUE;
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
}
/* Now let go of the source and grab to the target process */
KeUnstackDetachProcess(&ApcState);
KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
/* Check if this is our first time through */
if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
{
/* Catch a failure here */
FailedInProbe = TRUE;
/* Do the probe */
ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
/* Passed */
FailedInProbe = FALSE;
}
/* Now do the actual move */
FailedInMoving = TRUE;
RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
}
_SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress, &BadAddress))
{
/* Detach from whoever we may be attached to */
KeUnstackDetachProcess(&ApcState);
/* Check if we had mapped the pages */
if (MdlAddress) MmUnmapLockedPages(MdlAddress, Mdl);
/* Check if we had locked the pages */
if (PagesLocked) MmUnlockPages(Mdl);
/* Check if we failed during the probe or mapping */
if ((FailedInProbe) || (FailedInMapping))
{
/* Exit */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
/* Otherwise, we failed probably during the move */
*ReturnSize = BufferSize - RemainingSize;
if (FailedInMoving)
{
/* Check if we know exactly where we stopped copying */
if (HaveBadAddress)
{
/* Return the exact number of bytes copied */
*ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
}
}
/* Return partial copy */
_SEH2_YIELD(return STATUS_PARTIAL_COPY);
}
_SEH2_END;
/* Detach from target */
KeUnstackDetachProcess(&ApcState);
/* Unmap and unlock */
MmUnmapLockedPages(MdlAddress, Mdl);
MmUnlockPages(Mdl);
/* Update location and size */
RemainingSize -= CurrentSize;
CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
}
/* All bytes read */
*ReturnSize = BufferSize;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
MiDoPoolCopy(IN PEPROCESS SourceProcess,
IN PVOID SourceAddress,
IN PEPROCESS TargetProcess,
OUT PVOID TargetAddress,
IN SIZE_T BufferSize,
IN KPROCESSOR_MODE PreviousMode,
OUT PSIZE_T ReturnSize)
{
UCHAR StackBuffer[MI_POOL_COPY_BYTES];
SIZE_T TotalSize, CurrentSize, RemainingSize;
volatile BOOLEAN FailedInProbe = FALSE, FailedInMoving, HavePoolAddress = FALSE;
PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
PVOID PoolAddress;
KAPC_STATE ApcState;
BOOLEAN HaveBadAddress;
ULONG_PTR BadAddress;
PAGED_CODE();
/* Calculate the maximum amount of data to move */
TotalSize = MI_MAX_TRANSFER_SIZE;
if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
CurrentSize = TotalSize;
RemainingSize = BufferSize;
/* Check if we can use the stack */
if (BufferSize <= MI_POOL_COPY_BYTES)
{
/* Use it */
PoolAddress = (PVOID)StackBuffer;
}
else
{
/* Allocate pool */
PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, TAG_VM);
if (!PoolAddress) ASSERT(FALSE);
HavePoolAddress = TRUE;
}
/* Loop as long as there is still data */
while (RemainingSize > 0)
{
/* Check if this transfer will finish everything off */
if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
/* Attach to the source address space */
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
/* Reset state for this pass */
FailedInMoving = FALSE;
ASSERT(FailedInProbe == FALSE);
/* Protect user-mode copy */
_SEH2_TRY
{
/* If this is our first time, probe the buffer */
if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
{
/* Catch a failure here */
FailedInProbe = TRUE;
/* Do the probe */
ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
/* Passed */
FailedInProbe = FALSE;
}
/* Do the copy */
RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
/* Now let go of the source and grab to the target process */
KeUnstackDetachProcess(&ApcState);
KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
/* Check if this is our first time through */
if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
{
/* Catch a failure here */
FailedInProbe = TRUE;
/* Do the probe */
ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
/* Passed */
FailedInProbe = FALSE;
}
/* Now do the actual move */
FailedInMoving = TRUE;
RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
}
_SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress, &BadAddress))
{
/* Detach from whoever we may be attached to */
KeUnstackDetachProcess(&ApcState);
/* Check if we had allocated pool */
if (HavePoolAddress) ExFreePool(PoolAddress);
/* Check if we failed during the probe */
if (FailedInProbe)
{
/* Exit */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
/* Otherwise, we failed probably during the move */
*ReturnSize = BufferSize - RemainingSize;
if (FailedInMoving)
{
/* Check if we know exactly where we stopped copying */
if (HaveBadAddress)
{
/* Return the exact number of bytes copied */
*ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
}
}
/* Return partial copy */
_SEH2_YIELD(return STATUS_PARTIAL_COPY);
}
_SEH2_END;
/* Detach from target */
KeUnstackDetachProcess(&ApcState);
/* Update location and size */
RemainingSize -= CurrentSize;
CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
}
/* Check if we had allocated pool */
if (HavePoolAddress) ExFreePool(PoolAddress);
/* All bytes read */
*ReturnSize = BufferSize;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
MmCopyVirtualMemory(IN PEPROCESS SourceProcess,
IN PVOID SourceAddress,
IN PEPROCESS TargetProcess,
OUT PVOID TargetAddress,
IN SIZE_T BufferSize,
IN KPROCESSOR_MODE PreviousMode,
OUT PSIZE_T ReturnSize)
{
NTSTATUS Status;
PEPROCESS Process = SourceProcess;
/* Don't accept zero-sized buffers */
if (!BufferSize) return STATUS_SUCCESS;
/* If we are copying from ourselves, lock the target instead */
if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
/* Acquire rundown protection */
if (!ExAcquireRundownProtection(&Process->RundownProtect))
{
/* Fail */
return STATUS_PROCESS_IS_TERMINATING;
}
/* See if we should use the pool copy */
if (BufferSize > MI_POOL_COPY_BYTES)
{
/* Use MDL-copy */
Status = MiDoMappedCopy(SourceProcess,
SourceAddress,
TargetProcess,
TargetAddress,
BufferSize,
PreviousMode,
ReturnSize);
}
else
{
/* Do pool copy */
Status = MiDoPoolCopy(SourceProcess,
SourceAddress,
TargetProcess,
TargetAddress,
BufferSize,
PreviousMode,
ReturnSize);
}
/* Release the lock */
ExReleaseRundownProtection(&Process->RundownProtect);
return Status;
}
NTSTATUS FASTCALL
MiQueryVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID Address,
@ -721,323 +337,8 @@ MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress,
NULL);
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @unimplemented
*/
PVOID
NTAPI
MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress)
{
UNIMPLEMENTED;
return 0;
}
/*
* @unimplemented
*/
PVOID
NTAPI
MmSecureVirtualMemory(IN PVOID Address,
IN SIZE_T Length,
IN ULONG Mode)
{
UNIMPLEMENTED;
return NULL;
}
/*
* @unimplemented
*/
VOID
NTAPI
MmUnsecureVirtualMemory(IN PVOID SecureMem)
{
UNIMPLEMENTED;
}
/* SYSTEM CALLS ***************************************************************/
NTSTATUS
NTAPI
NtReadVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN SIZE_T NumberOfBytesToRead,
OUT PSIZE_T NumberOfBytesRead OPTIONAL)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PEPROCESS Process;
NTSTATUS Status;
SIZE_T BytesRead = 0;
PAGED_CODE();
/* Check if we came from user mode */
if (PreviousMode != KernelMode)
{
/* Validate the read addresses */
if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
(((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
(((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
(((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
{
/* Don't allow to write into kernel space */
return STATUS_ACCESS_VIOLATION;
}
/* Enter SEH for probe */
_SEH2_TRY
{
/* Probe the output value */
if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Reference the process */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_READ,
PsProcessType,
PreviousMode,
(PVOID*)(&Process),
NULL);
if (NT_SUCCESS(Status))
{
/* Do the copy */
Status = MmCopyVirtualMemory(Process,
BaseAddress,
PsGetCurrentProcess(),
Buffer,
NumberOfBytesToRead,
PreviousMode,
&BytesRead);
/* Dereference the process */
ObDereferenceObject(Process);
}
/* Check if the caller sent this parameter */
if (NumberOfBytesRead)
{
/* Enter SEH to guard write */
_SEH2_TRY
{
/* Return the number of bytes read */
*NumberOfBytesRead = BytesRead;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Handle exception */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
NtWriteVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN SIZE_T NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PEPROCESS Process;
NTSTATUS Status;
ULONG BytesWritten = 0;
PAGED_CODE();
/* Check if we came from user mode */
if (PreviousMode != KernelMode)
{
/* Validate the read addresses */
if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
(((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
(((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
(((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
{
/* Don't allow to write into kernel space */
return STATUS_ACCESS_VIOLATION;
}
/* Enter SEH for probe */
_SEH2_TRY
{
/* Probe the output value */
if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Reference the process */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_WRITE,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if (NT_SUCCESS(Status))
{
/* Do the copy */
Status = MmCopyVirtualMemory(PsGetCurrentProcess(),
Buffer,
Process,
BaseAddress,
NumberOfBytesToWrite,
PreviousMode,
&BytesWritten);
/* Dereference the process */
ObDereferenceObject(Process);
}
/* Check if the caller sent this parameter */
if (NumberOfBytesWritten)
{
/* Enter SEH to guard write */
_SEH2_TRY
{
/* Return the number of bytes read */
*NumberOfBytesWritten = BytesWritten;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Handle exception */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
NtProtectVirtualMemory(IN HANDLE ProcessHandle,
IN OUT PVOID *UnsafeBaseAddress,
IN OUT SIZE_T *UnsafeNumberOfBytesToProtect,
IN ULONG NewAccessProtection,
OUT PULONG UnsafeOldAccessProtection)
{
PEPROCESS Process;
ULONG OldAccessProtection;
ULONG Protection;
PVOID BaseAddress = NULL;
SIZE_T NumberOfBytesToProtect = 0;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
/* Check for valid protection flags */
Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
if (Protection != PAGE_NOACCESS &&
Protection != PAGE_READONLY &&
Protection != PAGE_READWRITE &&
Protection != PAGE_WRITECOPY &&
Protection != PAGE_EXECUTE &&
Protection != PAGE_EXECUTE_READ &&
Protection != PAGE_EXECUTE_READWRITE &&
Protection != PAGE_EXECUTE_WRITECOPY)
{
return STATUS_INVALID_PAGE_PROTECTION;
}
/* Check if we came from user mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH for probing */
_SEH2_TRY
{
/* Validate all outputs */
ProbeForWritePointer(UnsafeBaseAddress);
ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
ProbeForWriteUlong(UnsafeOldAccessProtection);
/* Capture them */
BaseAddress = *UnsafeBaseAddress;
NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* Capture directly */
BaseAddress = *UnsafeBaseAddress;
NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
}
/* Catch illegal base address */
if (BaseAddress > (PVOID)MmUserProbeAddress) return STATUS_INVALID_PARAMETER_2;
/* Catch illegal region size */
if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
{
/* Fail */
return STATUS_INVALID_PARAMETER_3;
}
/* 0 is also illegal */
if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
/* Get a reference to the process */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
PreviousMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Do the actual work */
Status = MiProtectVirtualMemory(Process,
&BaseAddress,
&NumberOfBytesToProtect,
NewAccessProtection,
&OldAccessProtection);
/* Release reference */
ObDereferenceObject(Process);
/* Enter SEH to return data */
_SEH2_TRY
{
/* Return data to user */
*UnsafeOldAccessProtection = OldAccessProtection;
*UnsafeBaseAddress = BaseAddress;
*UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Catch exception */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Return status */
return Status;
}
NTSTATUS NTAPI
NtQueryVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID Address,
@ -1202,92 +503,4 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle,
return(Status);
}
NTSTATUS
NTAPI
NtLockVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN SIZE_T NumberOfBytesToLock,
OUT PSIZE_T NumberOfBytesLocked OPTIONAL)
{
UNIMPLEMENTED;
if (NumberOfBytesLocked) *NumberOfBytesLocked = 0;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
NtUnlockVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN SIZE_T NumberOfBytesToUnlock,
OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL)
{
UNIMPLEMENTED;
if (NumberOfBytesUnlocked) *NumberOfBytesUnlocked = 0;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
NtFlushVirtualMemory(IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PSIZE_T NumberOfBytesToFlush,
OUT PIO_STATUS_BLOCK IoStatusBlock)
{
UNIMPLEMENTED;
return STATUS_SUCCESS;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtGetWriteWatch(IN HANDLE ProcessHandle,
IN ULONG Flags,
IN PVOID BaseAddress,
IN ULONG RegionSize,
IN PVOID *UserAddressArray,
OUT PULONG EntriesInUserAddressArray,
OUT PULONG Granularity)
{
if (!EntriesInUserAddressArray || !Granularity)
{
return STATUS_ACCESS_VIOLATION;
}
if (!*EntriesInUserAddressArray || !RegionSize)
{
return STATUS_INVALID_PARAMETER;
}
if (!UserAddressArray)
{
return STATUS_ACCESS_VIOLATION;
}
/* HACK: Set granularity to PAGE_SIZE */
*Granularity = PAGE_SIZE;
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtResetWriteWatch(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN ULONG RegionSize)
{
if (!RegionSize)
{
return STATUS_INVALID_PARAMETER;
}
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -394,6 +394,7 @@
<file>pool.c</file>
<file>procsup.c</file>
<file>syspte.c</file>
<file>virtual.c</file>
</directory>
<file>anonmem.c</file>
<file>balance.c</file>