* [PATCH v3] mm/memory: refuse to map page cache folios that are not uptodate
@ 2026-11-11 18:24 Kiryl Shutsemau (Meta)
0 siblings, 0 replies; only message in thread
From: Kiryl Shutsemau (Meta) @ 2026-11-11 18:24 UTC (permalink / raw)
To: David Hildenbrand (Arm),
Andrew Morton, Pedro Falcato, Lorenzo Stoakes,
Matthew Wilcox (Oracle)
Cc: Kiryl Shutsemau (Meta),
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Chris Mason,
linux-mm, linux-fsdevel, linux-kernel, kernel-team
A page cache folio that is not uptodate holds data that was never read
in or cleared. shmem fallocate(2), for one, adds such folios and clears
them only on first use. Mapping one hands userspace whatever the memory
held before.
Each path that maps page cache checks for this itself: fault-around in
next_uptodate_folio(), a fault in filemap_fault() or shmem_get_folio().
Nothing in the mapping code does, so a caller that misses the check
leaks stale memory silently. MADV_COLLAPSE did exactly that with
fallocated shmem THPs until recently.
Warn and refuse the mapping in __do_fault() and do_set_pmd().
__do_fault() checks the folio ->fault() returned while it is still
locked. For CoW, that is the page cache folio that do_cow_fault()
copies from. do_set_pmd() covers MADV_COLLAPSE, which maps without a
fault.
do_shared_fault() then unlocks the folio for ->page_mkwrite(). A
filesystem that clears PG_uptodate on a folio in the page cache is
buggy, so that window gets no check of its own.
The fault gets SIGBUS, as for a folio that fails to read in.
MADV_COLLAPSE fails and leaves the range to be faulted in.
Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
---
v3:
- Drop "mm/memory: recheck PG_uptodate after ->page_mkwrite()": a
filesystem that clears PG_uptodate on a cached folio is buggy (Matthew)
- Move file_folio_not_uptodate() into this patch, assert it never sees
an anon folio, reword its comment and drop likely() (Lorenzo)
- Rebase on mm/core.git for-next, which has the MADV_COLLAPSE fix
v2: https://lore.kernel.org/all/20261109120403.82361-1-kas@kernel.org/
v1: https://lore.kernel.org/all/20261106144323.3634477-1-kirill@shutemov.name/
mm/memory.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/mm/memory.c b/mm/memory.c
index fcc7ea2a00d1..c79c1c6f6141 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -5641,6 +5641,22 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
return VM_FAULT_OOM;
}
+/*
+ * A page cache folio that is not uptodate holds data that was never read in
+ * or cleared, and mapping it leaks stale memory to userspace.
+ */
+static bool file_folio_not_uptodate(struct folio *folio)
+{
+ VM_WARN_ON_ONCE_FOLIO(folio_test_anon(folio), folio);
+ if (folio_test_uptodate(folio))
+ return false;
+ /*
+ * ->fault() can also return driver memory that is not in the page
+ * cache. It never gets PG_uptodate.
+ */
+ return folio->mapping;
+}
+
/*
* Either the VMA lock or the mmap_lock must have been held on entry
* (see FAULT_FLAG_VMA_LOCK) and may have been released depending on
@@ -5700,6 +5716,13 @@ static vm_fault_t __do_fault(struct vm_fault *vmf)
else
VM_BUG_ON_PAGE(!folio_test_locked(folio), vmf->page);
+ if (WARN_ON_ONCE(file_folio_not_uptodate(folio))) {
+ folio_unlock(folio);
+ folio_put(folio);
+ vmf->page = NULL;
+ return VM_FAULT_SIGBUS;
+ }
+
return ret;
}
@@ -5745,6 +5768,9 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct folio *folio, struct page *pa
return ret;
page = &folio->page;
+ if (WARN_ON_ONCE(file_folio_not_uptodate(folio)))
+ return VM_FAULT_SIGBUS;
+
/*
* Just backoff if any subpage of a THP is corrupted otherwise
* the corrupted page may mapped by PMD silently to escape the
Range-diff against v2:
1: 632ab50e643d < -: ------------ mm/memory: recheck PG_uptodate after ->page_mkwrite()
2: 1e329f330c41 ! 1: 50ea9bc46c05 mm/memory: refuse to map page cache folios that are not uptodate
@@ Commit message
Warn and refuse the mapping in __do_fault() and do_set_pmd().
__do_fault() checks the folio ->fault() returned while it is still
- locked. do_shared_fault() unlocks it for ->page_mkwrite(), and a
- writeback error can clear PG_uptodate after that; that case retries the
- fault instead. For CoW, __do_fault() sees the page cache folio that
- do_cow_fault() copies from. do_set_pmd() covers MADV_COLLAPSE, which
- maps without a fault.
+ locked. For CoW, that is the page cache folio that do_cow_fault()
+ copies from. do_set_pmd() covers MADV_COLLAPSE, which maps without a
+ fault.
+
+ do_shared_fault() then unlocks the folio for ->page_mkwrite(). A
+ filesystem that clears PG_uptodate on a folio in the page cache is
+ buggy, so that window gets no check of its own.
The fault gets SIGBUS, as for a folio that fails to read in.
MADV_COLLAPSE fails and leaves the range to be faulted in.
@@ Commit message
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
## mm/memory.c ##
+@@ mm/memory.c: static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
+ return VM_FAULT_OOM;
+ }
+
++/*
++ * A page cache folio that is not uptodate holds data that was never read in
++ * or cleared, and mapping it leaks stale memory to userspace.
++ */
++static bool file_folio_not_uptodate(struct folio *folio)
++{
++ VM_WARN_ON_ONCE_FOLIO(folio_test_anon(folio), folio);
++ if (folio_test_uptodate(folio))
++ return false;
++ /*
++ * ->fault() can also return driver memory that is not in the page
++ * cache. It never gets PG_uptodate.
++ */
++ return folio->mapping;
++}
++
+ /*
+ * Either the VMA lock or the mmap_lock must have been held on entry
+ * (see FAULT_FLAG_VMA_LOCK) and may have been released depending on
@@ mm/memory.c: static vm_fault_t __do_fault(struct vm_fault *vmf)
else
VM_BUG_ON_PAGE(!folio_test_locked(folio), vmf->page);
base-commit: 8d21e3d3faf19f461f6d0380fe8a1f5bdba97f25
--
2.54.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-11-11 18:24 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-11 18:24 [PATCH v3] mm/memory: refuse to map page cache folios that are not uptodate Kiryl Shutsemau (Meta)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®