]>
Commit | Line | Data |
---|---|---|
37554d48 SL |
1 | From ffcd55ace4fbcadc6781160828c066432ead4156 Mon Sep 17 00:00:00 2001 |
2 | From: Chao Yu <yuchao0@huawei.com> | |
3 | Date: Mon, 15 Apr 2019 15:28:34 +0800 | |
4 | Subject: f2fs: fix to avoid panic in f2fs_remove_inode_page() | |
5 | ||
6 | [ Upstream commit 8b6810f8acfe429fde7c7dad4714692cc5f75651 ] | |
7 | ||
8 | As Jungyeon reported in bugzilla: | |
9 | ||
10 | https://bugzilla.kernel.org/show_bug.cgi?id=203219 | |
11 | ||
12 | - Overview | |
13 | When mounting the attached crafted image and running program, I got this error. | |
14 | Additionally, it hangs on sync after running the program. | |
15 | ||
16 | The image is intentionally fuzzed from a normal f2fs image for testing and I enabled option CONFIG_F2FS_CHECK_FS on. | |
17 | ||
18 | - Reproduces | |
19 | cc poc_06.c | |
20 | mkdir test | |
21 | mount -t f2fs tmp.img test | |
22 | cp a.out test | |
23 | cd test | |
24 | sudo ./a.out | |
25 | sync | |
26 | ||
27 | - Messages | |
28 | kernel BUG at fs/f2fs/node.c:1183! | |
29 | RIP: 0010:f2fs_remove_inode_page+0x294/0x2d0 | |
30 | Call Trace: | |
31 | f2fs_evict_inode+0x2a3/0x3a0 | |
32 | evict+0xba/0x180 | |
33 | __dentry_kill+0xbe/0x160 | |
34 | dentry_kill+0x46/0x180 | |
35 | dput+0xbb/0x100 | |
36 | do_renameat2+0x3c9/0x550 | |
37 | __x64_sys_rename+0x17/0x20 | |
38 | do_syscall_64+0x43/0xf0 | |
39 | entry_SYSCALL_64_after_hwframe+0x44/0xa9 | |
40 | ||
41 | The reason is f2fs_remove_inode_page() will trigger kernel panic due to | |
42 | inconsistent i_blocks value of inode. | |
43 | ||
44 | To avoid panic, let's just print debug message and set SBI_NEED_FSCK to | |
45 | give a hint to fsck for latter repairing of potential image corruption. | |
46 | ||
47 | Signed-off-by: Chao Yu <yuchao0@huawei.com> | |
48 | [Jaegeuk Kim: fix build warning and add unlikely] | |
49 | Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> | |
50 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
51 | --- | |
52 | fs/f2fs/node.c | 10 ++++++++-- | |
53 | 1 file changed, 8 insertions(+), 2 deletions(-) | |
54 | ||
55 | diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c | |
56 | index 19a0d83aae65..807a77518a49 100644 | |
57 | --- a/fs/f2fs/node.c | |
58 | +++ b/fs/f2fs/node.c | |
59 | @@ -1180,8 +1180,14 @@ int f2fs_remove_inode_page(struct inode *inode) | |
60 | f2fs_put_dnode(&dn); | |
61 | return -EIO; | |
62 | } | |
63 | - f2fs_bug_on(F2FS_I_SB(inode), | |
64 | - inode->i_blocks != 0 && inode->i_blocks != 8); | |
65 | + | |
66 | + if (unlikely(inode->i_blocks != 0 && inode->i_blocks != 8)) { | |
67 | + f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING, | |
68 | + "Inconsistent i_blocks, ino:%lu, iblocks:%llu", | |
69 | + inode->i_ino, | |
70 | + (unsigned long long)inode->i_blocks); | |
71 | + set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK); | |
72 | + } | |
73 | ||
74 | /* will put inode & node pages */ | |
75 | err = truncate_node(&dn); | |
76 | -- | |
77 | 2.20.1 | |
78 |