Skip to content

Commit 50ac3ec

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix to do sanity check on node footer in {read,write}_end_io
-----------[ 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>
1 parent 0a73610 commit 50ac3ec

4 files changed

Lines changed: 32 additions & 19 deletions

File tree

fs/f2fs/data.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
172172
while (nr_pages--)
173173
dec_page_count(F2FS_F_SB(folio), __read_io_type(folio));
174174

175+
if (F2FS_F_SB(folio)->node_inode && is_node_folio(folio) &&
176+
f2fs_sanity_check_node_footer(F2FS_F_SB(folio),
177+
folio, folio->index, NODE_TYPE_REGULAR, true))
178+
bio->bi_status = BLK_STS_IOERR;
179+
175180
if (finished)
176181
folio_end_read(folio, bio->bi_status == BLK_STS_OK);
177182
}
@@ -374,8 +379,11 @@ static void f2fs_write_end_io(struct bio *bio)
374379
STOP_CP_REASON_WRITE_FAIL);
375380
}
376381

377-
f2fs_bug_on(sbi, is_node_folio(folio) &&
378-
folio->index != nid_of_node(folio));
382+
if (is_node_folio(folio)) {
383+
f2fs_sanity_check_node_footer(sbi, folio,
384+
folio->index, NODE_TYPE_REGULAR, true);
385+
f2fs_bug_on(sbi, folio->index != nid_of_node(folio));
386+
}
379387

380388
dec_page_count(sbi, type);
381389

fs/f2fs/f2fs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,14 @@ enum f2fs_lookup_mode {
15721572
LOOKUP_AUTO,
15731573
};
15741574

1575+
/* For node type in __get_node_folio() */
1576+
enum node_type {
1577+
NODE_TYPE_REGULAR,
1578+
NODE_TYPE_INODE,
1579+
NODE_TYPE_XATTR,
1580+
NODE_TYPE_NON_INODE,
1581+
};
1582+
15751583
/* a threshold of maximum elapsed time in critical region to print tracepoint */
15761584
#define MAX_LOCK_ELAPSED_TIME 500
15771585

@@ -3915,6 +3923,9 @@ struct folio *f2fs_new_node_folio(struct dnode_of_data *dn, unsigned int ofs);
39153923
void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
39163924
struct folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid,
39173925
enum node_type node_type);
3926+
int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,
3927+
struct folio *folio, pgoff_t nid,
3928+
enum node_type ntype, bool in_irq);
39183929
struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino);
39193930
struct folio *f2fs_get_xnode_folio(struct f2fs_sb_info *sbi, pgoff_t xnid);
39203931
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
@@ -1511,9 +1511,9 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
15111511
f2fs_folio_put(afolio, err ? true : false);
15121512
}
15131513

1514-
static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
1514+
int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,
15151515
struct folio *folio, pgoff_t nid,
1516-
enum node_type ntype)
1516+
enum node_type ntype, bool in_irq)
15171517
{
15181518
if (unlikely(nid != nid_of_node(folio)))
15191519
goto out_err;
@@ -1538,12 +1538,13 @@ static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
15381538
goto out_err;
15391539
return 0;
15401540
out_err:
1541-
f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
1542-
"node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
1543-
ntype, nid, nid_of_node(folio), ino_of_node(folio),
1544-
ofs_of_node(folio), cpver_of_node(folio),
1545-
next_blkaddr_of_node(folio));
15461541
set_sbi_flag(sbi, SBI_NEED_FSCK);
1542+
f2fs_warn_ratelimited(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
1543+
"node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
1544+
ntype, nid, nid_of_node(folio), ino_of_node(folio),
1545+
ofs_of_node(folio), cpver_of_node(folio),
1546+
next_blkaddr_of_node(folio));
1547+
15471548
f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER);
15481549
return -EFSCORRUPTED;
15491550
}
@@ -1589,7 +1590,7 @@ static struct folio *__get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid,
15891590
goto out_err;
15901591
}
15911592
page_hit:
1592-
err = sanity_check_node_footer(sbi, folio, nid, ntype);
1593+
err = f2fs_sanity_check_node_footer(sbi, folio, nid, ntype, false);
15931594
if (!err)
15941595
return folio;
15951596
out_err:
@@ -1764,7 +1765,8 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
17641765
/* get old block addr of this node page */
17651766
nid = nid_of_node(folio);
17661767

1767-
if (sanity_check_node_footer(sbi, folio, nid, NODE_TYPE_REGULAR)) {
1768+
if (f2fs_sanity_check_node_footer(sbi, folio, nid,
1769+
NODE_TYPE_REGULAR, false)) {
17681770
f2fs_handle_critical_error(sbi, STOP_CP_REASON_CORRUPTED_NID);
17691771
goto redirty_out;
17701772
}

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)