[NTOS]: High-level interface fixes to NtAllocateVirtualMemory/NtFreeVirtualMemory:

- Validate MEM_LARGE_PAGES, MEM_PHYSICAL flags. Check for permission to use MEM_LARGE_PAGES.
        - Validate protection mask.
        - Validate MEM_RELEASE and MEM_DECOMMIT.
        - Perform correct SEH in NtFreeVirtualMemory.
        - Protect against overflows past VAD/User address ranegs.
        - Only reference the process by handle if this isn't already the current process.
        - If this isn't the current process, attach to it during the duration of the VM operation.

svn path=/trunk/; revision=49004
This commit is contained in:
Sir Richard 2010-10-05 20:00:32 +00:00
parent 58ed576929
commit 44e3333652

View file

@ -43,6 +43,9 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
#define MODULE_INVOLVED_IN_ARM3
#include "ARM3/miarm.h"
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
NTSTATUS NTSTATUS
@ -663,31 +666,14 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
/* /*
* @implemented * @implemented
*/ */
NTSTATUS NTAPI NTSTATUS
NtAllocateVirtualMemory(IN HANDLE ProcessHandle, NTAPI
NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
IN OUT PVOID* UBaseAddress, IN OUT PVOID* UBaseAddress,
IN ULONG_PTR ZeroBits, IN ULONG_PTR ZeroBits,
IN OUT PSIZE_T URegionSize, IN OUT PSIZE_T URegionSize,
IN ULONG AllocationType, IN ULONG AllocationType,
IN ULONG Protect) 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.
* RETURNS: Status
*/
{ {
PEPROCESS Process; PEPROCESS Process;
MEMORY_AREA* MemoryArea; MEMORY_AREA* MemoryArea;
@ -699,132 +685,188 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
ULONG RegionSize; ULONG RegionSize;
PVOID PBaseAddress; PVOID PBaseAddress;
ULONG PRegionSize; ULONG PRegionSize;
ULONG MemProtection;
PHYSICAL_ADDRESS BoundaryAddressMultiple; PHYSICAL_ADDRESS BoundaryAddressMultiple;
KPROCESSOR_MODE PreviousMode; PEPROCESS CurrentProcess = PsGetCurrentProcess();
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
KAPC_STATE ApcState;
ULONG ProtectionMask;
BOOLEAN Attached = FALSE;
BoundaryAddressMultiple.QuadPart = 0;
PAGED_CODE();
PAGED_CODE(); /* Check for valid Zero bits */
if (ZeroBits > 21)
{
DPRINT1("Too many zero bits\n");
return STATUS_INVALID_PARAMETER_3;
}
DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, " /* Check for valid Allocation Types */
"ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n", if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL |
*UBaseAddress,ZeroBits,*URegionSize,AllocationType, MEM_TOP_DOWN | MEM_WRITE_WATCH)))
Protect); {
DPRINT1("Invalid Allocation Type\n");
return STATUS_INVALID_PARAMETER_5;
}
/* Check for valid protection flags */ /* Check for at least one of these Allocation Types to be set */
MemProtection = Protect & ~(PAGE_GUARD|PAGE_NOCACHE); if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)))
if (MemProtection != PAGE_NOACCESS && {
MemProtection != PAGE_READONLY && DPRINT1("No memory allocation base type\n");
MemProtection != PAGE_READWRITE && return STATUS_INVALID_PARAMETER_5;
MemProtection != PAGE_WRITECOPY && }
MemProtection != PAGE_EXECUTE &&
MemProtection != PAGE_EXECUTE_READ &&
MemProtection != PAGE_EXECUTE_READWRITE &&
MemProtection != PAGE_EXECUTE_WRITECOPY)
{
DPRINT1("Invalid page protection\n");
return STATUS_INVALID_PAGE_PROTECTION;
}
/* Check for valid Zero bits */ /* MEM_RESET is an exclusive flag, make sure that is valid too */
if (ZeroBits > 21) if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET))
{ {
DPRINT1("Too many zero bits\n"); DPRINT1("Invalid use of MEM_RESET\n");
return STATUS_INVALID_PARAMETER_3; return STATUS_INVALID_PARAMETER_5;
} }
/* Check for valid Allocation Types */ /* Check if large pages are being used */
if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_PHYSICAL | if (AllocationType & MEM_LARGE_PAGES)
MEM_TOP_DOWN | MEM_WRITE_WATCH))) {
{ /* Large page allocations MUST be committed */
DPRINT1("Invalid Allocation Type\n"); if (!(AllocationType & MEM_COMMIT))
return STATUS_INVALID_PARAMETER_5; {
} DPRINT1("Must supply MEM_COMMIT with MEM_LARGE_PAGES\n");
return STATUS_INVALID_PARAMETER_5;
}
/* Check for at least one of these Allocation Types to be set */ /* These flags are not allowed with large page allocations */
if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET))) if (AllocationType & (MEM_PHYSICAL | MEM_RESET | MEM_WRITE_WATCH))
{ {
DPRINT1("No memory allocation base type\n"); DPRINT1("Using illegal flags with MEM_LARGE_PAGES\n");
return STATUS_INVALID_PARAMETER_5; return STATUS_INVALID_PARAMETER_5;
} }
}
/* MEM_RESET is an exclusive flag, make sure that is valid too */ /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET)) if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE))
{ {
DPRINT1("Invalid use of MEM_RESET\n"); DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
return STATUS_INVALID_PARAMETER_5; return STATUS_INVALID_PARAMETER_5;
} }
/* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */ /* MEM_PHYSICAL can only be used if MEM_RESERVE is also used */
if ((AllocationType & MEM_WRITE_WATCH) && !(AllocationType & MEM_RESERVE)) if ((AllocationType & MEM_PHYSICAL) && !(AllocationType & MEM_RESERVE))
{ {
DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n"); DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
return STATUS_INVALID_PARAMETER_5; return STATUS_INVALID_PARAMETER_5;
} }
/* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */ /* Check for valid MEM_PHYSICAL usage */
if (AllocationType & MEM_PHYSICAL) if (AllocationType & MEM_PHYSICAL)
{ {
/* First check for MEM_RESERVE exclusivity */ /* Only these flags are allowed with MEM_PHYSIAL */
if (AllocationType != (MEM_RESERVE | MEM_PHYSICAL)) if (AllocationType & ~(MEM_RESERVE | MEM_TOP_DOWN | MEM_PHYSICAL))
{ {
DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or" DPRINT1("Using illegal flags with MEM_PHYSICAL\n");
"MEM_RESERVE was not present at all\n"); return STATUS_INVALID_PARAMETER_5;
return STATUS_INVALID_PARAMETER_5; }
}
/* Then make sure PAGE_READWRITE is used */ /* Then make sure PAGE_READWRITE is used */
if (Protect != PAGE_READWRITE) if (Protect != PAGE_READWRITE)
{ {
DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n"); DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
return STATUS_INVALID_PAGE_PROTECTION; return STATUS_INVALID_PARAMETER_6;
} }
} }
PreviousMode = KeGetPreviousMode(); /* Calculate the protection mask and make sure it's valid */
ProtectionMask = MiMakeProtectionMask(Protect);
if (ProtectionMask == MM_INVALID_PROTECTION)
{
DPRINT1("Invalid protection mask\n");
return STATUS_INVALID_PAGE_PROTECTION;
}
_SEH2_TRY /* Enter SEH */
{ _SEH2_TRY
if (PreviousMode != KernelMode) {
{ /* Check for user-mode parameters */
ProbeForWritePointer(UBaseAddress); if (PreviousMode != KernelMode)
ProbeForWriteUlong(URegionSize); {
} /* Make sure they are writable */
PBaseAddress = *UBaseAddress; ProbeForWritePointer(UBaseAddress);
PRegionSize = *URegionSize; ProbeForWriteUlong(URegionSize);
} }
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
BoundaryAddressMultiple.QuadPart = 0; /* Capture their values */
PBaseAddress = *UBaseAddress;
PRegionSize = *URegionSize;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Make sure the allocation isn't past the VAD area */
if (PBaseAddress >= MM_HIGHEST_VAD_ADDRESS)
{
DPRINT1("Virtual allocation base above User Space\n");
return STATUS_INVALID_PARAMETER_2;
}
/* Make sure the allocation wouldn't overflow past the VAD area */
if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)PBaseAddress) < PRegionSize)
{
DPRINT1("Region size would overflow into kernel-memory\n");
return STATUS_INVALID_PARAMETER_4;
}
/* Make sure there's a size specified */
if (!PRegionSize)
{
DPRINT1("Region size is invalid (zero)\n");
return STATUS_INVALID_PARAMETER_4;
}
/* Check if this is for the current process */
if (ProcessHandle == NtCurrentProcess())
{
/* We already have the current process, no need to go through Ob */
Process = CurrentProcess;
}
else
{
/* Reference the handle for correct permissions */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Check if not running in the current process */
if (CurrentProcess != Process)
{
/* Attach to it */
KeStackAttachProcess(&Process->Pcb, &ApcState);
Attached = TRUE;
}
}
/* Check for large page allocations */
if (AllocationType & MEM_LARGE_PAGES)
{
/* The lock memory privilege is required */
if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
{
/* Fail without it */
DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return STATUS_PRIVILEGE_NOT_HELD;
}
}
BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress); BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) - RegionSize = PAGE_ROUND_UP((ULONG_PTR)PBaseAddress + PRegionSize) -
PAGE_ROUND_DOWN(PBaseAddress); PAGE_ROUND_DOWN(PBaseAddress);
/*
* We've captured and calculated the data, now do more checks
* Yes, MmCreateMemoryArea does similar checks, but they don't return
* the right status codes that a caller of this routine would expect.
*/
if ((ULONG_PTR)BaseAddress >= USER_SHARED_DATA)
{
DPRINT1("Virtual allocation base above User Space\n");
return STATUS_INVALID_PARAMETER_2;
}
if (!RegionSize)
{
DPRINT1("Region size is invalid (zero)\n");
return STATUS_INVALID_PARAMETER_4;
}
if ((USER_SHARED_DATA - (ULONG_PTR)BaseAddress) < RegionSize)
{
DPRINT1("Region size would overflow into kernel-memory\n");
return STATUS_INVALID_PARAMETER_4;
}
/* /*
* Copy on Write is reserved for system use. This case is a certain failure * Copy on Write is reserved for system use. This case is a certain failure
@ -837,19 +879,6 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
return STATUS_INVALID_PAGE_PROTECTION; return STATUS_INVALID_PAGE_PROTECTION;
} }
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
PreviousMode,
(PVOID*)(&Process),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
return(Status);
}
Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE; Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
DPRINT("Type %x\n", Type); DPRINT("Type %x\n", Type);
@ -871,8 +900,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
(ULONG_PTR)BaseAddress + RegionSize, MemoryArea->EndingAddress); (ULONG_PTR)BaseAddress + RegionSize, MemoryArea->EndingAddress);
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return STATUS_MEMORY_NOT_ALLOCATED; return STATUS_MEMORY_NOT_ALLOCATED;
} }
@ -888,7 +917,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
} }
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
/* MEM_RESET does not modify any attributes of region */ /* MEM_RESET does not modify any attributes of region */
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -904,7 +934,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
BaseAddress, RegionSize, BaseAddress, RegionSize,
Type, Protect, MmModifyAttributes); Type, Protect, MmModifyAttributes);
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status); DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
/* Give the caller rounded BaseAddress and area length */ /* Give the caller rounded BaseAddress and area length */
@ -935,7 +966,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
} }
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status); DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
/* Give the caller rounded BaseAddress and area length */ /* Give the caller rounded BaseAddress and area length */
@ -951,7 +983,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
else else
{ {
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return(STATUS_UNSUCCESSFUL); return(STATUS_UNSUCCESSFUL);
} }
} }
@ -969,7 +1002,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
DPRINT("NtAllocateVirtualMemory() = %x\n",Status); DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
return(Status); return(Status);
} }
@ -987,12 +1021,14 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
MmReserveSwapPages(nPages); MmReserveSwapPages(nPages);
} }
MmUnlockAddressSpace(AddressSpace);
if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
*UBaseAddress = BaseAddress; *UBaseAddress = BaseAddress;
*URegionSize = MemoryAreaLength; *URegionSize = MemoryAreaLength;
DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize); DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -1261,8 +1297,8 @@ MmFreeVirtualMemory(PEPROCESS Process,
*/ */
NTSTATUS NTAPI NTSTATUS NTAPI
NtFreeVirtualMemory(IN HANDLE ProcessHandle, NtFreeVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID* PBaseAddress, IN PVOID* UBaseAddress,
IN PSIZE_T PRegionSize, IN PSIZE_T URegionSize,
IN ULONG FreeType) IN ULONG FreeType)
/* /*
* FUNCTION: Frees a range of virtual memory * FUNCTION: Frees a range of virtual memory
@ -1281,52 +1317,95 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
NTSTATUS Status; NTSTATUS Status;
PEPROCESS Process; PEPROCESS Process;
PMMSUPPORT AddressSpace; PMMSUPPORT AddressSpace;
PVOID BaseAddress; PVOID BaseAddress, PBaseAddress;
ULONG RegionSize; ULONG RegionSize, PRegionSize;
PEPROCESS CurrentProcess = PsGetCurrentProcess();
PAGED_CODE(); KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
KAPC_STATE ApcState;
DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, " BOOLEAN Attached = FALSE;
"*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress, PAGED_CODE();
*PRegionSize,FreeType);
/* Only two flags are supported */
if (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT))) if (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT)))
{ {
DPRINT1("Invalid FreeType\n"); DPRINT1("Invalid FreeType\n");
return STATUS_INVALID_PARAMETER_4; return STATUS_INVALID_PARAMETER_4;
} }
if (ExGetPreviousMode() != KernelMode) /* Check if no flag was used, or if both flags were used */
if (!((FreeType & (MEM_DECOMMIT | MEM_RELEASE))) ||
((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == (MEM_DECOMMIT | MEM_RELEASE)))
{ {
_SEH2_TRY DPRINT1("Invalid FreeType combination\n");
{ return STATUS_INVALID_PARAMETER_4;
/* Probe user pointers */
ProbeForWriteSize_t(PRegionSize);
ProbeForWritePointer(PBaseAddress);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
} }
BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress)); /* Enter SEH */
RegionSize = PAGE_ROUND_UP((ULONG_PTR)(*PBaseAddress) + (*PRegionSize)) - _SEH2_TRY
PAGE_ROUND_DOWN((*PBaseAddress)); {
/* Check for user-mode parameters */
if (PreviousMode != KernelMode)
{
/* Make sure they are writable */
ProbeForWritePointer(UBaseAddress);
ProbeForWriteUlong(URegionSize);
}
Status = ObReferenceObjectByHandle(ProcessHandle, /* Capture their values */
PROCESS_VM_OPERATION, PBaseAddress = *UBaseAddress;
PsProcessType, PRegionSize = *URegionSize;
UserMode, }
(PVOID*)(&Process), _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
NULL); {
if (!NT_SUCCESS(Status)) /* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
/* Make sure the allocation isn't past the user area */
if (PBaseAddress >= MM_HIGHEST_USER_ADDRESS)
{
DPRINT1("Virtual free base above User Space\n");
return STATUS_INVALID_PARAMETER_2;
}
/* Make sure the allocation wouldn't overflow past the user area */
if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)PBaseAddress) < PRegionSize)
{ {
return(Status); DPRINT1("Region size would overflow into kernel-memory\n");
return STATUS_INVALID_PARAMETER_3;
} }
/* Check if this is for the current process */
if (ProcessHandle == NtCurrentProcess())
{
/* We already have the current process, no need to go through Ob */
Process = CurrentProcess;
}
else
{
/* Reference the handle for correct permissions */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Check if not running in the current process */
if (CurrentProcess != Process)
{
/* Attach to it */
KeStackAttachProcess(&Process->Pcb, &ApcState);
Attached = TRUE;
}
}
BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
PAGE_ROUND_DOWN((PBaseAddress));
AddressSpace = &Process->Vm; AddressSpace = &Process->Vm;
MmLockAddressSpace(AddressSpace); MmLockAddressSpace(AddressSpace);
@ -1372,7 +1451,8 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
unlock_deref_and_return: unlock_deref_and_return:
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process); if (Attached) KeUnstackDetachProcess(&ApcState);
if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
return(Status); return(Status);
} }