mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
mm: call ->free_folio() directly in folio_unmap_invalidate()
commit615d9bb2ccupstream. 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:fb7d3bc414("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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ff8a7996dc
commit
efc5294724
+2
-1
@@ -227,7 +227,8 @@ void __filemap_remove_folio(struct folio *folio, void *shadow)
|
||||
page_cache_delete(mapping, folio, shadow);
|
||||
}
|
||||
|
||||
void filemap_free_folio(struct address_space *mapping, struct folio *folio)
|
||||
static void filemap_free_folio(const struct address_space *mapping,
|
||||
struct folio *folio)
|
||||
{
|
||||
void (*free_folio)(struct folio *);
|
||||
|
||||
|
||||
@@ -471,7 +471,6 @@ unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
|
||||
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
|
||||
unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
|
||||
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
|
||||
void filemap_free_folio(struct address_space *mapping, struct folio *folio);
|
||||
int truncate_inode_folio(struct address_space *mapping, struct folio *folio);
|
||||
bool truncate_inode_partial_folio(struct folio *folio, loff_t start,
|
||||
loff_t end);
|
||||
|
||||
+5
-1
@@ -622,6 +622,7 @@ static int folio_launder(struct address_space *mapping, struct folio *folio)
|
||||
int folio_unmap_invalidate(struct address_space *mapping, struct folio *folio,
|
||||
gfp_t gfp)
|
||||
{
|
||||
void (*free_folio)(struct folio *);
|
||||
int ret;
|
||||
|
||||
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
|
||||
@@ -648,9 +649,12 @@ int folio_unmap_invalidate(struct address_space *mapping, struct folio *folio,
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
if (mapping_shrinkable(mapping))
|
||||
inode_add_lru(mapping->host);
|
||||
free_folio = mapping->a_ops->free_folio;
|
||||
spin_unlock(&mapping->host->i_lock);
|
||||
|
||||
filemap_free_folio(mapping, folio);
|
||||
if (free_folio)
|
||||
free_folio(folio);
|
||||
folio_put_refs(folio, folio_nr_pages(folio));
|
||||
return 1;
|
||||
failed:
|
||||
xa_unlock_irq(&mapping->i_pages);
|
||||
|
||||
Reference in New Issue
Block a user