[PATCH 4.19 5.4 5.10 5.15 6.1] nilfs2: fix general protection fault in nilfs_lookup_dirty_data_buffers()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux