From 128fd3ca9284e4f4fe022cf12f3fe641f4b00e86 Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Thu, 22 Jul 2010 19:08:45 +0000 Subject: [PATCH] [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 --- reactos/ntoskrnl/mm/ARM3/procsup.c | 125 ++++++++++++++++++++++++++--- reactos/ntoskrnl/mm/procsup.c | 74 ----------------- 2 files changed, 114 insertions(+), 85 deletions(-) diff --git a/reactos/ntoskrnl/mm/ARM3/procsup.c b/reactos/ntoskrnl/mm/ARM3/procsup.c index d2ea798914d..75c25c681cc 100644 --- a/reactos/ntoskrnl/mm/ARM3/procsup.c +++ b/reactos/ntoskrnl/mm/ARM3/procsup.c @@ -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 diff --git a/reactos/ntoskrnl/mm/procsup.c b/reactos/ntoskrnl/mm/procsup.c index 1e5bd9afb2d..fce21f5bd6f 100644 --- a/reactos/ntoskrnl/mm/procsup.c +++ b/reactos/ntoskrnl/mm/procsup.c @@ -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)