mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[NTOS] Add some sanity checks when synchronizing PDEs
This commit is contained in:
parent
e5ebbc8afa
commit
75125228be
6 changed files with 113 additions and 75 deletions
|
@ -1288,13 +1288,13 @@ NTSTATUS
|
|||
NTAPI
|
||||
MmGetExecuteOptions(IN PULONG ExecuteOptions);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_Success_(return)
|
||||
BOOLEAN
|
||||
MmDeleteVirtualMapping(
|
||||
struct _EPROCESS *Process,
|
||||
PVOID Address,
|
||||
BOOLEAN* WasDirty,
|
||||
PPFN_NUMBER Page
|
||||
_In_opt_ PEPROCESS Process,
|
||||
_In_ PVOID Address,
|
||||
_Out_opt_ BOOLEAN* WasDirty,
|
||||
_Out_opt_ PPFN_NUMBER Page
|
||||
);
|
||||
|
||||
/* arch/procsup.c ************************************************************/
|
||||
|
|
|
@ -2428,21 +2428,29 @@ FORCEINLINE
|
|||
BOOLEAN
|
||||
MiSynchronizeSystemPde(PMMPDE PointerPde)
|
||||
{
|
||||
MMPDE SystemPde;
|
||||
ULONG Index;
|
||||
|
||||
/* Get the Index from the PDE */
|
||||
Index = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE);
|
||||
if (PointerPde->u.Hard.Valid != 0)
|
||||
{
|
||||
NT_ASSERT(PointerPde->u.Long == MmSystemPagePtes[Index].u.Long);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (MmSystemPagePtes[Index].u.Hard.Valid == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Copy the PDE from the double-mapped system page directory */
|
||||
SystemPde = MmSystemPagePtes[Index];
|
||||
*PointerPde = SystemPde;
|
||||
MI_WRITE_VALID_PDE(PointerPde, MmSystemPagePtes[Index]);
|
||||
|
||||
/* Make sure we re-read the PDE and PTE */
|
||||
KeMemoryBarrierWithoutFence();
|
||||
|
||||
/* Return, if we had success */
|
||||
return SystemPde.u.Hard.Valid != 0;
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -119,7 +119,12 @@ BOOLEAN
|
|||
MiIsPageTablePresent(PVOID Address)
|
||||
{
|
||||
#if _MI_PAGING_LEVELS == 2
|
||||
return MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] != 0;
|
||||
BOOLEAN Ret = MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] != 0;
|
||||
|
||||
/* Some sanity check while we're here */
|
||||
ASSERT(Ret == (MiAddressToPde(Address)->u.Hard.Valid != 0));
|
||||
|
||||
return Ret;
|
||||
#else
|
||||
PMMPDE PointerPde;
|
||||
PMMPPE PointerPpe;
|
||||
|
@ -217,16 +222,29 @@ MmGetPfnForProcess(PEPROCESS Process,
|
|||
return Page;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
|
||||
BOOLEAN* WasDirty, PPFN_NUMBER Page)
|
||||
/*
|
||||
* FUNCTION: Delete a virtual mapping
|
||||
/**
|
||||
* @brief Deletes the virtual mapping and optionally gives back the page & dirty bit.
|
||||
*
|
||||
* @param Process - The process this address belongs to, or NULL if system address.
|
||||
* @param Address - The address to unmap.
|
||||
* @param WasDirty - Optional param receiving the dirty bit of the PTE.
|
||||
* @param Page - Optional param receiving the page number previously mapped to this address.
|
||||
*
|
||||
* @return Whether there was actually a page mapped at the given address.
|
||||
*/
|
||||
_Success_(return)
|
||||
BOOLEAN
|
||||
MmDeleteVirtualMapping(
|
||||
_In_opt_ PEPROCESS Process,
|
||||
_In_ PVOID Address,
|
||||
_Out_opt_ BOOLEAN* WasDirty,
|
||||
_Out_opt_ PPFN_NUMBER Page)
|
||||
{
|
||||
PMMPTE PointerPte;
|
||||
MMPTE OldPte;
|
||||
BOOLEAN ValidPde;
|
||||
|
||||
OldPte.u.Long = 0;
|
||||
|
||||
DPRINT("MmDeleteVirtualMapping(%p, %p, %p, %p)\n", Process, Address, WasDirty, Page);
|
||||
|
||||
|
@ -244,18 +262,10 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
|
|||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
}
|
||||
#if (_MI_PAGING_LEVELS == 2)
|
||||
if (!MiSynchronizeSystemPde(MiAddressToPde(Address)))
|
||||
ValidPde = MiSynchronizeSystemPde(MiAddressToPde(Address));
|
||||
#else
|
||||
if (!MiIsPdeForAddressValid(Address))
|
||||
ValidPde = MiIsPdeForAddressValid(Address);
|
||||
#endif
|
||||
{
|
||||
/* There can't be a page if there is no PDE */
|
||||
if (WasDirty)
|
||||
*WasDirty = FALSE;
|
||||
if (Page)
|
||||
*Page = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -266,61 +276,56 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
|
|||
}
|
||||
|
||||
/* Only for current process !!! */
|
||||
ASSERT(Process = PsGetCurrentProcess());
|
||||
ASSERT(Process == PsGetCurrentProcess());
|
||||
MiLockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
|
||||
|
||||
/* No PDE --> No page */
|
||||
if (!MiIsPageTablePresent(Address))
|
||||
ValidPde = MiIsPageTablePresent(Address);
|
||||
if (ValidPde)
|
||||
{
|
||||
MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
|
||||
if (WasDirty)
|
||||
*WasDirty = 0;
|
||||
if (Page)
|
||||
*Page = 0;
|
||||
return;
|
||||
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
|
||||
}
|
||||
|
||||
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
|
||||
}
|
||||
|
||||
PointerPte = MiAddressToPte(Address);
|
||||
OldPte.u.Long = InterlockedExchangePte(PointerPte, 0);
|
||||
|
||||
if (OldPte.u.Long == 0)
|
||||
/* Get the PTE if we're having anything */
|
||||
if (ValidPde)
|
||||
{
|
||||
/* There was nothing here */
|
||||
if (Address < MmSystemRangeStart)
|
||||
MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
|
||||
if (WasDirty)
|
||||
*WasDirty = 0;
|
||||
if (Page)
|
||||
*Page = 0;
|
||||
return;
|
||||
}
|
||||
PointerPte = MiAddressToPte(Address);
|
||||
OldPte.u.Long = InterlockedExchangePte(PointerPte, 0);
|
||||
|
||||
/* It must have been present, or not a swap entry */
|
||||
ASSERT(OldPte.u.Hard.Valid || !FlagOn(OldPte.u.Long, 0x800));
|
||||
|
||||
if (OldPte.u.Hard.Valid)
|
||||
KeInvalidateTlbEntry(Address);
|
||||
|
||||
if (Address < MmSystemRangeStart)
|
||||
{
|
||||
/* Remove PDE reference */
|
||||
if (MiDecrementPageTableReferences(Address) == 0)
|
||||
if (OldPte.u.Long != 0)
|
||||
{
|
||||
KIRQL OldIrql = MiAcquirePfnLock();
|
||||
MiDeletePde(MiAddressToPde(Address), Process);
|
||||
MiReleasePfnLock(OldIrql);
|
||||
/* It must have been present, or not a swap entry */
|
||||
ASSERT(OldPte.u.Hard.Valid || !FlagOn(OldPte.u.Long, 0x800));
|
||||
if (WasDirty != NULL)
|
||||
{
|
||||
*WasDirty = !!OldPte.u.Hard.Dirty;
|
||||
}
|
||||
if (Page != NULL)
|
||||
{
|
||||
*Page = OldPte.u.Hard.PageFrameNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Process != NULL)
|
||||
{
|
||||
/* Remove PDE reference, if needed */
|
||||
if (OldPte.u.Long != 0)
|
||||
{
|
||||
if (MiDecrementPageTableReferences(Address) == 0)
|
||||
{
|
||||
KIRQL OldIrql = MiAcquirePfnLock();
|
||||
MiDeletePde(MiAddressToPde(Address), Process);
|
||||
MiReleasePfnLock(OldIrql);
|
||||
}
|
||||
}
|
||||
|
||||
MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
|
||||
}
|
||||
|
||||
if (WasDirty)
|
||||
*WasDirty = !!OldPte.u.Hard.Dirty;
|
||||
if (Page)
|
||||
*Page = OldPte.u.Hard.PageFrameNumber;
|
||||
return OldPte.u.Long != 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -631,7 +636,7 @@ MmCreateVirtualMappingUnsafe(PEPROCESS Process,
|
|||
}
|
||||
|
||||
/* Only for current process !!! */
|
||||
ASSERT(Process = PsGetCurrentProcess());
|
||||
ASSERT(Process == PsGetCurrentProcess());
|
||||
MiLockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
|
||||
|
||||
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
|
||||
|
|
|
@ -314,16 +314,19 @@ MmFreeMemoryArea(
|
|||
BOOLEAN Dirty = FALSE;
|
||||
SWAPENTRY SwapEntry = 0;
|
||||
PFN_NUMBER Page = 0;
|
||||
BOOLEAN DoFree;
|
||||
|
||||
if (MmIsPageSwapEntry(Process, (PVOID)Address))
|
||||
{
|
||||
MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
|
||||
/* We'll have to do some cleanup when we're on the page file */
|
||||
DoFree = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
MmDeleteVirtualMapping(Process, (PVOID)Address, &Dirty, &Page);
|
||||
DoFree = MmDeleteVirtualMapping(Process, (PVOID)Address, &Dirty, &Page);
|
||||
}
|
||||
if (FreePage != NULL)
|
||||
if (DoFree && (FreePage != NULL))
|
||||
{
|
||||
FreePage(FreePageContext, MemoryArea, (PVOID)Address,
|
||||
Page, SwapEntry, (BOOLEAN)Dirty);
|
||||
|
|
|
@ -135,6 +135,7 @@ GetEntry:
|
|||
PFN_NUMBER MapPage;
|
||||
LARGE_INTEGER Offset;
|
||||
BOOLEAN Released;
|
||||
BOOLEAN Unmapped;
|
||||
|
||||
Offset.QuadPart = MemoryArea->SectionData.ViewOffset +
|
||||
((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea));
|
||||
|
@ -158,10 +159,19 @@ GetEntry:
|
|||
|
||||
/* Delete this virtual mapping in the process */
|
||||
MmDeleteRmap(Page, Process, Address);
|
||||
MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage);
|
||||
|
||||
/* We checked this earlier */
|
||||
ASSERT(MapPage == Page);
|
||||
Unmapped = MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage);
|
||||
if (!Unmapped || (MapPage != Page))
|
||||
{
|
||||
/*
|
||||
* Something's corrupted, we got there because this process is
|
||||
* supposed to be mapping this page there.
|
||||
*/
|
||||
KeBugCheckEx(MEMORY_MANAGEMENT,
|
||||
(ULONG_PTR)Process,
|
||||
(ULONG_PTR)Address,
|
||||
(ULONG_PTR)__FILE__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
if (Page != PFN_FROM_SSE(Entry))
|
||||
{
|
||||
|
|
|
@ -1897,6 +1897,7 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
PMM_SECTION_SEGMENT Segment;
|
||||
PFN_NUMBER OldPage;
|
||||
PFN_NUMBER NewPage;
|
||||
PFN_NUMBER UnmappedPage;
|
||||
PVOID PAddress;
|
||||
LARGE_INTEGER Offset;
|
||||
PMM_REGION Region;
|
||||
|
@ -1904,6 +1905,7 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
BOOLEAN Cow = FALSE;
|
||||
ULONG NewProtect;
|
||||
BOOLEAN Unmapped;
|
||||
|
||||
DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
|
||||
|
||||
|
@ -2003,7 +2005,17 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
* Unshare the old page.
|
||||
*/
|
||||
DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
|
||||
MmDeleteVirtualMapping(Process, PAddress, NULL, NULL);
|
||||
Unmapped = MmDeleteVirtualMapping(Process, PAddress, NULL, &UnmappedPage);
|
||||
if (!Unmapped || (UnmappedPage != OldPage))
|
||||
{
|
||||
/* Uh , we had a page just before, but suddenly it changes. Someone corrupted us. */
|
||||
KeBugCheckEx(MEMORY_MANAGEMENT,
|
||||
(ULONG_PTR)Process,
|
||||
(ULONG_PTR)PAddress,
|
||||
(ULONG_PTR)__FILE__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
if (Process)
|
||||
MmDeleteRmap(OldPage, Process, PAddress);
|
||||
MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, FALSE, FALSE, NULL);
|
||||
|
|
Loading…
Reference in a new issue