[NTOS:MM] Rewrite arch-specifics of the legacy Mm

Properly handle PDE refcounting
Clean-up of the internal API
Enforce attaching to the process when modifying its memory layout, instead of
making circonvoluted mappings which always end up being broken.
This commit is contained in:
Jérôme Gardou 2021-03-22 09:52:11 +01:00 committed by Jérôme Gardou
parent b445005c70
commit 43378411fb
5 changed files with 474 additions and 572 deletions

View file

@ -1034,8 +1034,7 @@ MmCreateVirtualMapping(
struct _EPROCESS* Process,
PVOID Address,
ULONG flProtect,
PPFN_NUMBER Pages,
ULONG PageCount
PFN_NUMBER Page
);
NTSTATUS
@ -1044,8 +1043,7 @@ MmCreateVirtualMappingUnsafe(
struct _EPROCESS* Process,
PVOID Address,
ULONG flProtect,
PPFN_NUMBER Pages,
ULONG PageCount
PFN_NUMBER Page
);
ULONG
@ -1080,13 +1078,6 @@ VOID
NTAPI
MmInitGlobalKernelPageDirectory(VOID);
VOID
NTAPI
MmGetPageFileMapping(
struct _EPROCESS *Process,
PVOID Address,
SWAPENTRY* SwapEntry);
VOID
NTAPI
MmDeletePageFileMapping(
@ -1103,6 +1094,13 @@ MmCreatePageFileMapping(
SWAPENTRY SwapEntry
);
VOID
NTAPI
MmGetPageFileMapping(
PEPROCESS Process,
PVOID Address,
SWAPENTRY *SwapEntry);
BOOLEAN
NTAPI
MmIsPageSwapEntry(
@ -1110,13 +1108,6 @@ MmIsPageSwapEntry(
PVOID Address
);
VOID
NTAPI
MmSetDirtyPage(
struct _EPROCESS *Process,
PVOID Address
);
PFN_NUMBER
NTAPI
MmAllocPage(
@ -1156,6 +1147,12 @@ MmSetCleanPage(
PVOID Address
);
VOID
NTAPI
MmSetDirtyBit(PEPROCESS Process, PVOID Address, BOOLEAN Bit);
#define MmSetCleanPage(__P, __A) MmSetDirtyBit(__P, __A, FALSE)
#define MmSetDirtyPage(__P, __A) MmSetDirtyBit(__P, __A, TRUE)
VOID
NTAPI
MmDeletePageTable(
@ -1208,21 +1205,6 @@ MmDeleteVirtualMapping(
PPFN_NUMBER Page
);
BOOLEAN
NTAPI
MmIsDirtyPage(
struct _EPROCESS *Process,
PVOID Address
);
VOID
NTAPI
MmClearPageAccessedBit(PEPROCESS Process, PVOID Address);
BOOLEAN
NTAPI
MmIsPageAccessed(PEPROCESS Process, PVOID Address);
/* wset.c ********************************************************************/
NTSTATUS

File diff suppressed because it is too large Load diff

View file

@ -328,24 +328,6 @@ MmFreeMemoryArea(
FreePage(FreePageContext, MemoryArea, (PVOID)Address,
Page, SwapEntry, (BOOLEAN)Dirty);
}
#if (_MI_PAGING_LEVELS == 2)
/* Remove page table reference */
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
if ((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart))
{
ASSERT(AddressSpace != MmGetKernelAddressSpace());
if (MiQueryPageTableReferences((PVOID)Address) == 0)
{
/* No PTE relies on this PDE. Release it */
KIRQL OldIrql = MiAcquirePfnLock();
PMMPDE PointerPde = MiAddressToPde(Address);
ASSERT(PointerPde->u.Hard.Valid == 1);
MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL);
ASSERT(PointerPde->u.Hard.Valid == 0);
MiReleasePfnLock(OldIrql);
}
}
#endif
}
if (Process != NULL &&

View file

@ -102,18 +102,26 @@ GetEntry:
MmLockAddressSpace(AddressSpace);
if (MmGetPfnForProcess(Process, Address) != Page)
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
{
/* This changed in the short window where we didn't have any locks */
MmUnlockAddressSpace(AddressSpace);
ExReleaseRundownProtection(&Process->RundownProtect);
ObDereferenceObject(Process);
goto GetEntry;
}
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
/* Attach to it, if needed */
ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
if (Process != PsInitialSystemProcess)
KeAttachProcess(&Process->Pcb);
if (MmGetPfnForProcess(Process, Address) != Page)
{
/* This changed in the short window where we didn't have any locks */
if (Process != PsInitialSystemProcess)
KeDetachProcess();
MmUnlockAddressSpace(AddressSpace);
ExReleaseRundownProtection(&Process->RundownProtect);
ObDereferenceObject(Process);
@ -140,6 +148,8 @@ GetEntry:
{
/* The segment is being read or something. Give up */
MmUnlockSectionSegment(Segment);
if (Process != PsInitialSystemProcess)
KeDetachProcess();
MmUnlockAddressSpace(AddressSpace);
ExReleaseRundownProtection(&Process->RundownProtect);
ObDereferenceObject(Process);
@ -160,11 +170,6 @@ GetEntry:
/* This page is private to the process */
MmUnlockSectionSegment(Segment);
/* Attach to it, if needed */
ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
if (Process != PsInitialSystemProcess)
KeAttachProcess(&Process->Pcb);
/* Check if we should write it back to the page file */
SwapEntry = MmGetSavedSwapEntryPage(Page);
@ -179,7 +184,7 @@ GetEntry:
Address, NULL);
/* We can't, so let this page in the Process VM */
MmCreateVirtualMapping(Process, Address, Region->Protect, &Page, 1);
MmCreateVirtualMapping(Process, Address, Region->Protect, Page);
MmInsertRmap(Page, Process, Address);
MmSetDirtyPage(Process, Address);
@ -219,7 +224,7 @@ GetEntry:
MmFreeSwapPage(SwapEntry);
/* We can't, so let this page in the Process VM */
MmCreateVirtualMapping(Process, Address, Region->Protect, &Page, 1);
MmCreateVirtualMapping(Process, Address, Region->Protect, Page);
MmInsertRmap(Page, Process, Address);
MmSetDirtyPage(Process, Address);
@ -241,7 +246,6 @@ GetEntry:
}
/* We can finally let this page go */
MmUnlockAddressSpace(AddressSpace);
if (Process != PsInitialSystemProcess)
KeDetachProcess();
@ -262,6 +266,8 @@ GetEntry:
Released = MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Dirty, TRUE, NULL);
MmUnlockSectionSegment(Segment);
if (Process != PsInitialSystemProcess)
KeDetachProcess();
MmUnlockAddressSpace(AddressSpace);
ExReleaseRundownProtection(&Process->RundownProtect);

View file

@ -1636,8 +1636,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
&Page,
1);
Page);
if (!NT_SUCCESS(Status))
{
DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
@ -1679,8 +1678,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
Status = MmCreateVirtualMappingUnsafe(Process,
PAddress,
Region->Protect,
&Page,
1);
Page);
if (!NT_SUCCESS(Status))
{
DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
@ -1729,7 +1727,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SSE(Page << PAGE_SHIFT, 1));
MmUnlockSectionSegment(Segment);
Status = MmCreateVirtualMapping(Process, PAddress, Attributes, &Page, 1);
Status = MmCreateVirtualMapping(Process, PAddress, Attributes, Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
@ -1828,8 +1826,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
Status = MmCreateVirtualMapping(Process,
PAddress,
Attributes,
&Page,
1);
Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
@ -1857,8 +1854,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
Status = MmCreateVirtualMapping(Process,
PAddress,
Attributes,
&Page,
1);
Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("Unable to create virtual mapping\n");
@ -1985,8 +1981,7 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
&NewPage,
1);
NewPage);
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");