[NTOS:MM] Fix a bit page fault handler with regard to COW sections

This commit is contained in:
Jérôme Gardou 2021-04-06 12:58:02 +02:00 committed by Jérôme Gardou
parent a34d9bcfb6
commit c48580135d

View file

@ -1697,8 +1697,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
* Check if this page needs to be mapped COW * Check if this page needs to be mapped COW
*/ */
if ((Segment->WriteCopy) && if ((Segment->WriteCopy) &&
(Region->Protect == PAGE_READWRITE || (Region->Protect == PAGE_READWRITE || Region->Protect == PAGE_EXECUTE_READWRITE))
Region->Protect == PAGE_EXECUTE_READWRITE))
{ {
Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ; Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
} }
@ -1883,32 +1882,70 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
PMM_SECTION_SEGMENT Segment; PMM_SECTION_SEGMENT Segment;
PFN_NUMBER OldPage; PFN_NUMBER OldPage;
PFN_NUMBER NewPage; PFN_NUMBER NewPage;
NTSTATUS Status;
PVOID PAddress; PVOID PAddress;
LARGE_INTEGER Offset; LARGE_INTEGER Offset;
PMM_REGION Region; PMM_REGION Region;
ULONG_PTR Entry; ULONG_PTR Entry;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
BOOLEAN Cow = FALSE;
ULONG NewProtect;
DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address); DPRINT("MmAccessFaultSectionView(%p, %p, %p)\n", AddressSpace, MemoryArea, Address);
/* Get the region for this address */
Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->SectionData.RegionListHead,
Address, NULL);
ASSERT(Region != NULL);
if (!(Region->Protect & PAGE_IS_WRITABLE))
return STATUS_ACCESS_VIOLATION;
/* Make sure we have a page mapping for this address. */ /* Make sure we have a page mapping for this address. */
Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, Locked); if (!MmIsPagePresent(Process, Address))
if (!NT_SUCCESS(Status))
{ {
/* This is invalid access ! */ NTSTATUS Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, Locked);
return Status; if (!NT_SUCCESS(Status))
{
/* This is invalid access ! */
return Status;
}
} }
/* /*
* Check if the page has already been set readwrite * Check if the page has already been set readwrite
*/ */
if (MmGetPageProtect(Process, Address) & PAGE_READWRITE) if (MmGetPageProtect(Process, Address) & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE))
{ {
DPRINT("Address 0x%p\n", Address); DPRINT("Address 0x%p\n", Address);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* Check if we are doing Copy-On-Write */
Segment = MemoryArea->SectionData.Segment;
Cow = Segment->WriteCopy || (Region->Protect & PAGE_IS_WRITECOPY);
if (!Cow)
{
/* Simply update page protection and we're done */
MmSetPageProtect(Process, Address, Region->Protect);
return STATUS_SUCCESS;
}
/* Calculate the new protection & check if we should update the region */
NewProtect = Region->Protect;
if (NewProtect & PAGE_IS_WRITECOPY)
{
NewProtect &= ~PAGE_IS_WRITECOPY;
if (Region->Protect & PAGE_IS_EXECUTABLE)
NewProtect |= PAGE_EXECUTE_READWRITE;
else
NewProtect |= PAGE_READWRITE;
MmAlterRegion(AddressSpace, (PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->SectionData.RegionListHead,
Address, PAGE_SIZE, Region->Type, NewProtect,
MmAlterViewAttributes);
}
/* /*
* Find the offset of the page * Find the offset of the page
*/ */
@ -1916,23 +1953,6 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea) Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
+ MemoryArea->SectionData.ViewOffset; + MemoryArea->SectionData.ViewOffset;
Segment = MemoryArea->SectionData.Segment;
Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
&MemoryArea->SectionData.RegionListHead,
Address, NULL);
ASSERT(Region != NULL);
/*
* Check if we are doing COW
*/
if (!((Segment->WriteCopy) &&
(Region->Protect == PAGE_READWRITE ||
Region->Protect == PAGE_EXECUTE_READWRITE)))
{
DPRINT("Address 0x%p\n", Address);
return STATUS_ACCESS_VIOLATION;
}
/* Get the page mapping this section offset. */ /* Get the page mapping this section offset. */
MmLockSectionSegment(Segment); MmLockSectionSegment(Segment);
Entry = MmGetPageEntrySectionSegment(Segment, &Offset); Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
@ -1947,15 +1967,14 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
{ {
MmUnlockSectionSegment(Segment); MmUnlockSectionSegment(Segment);
/* This is a private page. We must only change the page protection. */ /* This is a private page. We must only change the page protection. */
MmSetPageProtect(Process, PAddress, Region->Protect); MmSetPageProtect(Process, PAddress, NewProtect);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* /*
* Allocate a page * Allocate a page
*/ */
Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage); if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage)))
if (!NT_SUCCESS(Status))
{ {
KeBugCheck(MEMORY_MANAGEMENT); KeBugCheck(MEMORY_MANAGEMENT);
} }
@ -1978,15 +1997,10 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
/* /*
* Set the PTE to point to the new page * Set the PTE to point to the new page
*/ */
Status = MmCreateVirtualMapping(Process, if (!NT_SUCCESS(MmCreateVirtualMapping(Process, PAddress, NewProtect, NewPage)))
PAddress,
Region->Protect,
NewPage);
if (!NT_SUCCESS(Status))
{ {
DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n"); DPRINT1("MmCreateVirtualMapping failed, unable to create virtual mapping, not out of memory\n");
KeBugCheck(MEMORY_MANAGEMENT); KeBugCheck(MEMORY_MANAGEMENT);
return Status;
} }
if (Process) if (Process)