Skip to content

Commit 855c54f

Browse files
chaseyugregkh
authored andcommitted
f2fs: fix to do sanity check on node footer in {read,write}_end_io
[ Upstream commit 50ac3ec ] -----------[ cut here ]------------ kernel BUG at fs/f2fs/data.c:358! Call Trace: <IRQ> blk_update_request+0x5eb/0xe70 block/blk-mq.c:987 blk_mq_end_request+0x3e/0x70 block/blk-mq.c:1149 blk_complete_reqs block/blk-mq.c:1224 [inline] blk_done_softirq+0x107/0x160 block/blk-mq.c:1229 handle_softirqs+0x283/0x870 kernel/softirq.c:579 __do_softirq kernel/softirq.c:613 [inline] invoke_softirq kernel/softirq.c:453 [inline] __irq_exit_rcu+0xca/0x1f0 kernel/softirq.c:680 irq_exit_rcu+0x9/0x30 kernel/softirq.c:696 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1050 [inline] sysvec_apic_timer_interrupt+0xa6/0xc0 arch/x86/kernel/apic/apic.c:1050 </IRQ> In f2fs_write_end_io(), it detects there is inconsistency in between node page index (nid) and footer.nid of node page. If footer of node page is corrupted in fuzzed image, then we load corrupted node page w/ async method, e.g. f2fs_ra_node_pages() or f2fs_ra_node_page(), in where we won't do sanity check on node footer, once node page becomes dirty, we will encounter this bug after node page writeback. Cc: stable@kernel.org Reported-by: syzbot+803dd716c4310d16ff3a@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=803dd716c4310d16ff3a Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> [ Context ] Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cd2fec9 commit 855c54f

4 files changed

Lines changed: 34 additions & 19 deletions

File tree

fs/f2fs/data.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
151151
}
152152

153153
dec_page_count(F2FS_F_SB(folio), __read_io_type(folio));
154+
155+
if (F2FS_F_SB(folio)->node_inode && is_node_folio(folio) &&
156+
f2fs_sanity_check_node_footer(F2FS_F_SB(folio),
157+
folio, folio->index, NODE_TYPE_REGULAR, true))
158+
bio->bi_status = BLK_STS_IOERR;
159+
154160
folio_end_read(folio, bio->bi_status == BLK_STS_OK);
155161
}
156162

@@ -352,8 +358,11 @@ static void f2fs_write_end_io(struct bio *bio)
352358
STOP_CP_REASON_WRITE_FAIL);
353359
}
354360

355-
f2fs_bug_on(sbi, is_node_folio(folio) &&
356-
folio->index != nid_of_node(folio));
361+
if (is_node_folio(folio)) {
362+
f2fs_sanity_check_node_footer(sbi, folio,
363+
folio->index, NODE_TYPE_REGULAR, true);
364+
f2fs_bug_on(sbi, folio->index != nid_of_node(folio));
365+
}
357366

358367
dec_page_count(sbi, type);
359368

fs/f2fs/f2fs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,15 @@ enum f2fs_lookup_mode {
15161516
LOOKUP_AUTO,
15171517
};
15181518

1519+
/* For node type in __get_node_folio() */
1520+
enum node_type {
1521+
NODE_TYPE_REGULAR,
1522+
NODE_TYPE_INODE,
1523+
NODE_TYPE_XATTR,
1524+
NODE_TYPE_NON_INODE,
1525+
};
1526+
1527+
15191528
static inline int f2fs_test_bit(unsigned int nr, char *addr);
15201529
static inline void f2fs_set_bit(unsigned int nr, char *addr);
15211530
static inline void f2fs_clear_bit(unsigned int nr, char *addr);
@@ -3874,6 +3883,9 @@ struct folio *f2fs_new_node_folio(struct dnode_of_data *dn, unsigned int ofs);
38743883
void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
38753884
struct folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid,
38763885
enum node_type node_type);
3886+
int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,
3887+
struct folio *folio, pgoff_t nid,
3888+
enum node_type ntype, bool in_irq);
38773889
struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino);
38783890
struct folio *f2fs_get_xnode_folio(struct f2fs_sb_info *sbi, pgoff_t xnid);
38793891
int f2fs_move_node_folio(struct folio *node_folio, int gc_type);

fs/f2fs/node.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,9 +1500,9 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
15001500
f2fs_folio_put(afolio, err ? true : false);
15011501
}
15021502

1503-
static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
1503+
int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,
15041504
struct folio *folio, pgoff_t nid,
1505-
enum node_type ntype)
1505+
enum node_type ntype, bool in_irq)
15061506
{
15071507
if (unlikely(nid != nid_of_node(folio)))
15081508
goto out_err;
@@ -1527,12 +1527,13 @@ static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
15271527
goto out_err;
15281528
return 0;
15291529
out_err:
1530-
f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
1531-
"node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
1532-
ntype, nid, nid_of_node(folio), ino_of_node(folio),
1533-
ofs_of_node(folio), cpver_of_node(folio),
1534-
next_blkaddr_of_node(folio));
15351530
set_sbi_flag(sbi, SBI_NEED_FSCK);
1531+
f2fs_warn_ratelimited(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
1532+
"node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
1533+
ntype, nid, nid_of_node(folio), ino_of_node(folio),
1534+
ofs_of_node(folio), cpver_of_node(folio),
1535+
next_blkaddr_of_node(folio));
1536+
15361537
f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER);
15371538
return -EFSCORRUPTED;
15381539
}
@@ -1578,7 +1579,7 @@ static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid,
15781579
goto out_err;
15791580
}
15801581
page_hit:
1581-
err = sanity_check_node_footer(sbi, folio, nid, ntype);
1582+
err = f2fs_sanity_check_node_footer(sbi, folio, nid, ntype, false);
15821583
if (!err)
15831584
return folio;
15841585
out_err:
@@ -1752,7 +1753,8 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
17521753
/* get old block addr of this node page */
17531754
nid = nid_of_node(folio);
17541755

1755-
if (sanity_check_node_footer(sbi, folio, nid, NODE_TYPE_REGULAR)) {
1756+
if (f2fs_sanity_check_node_footer(sbi, folio, nid,
1757+
NODE_TYPE_REGULAR, false)) {
17561758
f2fs_handle_critical_error(sbi, STOP_CP_REASON_CORRUPTED_NID);
17571759
goto redirty_out;
17581760
}

fs/f2fs/node.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,6 @@ enum {
5252
IS_PREALLOC, /* nat entry is preallocated */
5353
};
5454

55-
/* For node type in __get_node_folio() */
56-
enum node_type {
57-
NODE_TYPE_REGULAR,
58-
NODE_TYPE_INODE,
59-
NODE_TYPE_XATTR,
60-
NODE_TYPE_NON_INODE,
61-
};
62-
6355
/*
6456
* For node information
6557
*/

0 commit comments

Comments
 (0)