https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c48580135df5ef86732546126830a1ab98f71b29

commit c48580135df5ef86732546126830a1ab98f71b29
Author:     Jérôme Gardou <[email protected]>
AuthorDate: Tue Apr 6 12:58:02 2021 +0200
Commit:     Jérôme Gardou <[email protected]>
CommitDate: Thu Apr 8 15:40:37 2021 +0200

    [NTOS:MM] Fix a bit page fault handler with regard to COW sections
---
 ntoskrnl/mm/section.c | 82 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 48 insertions(+), 34 deletions(-)

diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c
index 0b6b8e80416..e273c3ac10b 100644
--- a/ntoskrnl/mm/section.c
+++ b/ntoskrnl/mm/section.c
@@ -1697,8 +1697,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
      * Check if this page needs to be mapped COW
      */
     if ((Segment->WriteCopy) &&
-            (Region->Protect == PAGE_READWRITE ||
-             Region->Protect == PAGE_EXECUTE_READWRITE))
+        (Region->Protect == PAGE_READWRITE || Region->Protect == 
PAGE_EXECUTE_READWRITE))
     {
         Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : 
PAGE_EXECUTE_READ;
     }
@@ -1883,32 +1882,70 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
     PMM_SECTION_SEGMENT Segment;
     PFN_NUMBER OldPage;
     PFN_NUMBER NewPage;
-    NTSTATUS Status;
     PVOID PAddress;
     LARGE_INTEGER Offset;
     PMM_REGION Region;
     ULONG_PTR Entry;
     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+    BOOLEAN Cow = FALSE;
+    ULONG NewProtect;
 
     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.  */
-    Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, Address, 
Locked);
-    if (!NT_SUCCESS(Status))
+    if (!MmIsPagePresent(Process, Address))
     {
-        /* This is invalid access ! */
-        return Status;
+        NTSTATUS Status = MmNotPresentFaultSectionView(AddressSpace, 
MemoryArea, Address, Locked);
+        if (!NT_SUCCESS(Status))
+        {
+            /* This is invalid access ! */
+            return Status;
+        }
     }
 
     /*
      * 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);
         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
      */
@@ -1916,23 +1953,6 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
     Offset.QuadPart = (ULONG_PTR)PAddress - MA_GetStartingAddress(MemoryArea)
                       + 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. */
     MmLockSectionSegment(Segment);
     Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
@@ -1947,15 +1967,14 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
     {
         MmUnlockSectionSegment(Segment);
         /* This is a private page. We must only change the page protection. */
-        MmSetPageProtect(Process, PAddress, Region->Protect);
+        MmSetPageProtect(Process, PAddress, NewProtect);
         return STATUS_SUCCESS;
     }
 
     /*
      * Allocate a page
      */
-    Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage)))
     {
         KeBugCheck(MEMORY_MANAGEMENT);
     }
@@ -1978,15 +1997,10 @@ MmAccessFaultSectionView(PMMSUPPORT AddressSpace,
     /*
      * Set the PTE to point to the new page
      */
-    Status = MmCreateVirtualMapping(Process,
-                                    PAddress,
-                                    Region->Protect,
-                                    NewPage);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(MmCreateVirtualMapping(Process, PAddress, NewProtect, 
NewPage)))
     {
         DPRINT1("MmCreateVirtualMapping failed, unable to create virtual 
mapping, not out of memory\n");
         KeBugCheck(MEMORY_MANAGEMENT);
-        return Status;
     }
 
     if (Process)

Reply via email to