]>
Commit | Line | Data |
---|---|---|
37554d48 SL |
1 | From eedd336d32ec9fda7f26d7883ade55484965b3cc Mon Sep 17 00:00:00 2001 |
2 | From: Chao Yu <yuchao0@huawei.com> | |
3 | Date: Mon, 15 Apr 2019 15:28:35 +0800 | |
4 | Subject: f2fs: fix to do checksum even if inode page is uptodate | |
5 | ||
6 | [ Upstream commit b42b179bda9ff11075a6fc2bac4d9e400513679a ] | |
7 | ||
8 | As Jungyeon reported in bugzilla: | |
9 | ||
10 | https://bugzilla.kernel.org/show_bug.cgi?id=203221 | |
11 | ||
12 | - Overview | |
13 | When mounting the attached crafted image and running program, this error is reported. | |
14 | ||
15 | The image is intentionally fuzzed from a normal f2fs image for testing and I enabled option CONFIG_F2FS_CHECK_FS on. | |
16 | ||
17 | - Reproduces | |
18 | cc poc_07.c | |
19 | mkdir test | |
20 | mount -t f2fs tmp.img test | |
21 | cp a.out test | |
22 | cd test | |
23 | sudo ./a.out | |
24 | ||
25 | - Messages | |
26 | kernel BUG at fs/f2fs/node.c:1279! | |
27 | RIP: 0010:read_node_page+0xcf/0xf0 | |
28 | Call Trace: | |
29 | __get_node_page+0x6b/0x2f0 | |
30 | f2fs_iget+0x8f/0xdf0 | |
31 | f2fs_lookup+0x136/0x320 | |
32 | __lookup_slow+0x92/0x140 | |
33 | lookup_slow+0x30/0x50 | |
34 | walk_component+0x1c1/0x350 | |
35 | path_lookupat+0x62/0x200 | |
36 | filename_lookup+0xb3/0x1a0 | |
37 | do_fchmodat+0x3e/0xa0 | |
38 | __x64_sys_chmod+0x12/0x20 | |
39 | do_syscall_64+0x43/0xf0 | |
40 | entry_SYSCALL_64_after_hwframe+0x44/0xa9 | |
41 | ||
42 | On below paths, we can have opportunity to readahead inode page | |
43 | - gc_node_segment -> f2fs_ra_node_page | |
44 | - gc_data_segment -> f2fs_ra_node_page | |
45 | - f2fs_fill_dentries -> f2fs_ra_node_page | |
46 | ||
47 | Unlike synchronized read, on readahead path, we can set page uptodate | |
48 | before verifying page's checksum, then read_node_page() will trigger | |
49 | kernel panic once it encounters a uptodated page w/ incorrect checksum. | |
50 | ||
51 | So considering readahead scenario, we have to do checksum each time | |
52 | when loading inode page even if it is uptodated. | |
53 | ||
54 | Signed-off-by: Chao Yu <yuchao0@huawei.com> | |
55 | Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> | |
56 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
57 | --- | |
58 | fs/f2fs/inode.c | 4 ++-- | |
59 | fs/f2fs/node.c | 7 ++++--- | |
60 | 2 files changed, 6 insertions(+), 5 deletions(-) | |
61 | ||
62 | diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c | |
63 | index fae9570e6860..0f31df01e36c 100644 | |
64 | --- a/fs/f2fs/inode.c | |
65 | +++ b/fs/f2fs/inode.c | |
66 | @@ -179,8 +179,8 @@ bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page) | |
67 | ||
68 | if (provided != calculated) | |
69 | f2fs_msg(sbi->sb, KERN_WARNING, | |
70 | - "checksum invalid, ino = %x, %x vs. %x", | |
71 | - ino_of_node(page), provided, calculated); | |
72 | + "checksum invalid, nid = %lu, ino_of_node = %x, %x vs. %x", | |
73 | + page->index, ino_of_node(page), provided, calculated); | |
74 | ||
75 | return provided == calculated; | |
76 | } | |
77 | diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c | |
78 | index 34c3f732601c..e2d9edad758c 100644 | |
79 | --- a/fs/f2fs/node.c | |
80 | +++ b/fs/f2fs/node.c | |
81 | @@ -1282,9 +1282,10 @@ static int read_node_page(struct page *page, int op_flags) | |
82 | int err; | |
83 | ||
84 | if (PageUptodate(page)) { | |
85 | -#ifdef CONFIG_F2FS_CHECK_FS | |
86 | - f2fs_bug_on(sbi, !f2fs_inode_chksum_verify(sbi, page)); | |
87 | -#endif | |
88 | + if (!f2fs_inode_chksum_verify(sbi, page)) { | |
89 | + ClearPageUptodate(page); | |
90 | + return -EBADMSG; | |
91 | + } | |
92 | return LOCKED_PAGE; | |
93 | } | |
94 | ||
95 | -- | |
96 | 2.20.1 | |
97 |