[NTOS]: Allocate the PEB at a pseudo-random address just like Windows XP SP2 and later, to prevent certain kinds of exploits.

[NTOS]: Allocate PEB and TEB using VADs! The user-mode fault handler seems to work fine, and I could find no regressions. This is the beginning of the end for MAREAs for VM allocations (they will remain for sections).

svn path=/trunk/; revision=48194
This commit is contained in:
Sir Richard 2010-07-22 19:08:45 +00:00
parent 92d6d7210c
commit 128fd3ca92
2 changed files with 114 additions and 85 deletions

View file

@ -18,11 +18,6 @@
extern MM_SYSTEMSIZE MmSystemSize;
PVOID
NTAPI
MiCreatePebOrTeb(PEPROCESS Process,
PVOID BaseAddress);
/* PRIVATE FUNCTIONS **********************************************************/
VOID
@ -48,6 +43,116 @@ MiRosTakeOverPebTebRanges(IN PEPROCESS Process)
ASSERT(NT_SUCCESS(Status));
}
NTSTATUS
NTAPI
MiCreatePebOrTeb(IN PEPROCESS Process,
IN ULONG Size,
OUT PULONG_PTR Base)
{
PETHREAD Thread = PsGetCurrentThread();
PMMVAD_LONG Vad;
NTSTATUS Status;
ULONG RandomCoeff;
ULONG_PTR StartAddress, EndAddress;
LARGE_INTEGER CurrentTime;
/* Allocate a VAD */
Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
if (!Vad) return STATUS_NO_MEMORY;
/* Setup the primary flags with the size, and make it commited, private, RW */
Vad->u.LongFlags = 0;
Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size);
Vad->u.VadFlags.MemCommit = TRUE;
Vad->u.VadFlags.PrivateMemory = TRUE;
Vad->u.VadFlags.Protection = MM_READWRITE;
Vad->u.VadFlags.NoChange = TRUE;
/* Setup the secondary flags to make it a secured, writable, long VAD */
Vad->u2.LongFlags2 = 0;
Vad->u2.VadFlags2.OneSecured = TRUE;
Vad->u2.VadFlags2.LongVad = TRUE;
Vad->u2.VadFlags2.ReadOnly = FALSE;
/* Lock the process address space */
KeAcquireGuardedMutex(&Process->AddressCreationLock);
/* Check if this is a PEB creation */
if (Size == sizeof(PEB))
{
/* Start at the highest valid address */
StartAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
/* Select the random coefficient */
KeQueryTickCount(&CurrentTime);
CurrentTime.LowPart &= ((64 * _1KB) >> PAGE_SHIFT) - 1;
if (CurrentTime.LowPart <= 1) CurrentTime.LowPart = 2;
RandomCoeff = CurrentTime.LowPart << PAGE_SHIFT;
/* Select the highest valid address minus the random coefficient */
StartAddress -= RandomCoeff;
EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
/* See if this VA range can be obtained */
if (!MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
EndAddress >> PAGE_SHIFT,
&Process->VadRoot))
{
/* No conflict, use this address */
*Base = StartAddress;
goto AfterFound;
}
}
/* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
Status = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
(ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
PAGE_SIZE,
&Process->VadRoot,
Base);
ASSERT(NT_SUCCESS(Status));
AfterFound:
/* Validate that it came from the VAD ranges */
ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
/* Build the rest of the VAD now */
Vad->StartingVpn = (*Base) >> PAGE_SHIFT;
Vad->EndingVpn = ((*Base) + Size - 1) >> PAGE_SHIFT;
Vad->u3.Secured.StartVpn = *Base;
Vad->u3.Secured.EndVpn = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
/* FIXME: Should setup VAD bitmap */
Status = STATUS_SUCCESS;
/* Pretend as if we own the working set */
MiLockProcessWorkingSet(Process, Thread);
/* Insert the VAD */
ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
Process->VadRoot.NodeHint = Vad;
MiInsertNode((PVOID)Vad, &Process->VadRoot);
/* Release the working set */
MiUnlockProcessWorkingSet(Process, Thread);
/* Release the address space lock */
KeReleaseGuardedMutex(&Process->AddressCreationLock);
/* Return the status */
DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
return Status;
}
VOID
NTAPI
MmDeleteTeb(IN PEPROCESS Process,
IN PTEB Teb)
{
/* Oops J */
DPRINT("Leaking 4KB at thread exit, this will be fixed later\n");
}
VOID
NTAPI
MmDeleteKernelStack(IN PVOID StackBase,
@ -415,9 +520,8 @@ MmCreatePeb(IN PEPROCESS Process,
//
// Allocate the PEB
//
Peb = MiCreatePebOrTeb(Process,
(PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
if (!Peb) return STATUS_INSUFFICIENT_RESOURCES;
Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
ASSERT(NT_SUCCESS(Status));
//
// Map NLS Tables
@ -651,9 +755,8 @@ MmCreateTeb(IN PEPROCESS Process,
//
// Allocate the TEB
//
Teb = MiCreatePebOrTeb(Process,
(PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
if (!Teb) return STATUS_INSUFFICIENT_RESOURCES;
Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
ASSERT(NT_SUCCESS(Status));
//
// Use SEH in case we can't load the TEB

View file

@ -17,80 +17,6 @@ VOID NTAPI MiRosTakeOverPebTebRanges(IN PEPROCESS Process);
/* FUNCTIONS *****************************************************************/
PVOID
NTAPI
MiCreatePebOrTeb(PEPROCESS Process,
PVOID BaseAddress)
{
NTSTATUS Status;
PMMSUPPORT ProcessAddressSpace = &Process->Vm;
PMEMORY_AREA MemoryArea;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
PVOID AllocatedBase = BaseAddress;
BoundaryAddressMultiple.QuadPart = 0;
/* Acquire the Lock */
MmLockAddressSpace(ProcessAddressSpace);
/*
* Create a Peb or Teb.
* Loop until it works, decreasing by PAGE_SIZE each time. The logic here
* is that a PEB allocation should never fail since the address is free,
* while TEB allocation can fail, and we should simply try the address
* below. Is there a nicer way of doing this automagically? (ie: findning)
* a gap region? -- Alex
*/
do {
DPRINT("Trying to allocate: %x\n", AllocatedBase);
Status = MmCreateMemoryArea(ProcessAddressSpace,
MEMORY_AREA_PEB_OR_TEB,
&AllocatedBase,
PAGE_SIZE,
PAGE_READWRITE,
&MemoryArea,
TRUE,
0,
BoundaryAddressMultiple);
AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE);
} while (Status != STATUS_SUCCESS);
/* Initialize the Region */
MmInitializeRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
PAGE_SIZE,
MEM_COMMIT,
PAGE_READWRITE);
/* Reserve the pages */
MmReserveSwapPages(PAGE_SIZE);
/* Unlock Address Space */
DPRINT("Returning\n");
MmUnlockAddressSpace(ProcessAddressSpace);
return RVA(AllocatedBase, PAGE_SIZE);
}
VOID
NTAPI
MmDeleteTeb(PEPROCESS Process,
PTEB Teb)
{
PMMSUPPORT ProcessAddressSpace = &Process->Vm;
PMEMORY_AREA MemoryArea;
/* Lock the Address Space */
MmLockAddressSpace(ProcessAddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(ProcessAddressSpace, (PVOID)Teb);
if (MemoryArea)
{
/* Delete the Teb */
MmFreeVirtualMemory(Process, MemoryArea);
}
/* Unlock the Address Space */
MmUnlockAddressSpace(ProcessAddressSpace);
}
NTSTATUS
NTAPI
MmInitializeHandBuiltProcess2(IN PEPROCESS Process)