]>
Commit | Line | Data |
---|---|---|
c2a518a0 GKH |
1 | From foo@baz Fri Jan 18 09:16:11 CET 2019 |
2 | From: Chao Yu <yuchao0@huawei.com> | |
3 | Date: Thu, 2 Aug 2018 22:59:12 +0800 | |
4 | Subject: f2fs: fix invalid memory access | |
5 | ||
6 | From: Chao Yu <yuchao0@huawei.com> | |
7 | ||
8 | commit d3f07c049dab1a3f1740f476afd3d5e5b738c21c upstream. | |
9 | ||
10 | syzbot found the following crash on: | |
11 | ||
12 | HEAD commit: d9bd94c0bcaa Add linux-next specific files for 20180801 | |
13 | git tree: linux-next | |
14 | console output: https://syzkaller.appspot.com/x/log.txt?x=1001189c400000 | |
15 | kernel config: https://syzkaller.appspot.com/x/.config?x=cc8964ea4d04518c | |
16 | dashboard link: https://syzkaller.appspot.com/bug?extid=c966a82db0b14aa37e81 | |
17 | compiler: gcc (GCC) 8.0.1 20180413 (experimental) | |
18 | ||
19 | Unfortunately, I don't have any reproducer for this crash yet. | |
20 | ||
21 | IMPORTANT: if you fix the bug, please add the following tag to the commit: | |
22 | Reported-by: syzbot+c966a82db0b14aa37e81@syzkaller.appspotmail.com | |
23 | ||
24 | loop7: rw=12288, want=8200, limit=20 | |
25 | netlink: 65342 bytes leftover after parsing attributes in process `syz-executor4'. | |
26 | openvswitch: netlink: Message has 8 unknown bytes. | |
27 | kasan: CONFIG_KASAN_INLINE enabled | |
28 | kasan: GPF could be caused by NULL-ptr deref or user memory access | |
29 | general protection fault: 0000 [#1] SMP KASAN | |
30 | CPU: 1 PID: 7615 Comm: syz-executor7 Not tainted 4.18.0-rc7-next-20180801+ #29 | |
31 | Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 | |
32 | RIP: 0010:__read_once_size include/linux/compiler.h:188 [inline] | |
33 | RIP: 0010:compound_head include/linux/page-flags.h:142 [inline] | |
34 | RIP: 0010:PageLocked include/linux/page-flags.h:272 [inline] | |
35 | RIP: 0010:f2fs_put_page fs/f2fs/f2fs.h:2011 [inline] | |
36 | RIP: 0010:validate_checkpoint+0x66d/0xec0 fs/f2fs/checkpoint.c:835 | |
37 | Code: e8 58 05 7f fe 4c 8d 6b 80 4d 8d 74 24 08 48 b8 00 00 00 00 00 fc ff df 4c 89 ea 48 c1 ea 03 c6 04 02 00 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 f4 06 00 00 4c 89 ea 4d 8b 7c 24 08 48 b8 00 00 | |
38 | RSP: 0018:ffff8801937cebe8 EFLAGS: 00010246 | |
39 | RAX: dffffc0000000000 RBX: ffff8801937cef30 RCX: ffffc90006035000 | |
40 | RDX: 0000000000000000 RSI: ffffffff82fd9658 RDI: 0000000000000005 | |
41 | RBP: ffff8801937cef58 R08: ffff8801ab254700 R09: fffff94000d9e026 | |
42 | R10: fffff94000d9e026 R11: ffffea0006cf0137 R12: fffffffffffffffb | |
43 | R13: ffff8801937ceeb0 R14: 0000000000000003 R15: ffff880193419b40 | |
44 | FS: 00007f36a61d5700(0000) GS:ffff8801db100000(0000) knlGS:0000000000000000 | |
45 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | |
46 | CR2: 00007fc04ff93000 CR3: 00000001d0562000 CR4: 00000000001426e0 | |
47 | DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | |
48 | DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | |
49 | Call Trace: | |
50 | f2fs_get_valid_checkpoint+0x436/0x1ec0 fs/f2fs/checkpoint.c:860 | |
51 | f2fs_fill_super+0x2d42/0x8110 fs/f2fs/super.c:2883 | |
52 | mount_bdev+0x314/0x3e0 fs/super.c:1344 | |
53 | f2fs_mount+0x3c/0x50 fs/f2fs/super.c:3133 | |
54 | legacy_get_tree+0x131/0x460 fs/fs_context.c:729 | |
55 | vfs_get_tree+0x1cb/0x5c0 fs/super.c:1743 | |
56 | do_new_mount fs/namespace.c:2603 [inline] | |
57 | do_mount+0x6f2/0x1e20 fs/namespace.c:2927 | |
58 | ksys_mount+0x12d/0x140 fs/namespace.c:3143 | |
59 | __do_sys_mount fs/namespace.c:3157 [inline] | |
60 | __se_sys_mount fs/namespace.c:3154 [inline] | |
61 | __x64_sys_mount+0xbe/0x150 fs/namespace.c:3154 | |
62 | do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 | |
63 | entry_SYSCALL_64_after_hwframe+0x49/0xbe | |
64 | RIP: 0033:0x45943a | |
65 | Code: b8 a6 00 00 00 0f 05 48 3d 01 f0 ff ff 0f 83 bd 8a fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 0f 83 9a 8a fb ff c3 66 0f 1f 84 00 00 00 00 00 | |
66 | RSP: 002b:00007f36a61d4a88 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5 | |
67 | RAX: ffffffffffffffda RBX: 00007f36a61d4b30 RCX: 000000000045943a | |
68 | RDX: 00007f36a61d4ad0 RSI: 0000000020000100 RDI: 00007f36a61d4af0 | |
69 | RBP: 0000000020000100 R08: 00007f36a61d4b30 R09: 00007f36a61d4ad0 | |
70 | R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000013 | |
71 | R13: 0000000000000000 R14: 00000000004c8ea0 R15: 0000000000000000 | |
72 | Modules linked in: | |
73 | Dumping ftrace buffer: | |
74 | (ftrace buffer empty) | |
75 | ---[ end trace bd8550c129352286 ]--- | |
76 | RIP: 0010:__read_once_size include/linux/compiler.h:188 [inline] | |
77 | RIP: 0010:compound_head include/linux/page-flags.h:142 [inline] | |
78 | RIP: 0010:PageLocked include/linux/page-flags.h:272 [inline] | |
79 | RIP: 0010:f2fs_put_page fs/f2fs/f2fs.h:2011 [inline] | |
80 | RIP: 0010:validate_checkpoint+0x66d/0xec0 fs/f2fs/checkpoint.c:835 | |
81 | Code: e8 58 05 7f fe 4c 8d 6b 80 4d 8d 74 24 08 48 b8 00 00 00 00 00 fc ff df 4c 89 ea 48 c1 ea 03 c6 04 02 00 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 f4 06 00 00 4c 89 ea 4d 8b 7c 24 08 48 b8 00 00 | |
82 | RSP: 0018:ffff8801937cebe8 EFLAGS: 00010246 | |
83 | RAX: dffffc0000000000 RBX: ffff8801937cef30 RCX: ffffc90006035000 | |
84 | RDX: 0000000000000000 RSI: ffffffff82fd9658 RDI: 0000000000000005 | |
85 | netlink: 65342 bytes leftover after parsing attributes in process `syz-executor4'. | |
86 | RBP: ffff8801937cef58 R08: ffff8801ab254700 R09: fffff94000d9e026 | |
87 | openvswitch: netlink: Message has 8 unknown bytes. | |
88 | R10: fffff94000d9e026 R11: ffffea0006cf0137 R12: fffffffffffffffb | |
89 | R13: ffff8801937ceeb0 R14: 0000000000000003 R15: ffff880193419b40 | |
90 | FS: 00007f36a61d5700(0000) GS:ffff8801db100000(0000) knlGS:0000000000000000 | |
91 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | |
92 | CR2: 00007fc04ff93000 CR3: 00000001d0562000 CR4: 00000000001426e0 | |
93 | DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | |
94 | DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | |
95 | ||
96 | In validate_checkpoint(), if we failed to call get_checkpoint_version(), we | |
97 | will pass returned invalid page pointer into f2fs_put_page, cause accessing | |
98 | invalid memory, this patch tries to handle error path correctly to fix this | |
99 | issue. | |
100 | ||
101 | Signed-off-by: Chao Yu <yuchao0@huawei.com> | |
102 | ||
103 | Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> | |
104 | [bwh: Backported to 4.4: adjust context] | |
105 | Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk> | |
106 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
107 | --- | |
108 | fs/f2fs/checkpoint.c | 11 ++++++----- | |
109 | 1 file changed, 6 insertions(+), 5 deletions(-) | |
110 | ||
111 | --- a/fs/f2fs/checkpoint.c | |
112 | +++ b/fs/f2fs/checkpoint.c | |
113 | @@ -631,6 +631,7 @@ static int get_checkpoint_version(struct | |
114 | ||
115 | crc_offset = le32_to_cpu((*cp_block)->checksum_offset); | |
116 | if (crc_offset >= blk_size) { | |
117 | + f2fs_put_page(*cp_page, 1); | |
118 | f2fs_msg(sbi->sb, KERN_WARNING, | |
119 | "invalid crc_offset: %zu", crc_offset); | |
120 | return -EINVAL; | |
121 | @@ -639,6 +640,7 @@ static int get_checkpoint_version(struct | |
122 | crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block | |
123 | + crc_offset))); | |
124 | if (!f2fs_crc_valid(crc, *cp_block, crc_offset)) { | |
125 | + f2fs_put_page(*cp_page, 1); | |
126 | f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value"); | |
127 | return -EINVAL; | |
128 | } | |
129 | @@ -658,14 +660,14 @@ static struct page *validate_checkpoint( | |
130 | err = get_checkpoint_version(sbi, cp_addr, &cp_block, | |
131 | &cp_page_1, version); | |
132 | if (err) | |
133 | - goto invalid_cp1; | |
134 | + return NULL; | |
135 | ||
136 | if (le32_to_cpu(cp_block->cp_pack_total_block_count) > | |
137 | sbi->blocks_per_seg) { | |
138 | f2fs_msg(sbi->sb, KERN_WARNING, | |
139 | "invalid cp_pack_total_block_count:%u", | |
140 | le32_to_cpu(cp_block->cp_pack_total_block_count)); | |
141 | - goto invalid_cp1; | |
142 | + goto invalid_cp; | |
143 | } | |
144 | pre_version = *version; | |
145 | ||
146 | @@ -673,7 +675,7 @@ static struct page *validate_checkpoint( | |
147 | err = get_checkpoint_version(sbi, cp_addr, &cp_block, | |
148 | &cp_page_2, version); | |
149 | if (err) | |
150 | - goto invalid_cp2; | |
151 | + goto invalid_cp; | |
152 | cur_version = *version; | |
153 | ||
154 | if (cur_version == pre_version) { | |
155 | @@ -681,9 +683,8 @@ static struct page *validate_checkpoint( | |
156 | f2fs_put_page(cp_page_2, 1); | |
157 | return cp_page_1; | |
158 | } | |
159 | -invalid_cp2: | |
160 | f2fs_put_page(cp_page_2, 1); | |
161 | -invalid_cp1: | |
162 | +invalid_cp: | |
163 | f2fs_put_page(cp_page_1, 1); | |
164 | return NULL; | |
165 | } |