From 158661ce3190e28b8816ea27ff0907d743d777bb Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sun, 25 May 2014 19:13:32 +0000 Subject: [PATCH] [NTOSKRNL] Implement prototype PTE support in MiGetPageProtection. Should hopefully fix crashes with OllyDbg. svn path=/trunk/; revision=63449 --- reactos/ntoskrnl/mm/ARM3/virtual.c | 146 +++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 37 deletions(-) diff --git a/reactos/ntoskrnl/mm/ARM3/virtual.c b/reactos/ntoskrnl/mm/ARM3/virtual.c index f82aedb9c9f..69017e7919d 100644 --- a/reactos/ntoskrnl/mm/ARM3/virtual.c +++ b/reactos/ntoskrnl/mm/ARM3/virtual.c @@ -1261,6 +1261,11 @@ MiGetPageProtection(IN PMMPTE PointerPte) { MMPTE TempPte; PMMPFN Pfn; + PEPROCESS CurrentProcess; + PETHREAD CurrentThread; + BOOLEAN WsSafe, WsShared; + ULONG Protect; + KIRQL OldIrql; PAGED_CODE(); /* Copy this PTE's contents */ @@ -1270,12 +1275,79 @@ MiGetPageProtection(IN PMMPTE PointerPte) ASSERT(TempPte.u.Long); /* Check for a special prototype format */ - if (TempPte.u.Soft.Valid == 0 && - TempPte.u.Soft.Prototype == 1) + if ((TempPte.u.Soft.Valid == 0) && + (TempPte.u.Soft.Prototype == 1)) { - /* Unsupported now */ - UNIMPLEMENTED; - ASSERT(FALSE); + /* Check if the prototype PTE is not yet pointing to a PTE */ + if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED) + { + /* The prototype PTE contains the protection */ + return MmProtectToValue[TempPte.u.Soft.Protection]; + } + + /* Get a pointer to the underlying shared PTE */ + PointerPte = MiProtoPteToPte(&TempPte); + + /* Since the PTE we want to read can be paged out at any time, we need + to release the working set lock first, so that it can be paged in */ + CurrentThread = PsGetCurrentThread(); + CurrentProcess = PsGetCurrentProcess(); + MiUnlockProcessWorkingSetForFault(CurrentProcess, + CurrentThread, + &WsSafe, + &WsShared); + + /* Now read the PTE value */ + TempPte = *PointerPte; + + /* Check if that one is invalid */ + if (!TempPte.u.Hard.Valid) + { + /* We get the protection directly from this PTE */ + Protect = MmProtectToValue[TempPte.u.Soft.Protection]; + } + else + { + /* The PTE is valid, so we might need to get the protection from + the PFN. Lock the PFN database */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* Check if the PDE is still valid */ + if (MiAddressToPte(PointerPte)->u.Hard.Valid == 0) + { + /* It's not, make it valid */ + MiMakeSystemAddressValidPfn(PointerPte, OldIrql); + } + + /* Now it's safe to read the PTE value again */ + TempPte = *PointerPte; + ASSERT(TempPte.u.Long != 0); + + /* Check again if the PTE is invalid */ + if (!TempPte.u.Hard.Valid) + { + /* The PTE is not valid, so we can use it's protection field */ + Protect = MmProtectToValue[TempPte.u.Soft.Protection]; + } + else + { + /* The PTE is valid, so we can find the protection in the + OriginalPte field of the PFN */ + Pfn = MI_PFN_ELEMENT(TempPte.u.Hard.PageFrameNumber); + Protect = MmProtectToValue[Pfn->OriginalPte.u.Soft.Protection]; + } + + /* Release the PFN database */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + } + + /* Lock the working set again */ + MiLockProcessWorkingSetForFault(CurrentProcess, + CurrentThread, + WsSafe, + WsShared); + + return Protect; } /* In the easy case of transition or demand zero PTE just return its protection */ @@ -4500,44 +4572,44 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle, { Status = STATUS_NO_MEMORY; goto FailPath; - } } - else + } + else + { + /* Make sure it doesn't conflict with an existing allocation */ + Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT, + EndingAddress >> PAGE_SHIFT, + &Process->VadRoot, + &Parent); + if (Result == TableFoundNode) { - /* Make sure it doesn't conflict with an existing allocation */ - Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT, - EndingAddress >> PAGE_SHIFT, - &Process->VadRoot, - &Parent); - if (Result == TableFoundNode) - { - // - // The address specified is in conflict! - // - Status = STATUS_CONFLICTING_ADDRESSES; - goto FailPath; - } + // + // The address specified is in conflict! + // + Status = STATUS_CONFLICTING_ADDRESSES; + goto FailPath; } + } - // - // Write out the VAD fields for this allocation - // - Vad->StartingVpn = StartingAddress >> PAGE_SHIFT; - Vad->EndingVpn = EndingAddress >> PAGE_SHIFT; + // + // Write out the VAD fields for this allocation + // + Vad->StartingVpn = StartingAddress >> PAGE_SHIFT; + Vad->EndingVpn = EndingAddress >> PAGE_SHIFT; - // - // FIXME: Should setup VAD bitmap - // - Status = STATUS_SUCCESS; + // + // FIXME: Should setup VAD bitmap + // + Status = STATUS_SUCCESS; - // - // Lock the working set and insert the VAD into the process VAD tree - // - MiLockProcessWorkingSetUnsafe(Process, CurrentThread); - Vad->ControlArea = NULL; // For Memory-Area hack - Process->VadRoot.NodeHint = Vad; - MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result); - MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread); + // + // Lock the working set and insert the VAD into the process VAD tree + // + MiLockProcessWorkingSetUnsafe(Process, CurrentThread); + Vad->ControlArea = NULL; // For Memory-Area hack + Process->VadRoot.NodeHint = Vad; + MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result); + MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread); // // Make sure the actual region size is at least as big as the -- 2.17.1