https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8ed15a49a7540a91afc07d...
commit 8ed15a49a7540a91afc07d8eafe26a952b6d0ae6 Author: Jérôme Gardou jerome.gardou@reactos.org AuthorDate: Wed Dec 30 09:43:55 2020 +0100 Commit: Jérôme Gardou jerome.gardou@reactos.org CommitDate: Wed Feb 3 09:41:23 2021 +0100
[NTOS:MM] Fix a race --- ntoskrnl/mm/freelist.c | 7 ++++++- ntoskrnl/mm/rmap.c | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/ntoskrnl/mm/freelist.c b/ntoskrnl/mm/freelist.c index 93d9bbd9f59..ba16362f546 100644 --- a/ntoskrnl/mm/freelist.c +++ b/ntoskrnl/mm/freelist.c @@ -436,7 +436,12 @@ MmGetRmapListHeadPage(PFN_NUMBER Pfn) /* Get the entry */ Pfn1 = MiGetPfnEntry(Pfn); ASSERT(Pfn1); - ASSERT_IS_ROS_PFN(Pfn1); + + if (!MI_IS_ROS_PFN(Pfn1)) + { + MiReleasePfnLock(oldIrql); + return NULL; + }
/* Get the list head */ ListHead = Pfn1->RmapListHead; diff --git a/ntoskrnl/mm/rmap.c b/ntoskrnl/mm/rmap.c index c000953cca1..785539ea58d 100644 --- a/ntoskrnl/mm/rmap.c +++ b/ntoskrnl/mm/rmap.c @@ -149,7 +149,32 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page)
/* Delete this virtual mapping in the process */ MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage); - ASSERT(MapPage == Page); + + /* There is a window betwwen the start of this function and now, + * where it's possible that the process changed its memory layout, + * because of copy-on-write, unmapping memory, or whatsoever. + * Just go away if that is the case */ + if (MapPage != Page) + { + PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), + &MemoryArea->SectionData.RegionListHead, + Address, NULL); + /* Restore the mapping */ + MmCreateVirtualMapping(Process, Address, Region->Protect, &MapPage, 1); + if (Dirty) + MmSetDirtyPage(Process, Address); + + MmUnlockSectionSegment(Segment); + MmUnlockAddressSpace(AddressSpace); + if (Address < MmSystemRangeStart) + { + ExReleaseRundownProtection(&Process->RundownProtect); + ObDereferenceObject(Process); + } + + /* We can still try to flush it to disk, though */ + goto WriteSegment; + }
if (Page != PFN_FROM_SSE(Entry)) {