From: Jaegeuk Kim <jaegeuk@kernel.org>
To: Chao Yu <chao@kernel.org>
Cc: linux-f2fs-devel@lists.sourceforge.net,
linux-kernel@vger.kernel.org,
syzbot+b6b347b7a4ea1b2e29b6@syzkaller.appspotmail.com
Subject: Re: [PATCH] f2fs: fix to avoid accessing uninitialized curseg
Date: Thu, 13 Feb 2025 18:01:21 +0000 [thread overview]
Message-ID: <Z64zcac0_dw1_rML@google.com> (raw)
In-Reply-To: <20250212075242.988652-1-chao@kernel.org>
On 02/12, Chao Yu wrote:
> syzbot reports a f2fs bug as below:
>
> F2FS-fs (loop3): Stopped filesystem due to reason: 7
> kworker/u8:7: attempt to access beyond end of device
> BUG: unable to handle page fault for address: ffffed1604ea3dfa
> RIP: 0010:get_ckpt_valid_blocks fs/f2fs/segment.h:361 [inline]
> RIP: 0010:has_curseg_enough_space fs/f2fs/segment.h:570 [inline]
> RIP: 0010:__get_secs_required fs/f2fs/segment.h:620 [inline]
> RIP: 0010:has_not_enough_free_secs fs/f2fs/segment.h:633 [inline]
> RIP: 0010:has_enough_free_secs+0x575/0x1660 fs/f2fs/segment.h:649
> <TASK>
> f2fs_is_checkpoint_ready fs/f2fs/segment.h:671 [inline]
> f2fs_write_inode+0x425/0x540 fs/f2fs/inode.c:791
> write_inode fs/fs-writeback.c:1525 [inline]
> __writeback_single_inode+0x708/0x10d0 fs/fs-writeback.c:1745
> writeback_sb_inodes+0x820/0x1360 fs/fs-writeback.c:1976
> wb_writeback+0x413/0xb80 fs/fs-writeback.c:2156
> wb_do_writeback fs/fs-writeback.c:2303 [inline]
> wb_workfn+0x410/0x1080 fs/fs-writeback.c:2343
> process_one_work kernel/workqueue.c:3236 [inline]
> process_scheduled_works+0xa66/0x1840 kernel/workqueue.c:3317
> worker_thread+0x870/0xd30 kernel/workqueue.c:3398
> kthread+0x7a9/0x920 kernel/kthread.c:464
> ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:148
> ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
>
> Commit 8b10d3653735 ("f2fs: introduce FAULT_NO_SEGMENT") allows to trigger
> no free segment fault in allocator, then it will update curseg->segno to
> NULL_SEGNO, though, CP_ERROR_FLAG has been set, f2fs_write_inode() missed
> to check the flag, and access invalid curseg->segno directly in below call
> path, then resulting in panic:
>
> - f2fs_write_inode
> - f2fs_is_checkpoint_ready
> - has_enough_free_secs
> - has_not_enough_free_secs
> - __get_secs_required
> - has_curseg_enough_space
> - get_ckpt_valid_blocks
> : access invalid curseg->segno
>
> To avoid this issue, let's:
> - check CP_ERROR_FLAG flag in prior to f2fs_is_checkpoint_ready() in
> f2fs_write_inode().
> - in has_curseg_enough_space(), a) verify status of curseg before accessing
> its field, and b) grab curseg_mutex lock to avoid race condition.
>
> Fixes: 8b10d3653735 ("f2fs: introduce FAULT_NO_SEGMENT")
> Reported-by: syzbot+b6b347b7a4ea1b2e29b6@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/all/67973c2b.050a0220.11b1bb.0089.GAE@google.com
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
> fs/f2fs/inode.c | 7 +++++++
> fs/f2fs/segment.h | 27 ++++++++++++++++++++++-----
> 2 files changed, 29 insertions(+), 5 deletions(-)
>
> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
> index 02f1b69d03d8..5c1b515eab36 100644
> --- a/fs/f2fs/inode.c
> +++ b/fs/f2fs/inode.c
> @@ -799,6 +799,13 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
> !is_inode_flag_set(inode, FI_DIRTY_INODE))
> return 0;
>
> + /*
> + * no need to update inode page, ultimately f2fs_evict_inode() will
> + * clear dirty status of inode.
> + */
> + if (f2fs_cp_error(sbi))
> + return -EIO;
> +
> if (!f2fs_is_checkpoint_ready(sbi)) {
> f2fs_mark_inode_dirty_sync(inode, true);
> return -ENOSPC;
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index 943be4f1d6d2..e9fcf2b85b76 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -559,15 +559,23 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
> unsigned int node_blocks, unsigned int data_blocks,
> unsigned int dent_blocks)
> {
> -
> + struct curseg_info *curseg;
> unsigned int segno, left_blocks, blocks;
> int i;
>
> /* check current data/node sections in the worst case. */
> for (i = CURSEG_HOT_DATA; i < NR_PERSISTENT_LOG; i++) {
> - segno = CURSEG_I(sbi, i)->segno;
> - left_blocks = CAP_BLKS_PER_SEC(sbi) -
> + curseg = CURSEG_I(sbi, i);
> +
> + mutex_lock(&curseg->curseg_mutex);
> + if (!curseg->inited || curseg->segno == NULL_SEGNO) {
> + left_blocks = 0;
> + } else {
> + segno = curseg->segno;
> + left_blocks = CAP_BLKS_PER_SEC(sbi) -
> get_ckpt_valid_blocks(sbi, segno, true);
> + }
> + mutex_unlock(&curseg->curseg_mutex);
This looks a bit worrisome, as it'll block user-facing allocation. Can we
have another way to prevent the issue?
>
> blocks = i <= CURSEG_COLD_DATA ? data_blocks : node_blocks;
> if (blocks > left_blocks)
> @@ -575,9 +583,18 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
> }
>
> /* check current data section for dentry blocks. */
> - segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno;
> - left_blocks = CAP_BLKS_PER_SEC(sbi) -
> + curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
> +
> + mutex_lock(&curseg->curseg_mutex);
> + if (!curseg->inited || curseg->segno == NULL_SEGNO) {
> + left_blocks = 0;
> + } else {
> + segno = curseg->segno;
> + left_blocks = CAP_BLKS_PER_SEC(sbi) -
> get_ckpt_valid_blocks(sbi, segno, true);
> + }
> + mutex_unlock(&curseg->curseg_mutex);
> +
> if (dent_blocks > left_blocks)
> return false;
> return true;
> --
> 2.48.1.502.g6dc24dfdaf-goog
WARNING: multiple messages have this Message-ID (diff)
From: Jaegeuk Kim via Linux-f2fs-devel <linux-f2fs-devel@lists.sourceforge.net>
To: Chao Yu <chao@kernel.org>
Cc: linux-kernel@vger.kernel.org,
syzbot+b6b347b7a4ea1b2e29b6@syzkaller.appspotmail.com,
linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH] f2fs: fix to avoid accessing uninitialized curseg
Date: Thu, 13 Feb 2025 18:01:21 +0000 [thread overview]
Message-ID: <Z64zcac0_dw1_rML@google.com> (raw)
In-Reply-To: <20250212075242.988652-1-chao@kernel.org>
On 02/12, Chao Yu wrote:
> syzbot reports a f2fs bug as below:
>
> F2FS-fs (loop3): Stopped filesystem due to reason: 7
> kworker/u8:7: attempt to access beyond end of device
> BUG: unable to handle page fault for address: ffffed1604ea3dfa
> RIP: 0010:get_ckpt_valid_blocks fs/f2fs/segment.h:361 [inline]
> RIP: 0010:has_curseg_enough_space fs/f2fs/segment.h:570 [inline]
> RIP: 0010:__get_secs_required fs/f2fs/segment.h:620 [inline]
> RIP: 0010:has_not_enough_free_secs fs/f2fs/segment.h:633 [inline]
> RIP: 0010:has_enough_free_secs+0x575/0x1660 fs/f2fs/segment.h:649
> <TASK>
> f2fs_is_checkpoint_ready fs/f2fs/segment.h:671 [inline]
> f2fs_write_inode+0x425/0x540 fs/f2fs/inode.c:791
> write_inode fs/fs-writeback.c:1525 [inline]
> __writeback_single_inode+0x708/0x10d0 fs/fs-writeback.c:1745
> writeback_sb_inodes+0x820/0x1360 fs/fs-writeback.c:1976
> wb_writeback+0x413/0xb80 fs/fs-writeback.c:2156
> wb_do_writeback fs/fs-writeback.c:2303 [inline]
> wb_workfn+0x410/0x1080 fs/fs-writeback.c:2343
> process_one_work kernel/workqueue.c:3236 [inline]
> process_scheduled_works+0xa66/0x1840 kernel/workqueue.c:3317
> worker_thread+0x870/0xd30 kernel/workqueue.c:3398
> kthread+0x7a9/0x920 kernel/kthread.c:464
> ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:148
> ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
>
> Commit 8b10d3653735 ("f2fs: introduce FAULT_NO_SEGMENT") allows to trigger
> no free segment fault in allocator, then it will update curseg->segno to
> NULL_SEGNO, though, CP_ERROR_FLAG has been set, f2fs_write_inode() missed
> to check the flag, and access invalid curseg->segno directly in below call
> path, then resulting in panic:
>
> - f2fs_write_inode
> - f2fs_is_checkpoint_ready
> - has_enough_free_secs
> - has_not_enough_free_secs
> - __get_secs_required
> - has_curseg_enough_space
> - get_ckpt_valid_blocks
> : access invalid curseg->segno
>
> To avoid this issue, let's:
> - check CP_ERROR_FLAG flag in prior to f2fs_is_checkpoint_ready() in
> f2fs_write_inode().
> - in has_curseg_enough_space(), a) verify status of curseg before accessing
> its field, and b) grab curseg_mutex lock to avoid race condition.
>
> Fixes: 8b10d3653735 ("f2fs: introduce FAULT_NO_SEGMENT")
> Reported-by: syzbot+b6b347b7a4ea1b2e29b6@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/all/67973c2b.050a0220.11b1bb.0089.GAE@google.com
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
> fs/f2fs/inode.c | 7 +++++++
> fs/f2fs/segment.h | 27 ++++++++++++++++++++++-----
> 2 files changed, 29 insertions(+), 5 deletions(-)
>
> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
> index 02f1b69d03d8..5c1b515eab36 100644
> --- a/fs/f2fs/inode.c
> +++ b/fs/f2fs/inode.c
> @@ -799,6 +799,13 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
> !is_inode_flag_set(inode, FI_DIRTY_INODE))
> return 0;
>
> + /*
> + * no need to update inode page, ultimately f2fs_evict_inode() will
> + * clear dirty status of inode.
> + */
> + if (f2fs_cp_error(sbi))
> + return -EIO;
> +
> if (!f2fs_is_checkpoint_ready(sbi)) {
> f2fs_mark_inode_dirty_sync(inode, true);
> return -ENOSPC;
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index 943be4f1d6d2..e9fcf2b85b76 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -559,15 +559,23 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
> unsigned int node_blocks, unsigned int data_blocks,
> unsigned int dent_blocks)
> {
> -
> + struct curseg_info *curseg;
> unsigned int segno, left_blocks, blocks;
> int i;
>
> /* check current data/node sections in the worst case. */
> for (i = CURSEG_HOT_DATA; i < NR_PERSISTENT_LOG; i++) {
> - segno = CURSEG_I(sbi, i)->segno;
> - left_blocks = CAP_BLKS_PER_SEC(sbi) -
> + curseg = CURSEG_I(sbi, i);
> +
> + mutex_lock(&curseg->curseg_mutex);
> + if (!curseg->inited || curseg->segno == NULL_SEGNO) {
> + left_blocks = 0;
> + } else {
> + segno = curseg->segno;
> + left_blocks = CAP_BLKS_PER_SEC(sbi) -
> get_ckpt_valid_blocks(sbi, segno, true);
> + }
> + mutex_unlock(&curseg->curseg_mutex);
This looks a bit worrisome, as it'll block user-facing allocation. Can we
have another way to prevent the issue?
>
> blocks = i <= CURSEG_COLD_DATA ? data_blocks : node_blocks;
> if (blocks > left_blocks)
> @@ -575,9 +583,18 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
> }
>
> /* check current data section for dentry blocks. */
> - segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno;
> - left_blocks = CAP_BLKS_PER_SEC(sbi) -
> + curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
> +
> + mutex_lock(&curseg->curseg_mutex);
> + if (!curseg->inited || curseg->segno == NULL_SEGNO) {
> + left_blocks = 0;
> + } else {
> + segno = curseg->segno;
> + left_blocks = CAP_BLKS_PER_SEC(sbi) -
> get_ckpt_valid_blocks(sbi, segno, true);
> + }
> + mutex_unlock(&curseg->curseg_mutex);
> +
> if (dent_blocks > left_blocks)
> return false;
> return true;
> --
> 2.48.1.502.g6dc24dfdaf-goog
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
next prev parent reply other threads:[~2025-02-13 18:01 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-12 7:52 [PATCH] f2fs: fix to avoid accessing uninitialized curseg Chao Yu
2025-02-12 7:52 ` [f2fs-dev] " Chao Yu via Linux-f2fs-devel
2025-02-13 18:01 ` Jaegeuk Kim [this message]
2025-02-13 18:01 ` Jaegeuk Kim via Linux-f2fs-devel
2025-02-14 1:35 ` Chao Yu
2025-02-14 1:35 ` [f2fs-dev] " Chao Yu via Linux-f2fs-devel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z64zcac0_dw1_rML@google.com \
--to=jaegeuk@kernel.org \
--cc=chao@kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=syzbot+b6b347b7a4ea1b2e29b6@syzkaller.appspotmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.