Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mm/memory: refuse to map page cache folios that are not uptodate
@ 2026-11-06 14:43 Kiryl Shutsemau
  2026-11-07 14:43 ` sashiko-bot
  0 siblings, 1 reply; 3+ messages in thread
From: Kiryl Shutsemau @ 2026-11-06 14:43 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand (Arm)
  Cc: Kiryl Shutsemau (Meta), Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Matthew Wilcox (Oracle), Hugh Dickins, Chris Mason, Pedro Falcato,
	linux-mm, linux-kernel, kernel-team

From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>

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 finish_fault() and do_set_pmd().
finish_fault() checks the folio ->fault() returned rather than the one
it maps: for CoW, do_cow_fault() copies the page cache folio and maps
the copy. do_set_pmd() covers MADV_COLLAPSE, which maps without a
fault.

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>
---
 mm/memory.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/mm/memory.c b/mm/memory.c
index 6fe0b7dab927..ff2f2deff761 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -5674,6 +5674,22 @@ static vm_fault_t __do_fault(struct vm_fault *vmf)
 	return ret;
 }
 
+/*
+ * 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. The callers are
+ * expected to check, so treat a hit as a kernel bug and refuse the mapping.
+ */
+static bool file_folio_not_uptodate(struct folio *folio)
+{
+	if (likely(folio_test_uptodate(folio)))
+		return false;
+	/* Driver pages from ->fault() never get PG_uptodate */
+	if (folio_test_anon(folio) || !folio->mapping)
+		return false;
+	WARN_ONCE(1, "refusing to map a page cache folio that is not uptodate\n");
+	return true;
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 static void deposit_prealloc_pte(struct vm_fault *vmf)
 {
@@ -5714,6 +5730,9 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct folio *folio, struct page *pa
 		return ret;
 	page = &folio->page;
 
+	if (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
@@ -5849,6 +5868,16 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
 	unsigned long addr;
 	bool needs_fallback = false;
 
+	/*
+	 * Check the folio ->fault() returned. For CoW that is the source of the
+	 * copy; DAX CoW has none.
+	 */
+	if (vmf->page) {
+		folio = page_folio(vmf->page);
+		if (file_folio_not_uptodate(folio))
+			return VM_FAULT_SIGBUS;
+	}
+
 fallback:
 	addr = vmf->address;
 

base-commit: dba8aba0a9a00ff781c03d82ae534fc6f8c2e263
-- 
2.54.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-07 18:18 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-06 14:43 [PATCH] mm/memory: refuse to map page cache folios that are not uptodate Kiryl Shutsemau
2026-11-07 14:43 ` sashiko-bot
2026-11-07 18:17   ` David Hildenbrand (Arm)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox