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

commit 573d579873c2e989460500eef90e55c5939f0eda
Author:     Jérôme Gardou <[email protected]>
AuthorDate: Sat Apr 1 16:56:49 2023 +0200
Commit:     GitHub <[email protected]>
CommitDate: Sat Apr 1 23:56:49 2023 +0900

    [NTOSKRNL] Flush file to disk when deleting file mappings (#4302)
    
    CORE-17627
    When closing a file, fastfat zeroes it out from ValidDataLength up to the 
end of the file.
    The ValidDataLength field is updated when the file content is actually 
written to disk.
    There is currently a race between the file-close path and the page out 
path, leading to potential file corruptions when the zeroing happens after the 
memory has been flushed to disk.
    
    Fix this by actually flushing the file to disk when unmapping files, with 
file lock acquired. This way, the FS driver cannot zero out the tail of the 
file while we're actually flushing it to disk.
---
 ntoskrnl/mm/section.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c
index 2fba8e89908..9323a6da196 100644
--- a/ntoskrnl/mm/section.c
+++ b/ntoskrnl/mm/section.c
@@ -3578,7 +3578,7 @@ MiRosUnmapViewOfSection(IN PEPROCESS Process,
 
     ASSERT(Process);
 
-    AddressSpace = Process ? &Process->Vm : MmGetKernelAddressSpace();
+    AddressSpace = &Process->Vm;
 
     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
                  BaseAddress);
@@ -3645,6 +3645,15 @@ MiRosUnmapViewOfSection(IN PEPROCESS Process,
     }
     else
     {
+        PMM_SECTION_SEGMENT Segment = MemoryArea->SectionData.Segment;
+        PMMVAD Vad = &MemoryArea->VadNode;
+        PFILE_OBJECT FileObject;
+        SIZE_T ViewSize;
+        LARGE_INTEGER ViewOffset;
+        ViewOffset.QuadPart = MemoryArea->SectionData.ViewOffset;
+        
+        InterlockedIncrement64(Segment->ReferenceCount);
+
         Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
         if (!NT_SUCCESS(Status))
         {
@@ -3652,6 +3661,47 @@ MiRosUnmapViewOfSection(IN PEPROCESS Process,
                     BaseAddress, Process, Status);
             ASSERT(NT_SUCCESS(Status));
         }
+
+        if (FlagOn(*Segment->Flags, MM_PHYSICALMEMORY_SEGMENT))
+        {
+            /* Don't bother */
+            MmDereferenceSegment(Segment);
+            return STATUS_SUCCESS;
+        }
+        ASSERT(FlagOn(*Segment->Flags, MM_DATAFILE_SEGMENT));
+
+        FileObject = Segment->FileObject;
+        FsRtlAcquireFileExclusive(FileObject);
+
+        /* Don't bother for auto-delete closed file. */
+        if (FlagOn(FileObject->Flags, FO_DELETE_ON_CLOSE) && 
FlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
+        {
+            FsRtlReleaseFile(FileObject);
+            MmDereferenceSegment(Segment);
+            return STATUS_SUCCESS;
+        }
+
+        /*
+         * Flush only when last mapping is deleted.
+         * FIXME: Why Vad->ControlArea == NULL?
+         */
+        if (Vad->ControlArea == NULL || Vad->ControlArea->NumberOfMappedViews 
== 1)
+        {
+            ViewSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << 
PAGE_SHIFT);
+            while (ViewSize > 0)
+            {
+                ULONG FlushSize = min(ViewSize, PAGE_ROUND_DOWN(MAXULONG));
+                MmFlushSegment(FileObject->SectionObjectPointer,
+                               &ViewOffset,
+                               FlushSize,
+                               NULL);
+                ViewSize -= FlushSize;
+                ViewOffset.QuadPart += FlushSize;
+            }
+        }
+
+        FsRtlReleaseFile(FileObject);
+        MmDereferenceSegment(Segment);
     }
 
     /* Notify debugger */

Reply via email to