commit f83913f8c5b882a312e72b7669762f8a5c9385e4 upstream. A syzbot stress test reported that create_empty_buffers() called from nilfs_lookup_dirty_data_buffers() can cause a general protection fault. Analysis using its reproducer revealed that the back reference "mapping" from a page/folio has been changed to NULL after dirty page/folio gang lookup in nilfs_lookup_dirty_data_buffers(). Fix this issue by excluding pages/folios from being collected if, after acquiring a lock on each page/folio, its back reference "mapping" differs from the pointer to the address space struct that held the page/folio. Link: https://lkml.kernel.org/r/20230805132038.6435-1-konishi.ryusuke@xxxxxxxxx Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxx> Reported-by: syzbot+0ad741797f4565e7e2d2@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://lkml.kernel.org/r/0000000000002930a705fc32b231@xxxxxxxxxx Tested-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxx> Cc: <stable@xxxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxx> --- Please apply this patch to the above stable trees instead of the patch that could not be applied to them. This patch resolves the conflict caused by the recent page to folio conversion applied in nilfs_lookup_dirty_data_buffers(). The general protection fault reported by syzbot reproduces on these stable kernels before the page/folio conversion is applied. This fixes it. With this tweak, this patch is applicable from v4.15 to v6.2. Also, this patch has been tested against the -stable trees of each version in the subject prefix. fs/nilfs2/segment.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 21e8260112c8..a4a147a983e0 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -725,6 +725,11 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, struct page *page = pvec.pages[i]; lock_page(page); + if (unlikely(page->mapping != mapping)) { + /* Exclude pages removed from the address space */ + unlock_page(page); + continue; + } if (!page_has_buffers(page)) create_empty_buffers(page, i_blocksize(inode), 0); unlock_page(page); -- 2.39.3