* [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2) @ 2024-10-15 17:29 syzbot 2024-12-11 11:30 ` Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 0/2] nilfs2: protect busy buffer heads from being force-cleared Ryusuke Konishi 0 siblings, 2 replies; 6+ messages in thread From: syzbot @ 2024-10-15 17:29 UTC (permalink / raw) To: konishi.ryusuke, linux-kernel, linux-nilfs, syzkaller-bugs Hello, syzbot found the following issue on: HEAD commit: 1d227fcc7222 Merge tag 'net-6.12-rc3' of git://git.kernel... git tree: upstream console+strace: https://syzkaller.appspot.com/x/log.txt?x=1342205f980000 kernel config: https://syzkaller.appspot.com/x/.config?x=7a3fccdd0bb995 dashboard link: https://syzkaller.appspot.com/bug?extid=b2b14916b77acf8626d7 compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 syz repro: https://syzkaller.appspot.com/x/repro.syz?x=11692840580000 C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12ea6f07980000 Downloadable assets: disk image: https://storage.googleapis.com/syzbot-assets/f64f03b05002/disk-1d227fcc.raw.xz vmlinux: https://storage.googleapis.com/syzbot-assets/3ab8ba99a1b6/vmlinux-1d227fcc.xz kernel image: https://storage.googleapis.com/syzbot-assets/97581c221708/bzImage-1d227fcc.xz mounted in repro: https://storage.googleapis.com/syzbot-assets/0cfc62de73c5/mount_0.gz IMPORTANT: if you fix the issue, please add the following tag to the commit: Reported-by: syzbot+b2b14916b77acf8626d7@syzkaller.appspotmail.com WARNING: CPU: 0 PID: 5245 at fs/nilfs2/btree.c:2089 nilfs_btree_propagate+0xc79/0xdf0 fs/nilfs2/btree.c:2089 Modules linked in: CPU: 0 UID: 0 PID: 5245 Comm: segctord Not tainted 6.12.0-rc2-syzkaller-00205-g1d227fcc7222 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 RIP: 0010:nilfs_btree_propagate+0xc79/0xdf0 fs/nilfs2/btree.c:2089 Code: 48 8b 44 24 08 49 8d 74 05 58 e8 12 67 ff ff 48 8b 6c 24 10 43 80 3c 27 00 0f 85 16 fe ff ff e9 19 fe ff ff e8 78 1d 20 fe 90 <0f> 0b 90 e9 ea f3 ff ff e8 6a 1d 20 fe 48 8b 1c 24 48 81 c3 d0 00 RSP: 0018:ffffc90003d873a0 EFLAGS: 00010293 RAX: ffffffff8374c988 RBX: 0000000000000000 RCX: ffff888011dada00 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffffffff8c47aec8 R08: ffffffff8374bd6c R09: 1ffff1100ec15f96 R10: dffffc0000000000 R11: ffffed100ec15f97 R12: dffffc0000000000 R13: 1ffff1100ec15f9f R14: 1ffff1100ec15f96 R15: ffff8880760afcb0 FS: 0000000000000000(0000) GS:ffff8880b8600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f8737b0dd58 CR3: 0000000079068000 CR4: 00000000003526f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> nilfs_bmap_propagate+0x75/0x120 fs/nilfs2/bmap.c:345 nilfs_collect_file_data+0x4d/0xd0 fs/nilfs2/segment.c:587 nilfs_segctor_apply_buffers+0x184/0x340 fs/nilfs2/segment.c:1006 nilfs_segctor_scan_file+0x28c/0xa50 fs/nilfs2/segment.c:1045 nilfs_segctor_collect_blocks fs/nilfs2/segment.c:1216 [inline] nilfs_segctor_collect fs/nilfs2/segment.c:1540 [inline] nilfs_segctor_do_construct+0x1c28/0x6b90 fs/nilfs2/segment.c:2115 nilfs_segctor_construct+0x181/0x6b0 fs/nilfs2/segment.c:2479 nilfs_segctor_thread_construct fs/nilfs2/segment.c:2587 [inline] nilfs_segctor_thread+0x69e/0xe80 fs/nilfs2/segment.c:2701 kthread+0x2f0/0x390 kernel/kthread.c:389 ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:147 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244 </TASK> --- This report is generated by a bot. It may contain errors. See https://goo.gl/tpsmEJ for more information about syzbot. syzbot engineers can be reached at syzkaller@googlegroups.com. syzbot will keep track of this issue. See: https://goo.gl/tpsmEJ#status for how to communicate with syzbot. If the report is already addressed, let syzbot know by replying with: #syz fix: exact-commit-title If you want syzbot to run the reproducer, reply with: #syz test: git://repo/address.git branch-or-commit-hash If you attach or paste a git patch, syzbot will apply it before testing. If you want to overwrite report's subsystems, reply with: #syz set subsystems: new-subsystem (See the list of subsystem names on the web dashboard) If the report is a duplicate of another one, reply with: #syz dup: exact-subject-of-another-report If you want to undo deduplication, reply with: #syz undup ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2) 2024-10-15 17:29 [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2) syzbot @ 2024-12-11 11:30 ` Ryusuke Konishi 2024-12-11 12:43 ` syzbot 2025-01-07 20:00 ` [PATCH 0/2] nilfs2: protect busy buffer heads from being force-cleared Ryusuke Konishi 1 sibling, 1 reply; 6+ messages in thread From: Ryusuke Konishi @ 2024-12-11 11:30 UTC (permalink / raw) To: syzbot+b2b14916b77acf8626d7; +Cc: linux-kernel, syzkaller-bugs Check if the buffer is referenced before clearing the page/folio state, and skip the clear if it is. #syz test diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 10def4b55995..ad99497f90af 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -392,6 +392,11 @@ void nilfs_clear_dirty_pages(struct address_space *mapping) /** * nilfs_clear_folio_dirty - discard dirty folio * @folio: dirty folio that will be discarded + * + * nilfs_clear_folio_dirty() clears working states including dirty state for + * the folio and its buffers. If the folio has buffers, clear only if it is + * confirmed that none of the buffer heads are busy (none have valid + * references and none are locked). */ void nilfs_clear_folio_dirty(struct folio *folio) { @@ -399,10 +404,6 @@ void nilfs_clear_folio_dirty(struct folio *folio) BUG_ON(!folio_test_locked(folio)); - folio_clear_uptodate(folio); - folio_clear_mappedtodisk(folio); - folio_clear_checked(folio); - head = folio_buffers(folio); if (head) { const unsigned long clear_bits = @@ -410,6 +411,25 @@ void nilfs_clear_folio_dirty(struct folio *folio) BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) | BIT(BH_Delay)); + bool busy, invalidated = false; + +recheck_buffers: + busy = false; + bh = head; + do { + if (atomic_read(&bh->b_count) | buffer_locked(bh)) { + busy = true; + break; + } + } while (bh = bh->b_this_page, bh != head); + + if (busy) { + if (invalidated) + return; + invalidate_bh_lrus(); + invalidated = true; + goto recheck_buffers; + } bh = head; do { @@ -419,6 +439,9 @@ void nilfs_clear_folio_dirty(struct folio *folio) } while (bh = bh->b_this_page, bh != head); } + folio_clear_uptodate(folio); + folio_clear_mappedtodisk(folio); + folio_clear_checked(folio); __nilfs_clear_folio_dirty(folio); } ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2) 2024-12-11 11:30 ` Ryusuke Konishi @ 2024-12-11 12:43 ` syzbot 0 siblings, 0 replies; 6+ messages in thread From: syzbot @ 2024-12-11 12:43 UTC (permalink / raw) To: konishi.ryusuke, linux-kernel, syzkaller-bugs Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-by: syzbot+b2b14916b77acf8626d7@syzkaller.appspotmail.com Tested-by: syzbot+b2b14916b77acf8626d7@syzkaller.appspotmail.com Tested on: commit: f92f4749 Merge tag 'clk-fixes-for-linus' of git://git... git tree: upstream console output: https://syzkaller.appspot.com/x/log.txt?x=135db3e8580000 kernel config: https://syzkaller.appspot.com/x/.config?x=5a0b1b189561bf60 dashboard link: https://syzkaller.appspot.com/bug?extid=b2b14916b77acf8626d7 compiler: Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40 patch: https://syzkaller.appspot.com/x/patch.diff?x=13a5c20f980000 Note: testing is done by a robot and is best-effort only. ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 0/2] nilfs2: protect busy buffer heads from being force-cleared 2024-10-15 17:29 [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2) syzbot 2024-12-11 11:30 ` Ryusuke Konishi @ 2025-01-07 20:00 ` Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 1/2] nilfs2: do not force clear folio if buffer is referenced Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 2/2] nilfs2: protect access to buffers with no active references Ryusuke Konishi 1 sibling, 2 replies; 6+ messages in thread From: Ryusuke Konishi @ 2025-01-07 20:00 UTC (permalink / raw) To: Andrew Morton Cc: linux-nilfs, syzbot+b2b14916b77acf8626d7, syzbot+d98fd19acd08b36ff422, syzkaller-bugs, linux-kernel Hi Andrew, please queue this series for the next cycle. This series fixes the buffer head state inconsistency issues reported by syzbot that occurs when the filesystem is corrupted and falls back to read-only, and the associated buffer head use-after-free issue. Thanks, Ryusuke Konishi Ryusuke Konishi (2): nilfs2: do not force clear folio if buffer is referenced nilfs2: protect access to buffers with no active references fs/nilfs2/page.c | 31 +++++++++++++++++++++++++++---- fs/nilfs2/segment.c | 4 +++- 2 files changed, 30 insertions(+), 5 deletions(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] nilfs2: do not force clear folio if buffer is referenced 2025-01-07 20:00 ` [PATCH 0/2] nilfs2: protect busy buffer heads from being force-cleared Ryusuke Konishi @ 2025-01-07 20:00 ` Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 2/2] nilfs2: protect access to buffers with no active references Ryusuke Konishi 1 sibling, 0 replies; 6+ messages in thread From: Ryusuke Konishi @ 2025-01-07 20:00 UTC (permalink / raw) To: Andrew Morton Cc: linux-nilfs, syzbot+b2b14916b77acf8626d7, syzbot+d98fd19acd08b36ff422, syzkaller-bugs, linux-kernel Syzbot has reported that after nilfs2 detects filesystem corruption and falls back to read-only, inconsistencies in the buffer state may occur. One of the inconsistencies is that when nilfs2 calls mark_buffer_dirty() to set a data or metadata buffer as dirty, but it detects that the buffer is not in the uptodate state: WARNING: CPU: 0 PID: 6049 at fs/buffer.c:1177 mark_buffer_dirty+0x2e5/0x520 fs/buffer.c:1177 ... Call Trace: <TASK> nilfs_palloc_commit_alloc_entry+0x4b/0x160 fs/nilfs2/alloc.c:598 nilfs_ifile_create_inode+0x1dd/0x3a0 fs/nilfs2/ifile.c:73 nilfs_new_inode+0x254/0x830 fs/nilfs2/inode.c:344 nilfs_mkdir+0x10d/0x340 fs/nilfs2/namei.c:218 vfs_mkdir+0x2f9/0x4f0 fs/namei.c:4257 do_mkdirat+0x264/0x3a0 fs/namei.c:4280 __do_sys_mkdirat fs/namei.c:4295 [inline] __se_sys_mkdirat fs/namei.c:4293 [inline] __x64_sys_mkdirat+0x87/0xa0 fs/namei.c:4293 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f The other is when nilfs_btree_propagate(), which propagates the dirty state to the ancestor nodes of a b-tree that point to a dirty buffer, detects that the origin buffer is not dirty, even though it should be: WARNING: CPU: 0 PID: 5245 at fs/nilfs2/btree.c:2089 nilfs_btree_propagate+0xc79/0xdf0 fs/nilfs2/btree.c:2089 ... Call Trace: <TASK> nilfs_bmap_propagate+0x75/0x120 fs/nilfs2/bmap.c:345 nilfs_collect_file_data+0x4d/0xd0 fs/nilfs2/segment.c:587 nilfs_segctor_apply_buffers+0x184/0x340 fs/nilfs2/segment.c:1006 nilfs_segctor_scan_file+0x28c/0xa50 fs/nilfs2/segment.c:1045 nilfs_segctor_collect_blocks fs/nilfs2/segment.c:1216 [inline] nilfs_segctor_collect fs/nilfs2/segment.c:1540 [inline] nilfs_segctor_do_construct+0x1c28/0x6b90 fs/nilfs2/segment.c:2115 nilfs_segctor_construct+0x181/0x6b0 fs/nilfs2/segment.c:2479 nilfs_segctor_thread_construct fs/nilfs2/segment.c:2587 [inline] nilfs_segctor_thread+0x69e/0xe80 fs/nilfs2/segment.c:2701 kthread+0x2f0/0x390 kernel/kthread.c:389 ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:147 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244 </TASK> Both of these issues are caused by the callbacks that handle the page/folio write requests, forcibly clear various states, including the working state of the buffers they hold, at unexpected times when they detect read-only fallback. Fix these issues by checking if the buffer is referenced before clearing the page/folio state, and skipping the clear if it is. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Reported-by: syzbot+b2b14916b77acf8626d7@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=b2b14916b77acf8626d7 Reported-by: syzbot+d98fd19acd08b36ff422@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=d98fd19acd08b36ff422 Fixes: 8c26c4e2694a ("nilfs2: fix issue with flush kernel thread after remount in RO mode because of driver's internal error or metadata corruption") Tested-by: syzbot+b2b14916b77acf8626d7@syzkaller.appspotmail.com --- fs/nilfs2/page.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 9de2a494a069..899686d2e5f7 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -392,6 +392,11 @@ void nilfs_clear_dirty_pages(struct address_space *mapping) /** * nilfs_clear_folio_dirty - discard dirty folio * @folio: dirty folio that will be discarded + * + * nilfs_clear_folio_dirty() clears working states including dirty state for + * the folio and its buffers. If the folio has buffers, clear only if it is + * confirmed that none of the buffer heads are busy (none have valid + * references and none are locked). */ void nilfs_clear_folio_dirty(struct folio *folio) { @@ -399,10 +404,6 @@ void nilfs_clear_folio_dirty(struct folio *folio) BUG_ON(!folio_test_locked(folio)); - folio_clear_uptodate(folio); - folio_clear_mappedtodisk(folio); - folio_clear_checked(folio); - head = folio_buffers(folio); if (head) { const unsigned long clear_bits = @@ -410,6 +411,25 @@ void nilfs_clear_folio_dirty(struct folio *folio) BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) | BIT(BH_Delay)); + bool busy, invalidated = false; + +recheck_buffers: + busy = false; + bh = head; + do { + if (atomic_read(&bh->b_count) | buffer_locked(bh)) { + busy = true; + break; + } + } while (bh = bh->b_this_page, bh != head); + + if (busy) { + if (invalidated) + return; + invalidate_bh_lrus(); + invalidated = true; + goto recheck_buffers; + } bh = head; do { @@ -419,6 +439,9 @@ void nilfs_clear_folio_dirty(struct folio *folio) } while (bh = bh->b_this_page, bh != head); } + folio_clear_uptodate(folio); + folio_clear_mappedtodisk(folio); + folio_clear_checked(folio); __nilfs_clear_folio_dirty(folio); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] nilfs2: protect access to buffers with no active references 2025-01-07 20:00 ` [PATCH 0/2] nilfs2: protect busy buffer heads from being force-cleared Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 1/2] nilfs2: do not force clear folio if buffer is referenced Ryusuke Konishi @ 2025-01-07 20:00 ` Ryusuke Konishi 1 sibling, 0 replies; 6+ messages in thread From: Ryusuke Konishi @ 2025-01-07 20:00 UTC (permalink / raw) To: Andrew Morton Cc: linux-nilfs, syzbot+b2b14916b77acf8626d7, syzbot+d98fd19acd08b36ff422, syzkaller-bugs, linux-kernel nilfs_lookup_dirty_data_buffers(), which iterates through the buffers attached to dirty data folios/pages, accesses the attached buffers without locking the folios/pages. For data cache, nilfs_clear_folio_dirty() may be called asynchronously when the file system degenerates to read only, so nilfs_lookup_dirty_data_buffers() still has the potential to cause use after free issues when buffers lose the protection of their dirty state midway due to this asynchronous clearing and are unintentionally freed by try_to_free_buffers(). Eliminate this race issue by adjusting the lock section in this function. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Fixes: 8c26c4e2694a ("nilfs2: fix issue with flush kernel thread after remount in RO mode because of driver's internal error or metadata corruption") --- fs/nilfs2/segment.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 587251830897..58a598b548fa 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -734,7 +734,6 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, if (!head) head = create_empty_buffers(folio, i_blocksize(inode), 0); - folio_unlock(folio); bh = head; do { @@ -744,11 +743,14 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, list_add_tail(&bh->b_assoc_buffers, listp); ndirties++; if (unlikely(ndirties >= nlimit)) { + folio_unlock(folio); folio_batch_release(&fbatch); cond_resched(); return ndirties; } } while (bh = bh->b_this_page, bh != head); + + folio_unlock(folio); } folio_batch_release(&fbatch); cond_resched(); -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-01-07 20:02 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-10-15 17:29 [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2) syzbot 2024-12-11 11:30 ` Ryusuke Konishi 2024-12-11 12:43 ` syzbot 2025-01-07 20:00 ` [PATCH 0/2] nilfs2: protect busy buffer heads from being force-cleared Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 1/2] nilfs2: do not force clear folio if buffer is referenced Ryusuke Konishi 2025-01-07 20:00 ` [PATCH 2/2] nilfs2: protect access to buffers with no active references Ryusuke Konishi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox