Skip to content

Commit 615d9bb

Browse files
Matthew Wilcox (Oracle)akpm00
authored andcommitted
mm: call ->free_folio() directly in folio_unmap_invalidate()
We can only call filemap_free_folio() if we have a reference to (or hold a lock on) the mapping. Otherwise, we've already removed the folio from the mapping so it no longer pins the mapping and the mapping can be removed, causing a use-after-free when accessing mapping->a_ops. Follow the same pattern as __remove_mapping() and load the free_folio function pointer before dropping the lock on the mapping. That lets us make filemap_free_folio() static as this was the only caller outside filemap.c. Link: https://lore.kernel.org/20260413184314.3419945-1-willy@infradead.org Fixes: fb7d3bc ("mm/filemap: drop streaming/uncached pages when writeback completes") Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reported-by: Google Big Sleep <big-sleep-vuln-reports+bigsleep-501448199@google.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: Jan Kara <jack@suse.cz> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 8f5857b commit 615d9bb

3 files changed

Lines changed: 7 additions & 3 deletions

File tree

mm/filemap.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ void __filemap_remove_folio(struct folio *folio, void *shadow)
228228
page_cache_delete(mapping, folio, shadow);
229229
}
230230

231-
void filemap_free_folio(struct address_space *mapping, struct folio *folio)
231+
static void filemap_free_folio(const struct address_space *mapping,
232+
struct folio *folio)
232233
{
233234
void (*free_folio)(struct folio *);
234235

mm/internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,6 @@ unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
540540
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
541541
unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
542542
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
543-
void filemap_free_folio(struct address_space *mapping, struct folio *folio);
544543
int truncate_inode_folio(struct address_space *mapping, struct folio *folio);
545544
bool truncate_inode_partial_folio(struct folio *folio, loff_t start,
546545
loff_t end);

mm/truncate.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ static int folio_launder(struct address_space *mapping, struct folio *folio)
622622
int folio_unmap_invalidate(struct address_space *mapping, struct folio *folio,
623623
gfp_t gfp)
624624
{
625+
void (*free_folio)(struct folio *);
625626
int ret;
626627

627628
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
@@ -648,9 +649,12 @@ int folio_unmap_invalidate(struct address_space *mapping, struct folio *folio,
648649
xa_unlock_irq(&mapping->i_pages);
649650
if (mapping_shrinkable(mapping))
650651
inode_lru_list_add(mapping->host);
652+
free_folio = mapping->a_ops->free_folio;
651653
spin_unlock(&mapping->host->i_lock);
652654

653-
filemap_free_folio(mapping, folio);
655+
if (free_folio)
656+
free_folio(folio);
657+
folio_put_refs(folio, folio_nr_pages(folio));
654658
return 1;
655659
failed:
656660
xa_unlock_irq(&mapping->i_pages);

0 commit comments

Comments
 (0)