https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8ed15a49a7540a91afc07…
commit 8ed15a49a7540a91afc07d8eafe26a952b6d0ae6
Author: Jérôme Gardou <jerome.gardou(a)reactos.org>
AuthorDate: Wed Dec 30 09:43:55 2020 +0100
Commit: Jérôme Gardou <jerome.gardou(a)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))
{