tree-checker.c (c1499166d10ae734b5ec5cc7982bd9b9ee7f9fe6) tree-checker.c (80d7fd1e09822daf8d94d46c6f9a17e7e34cf0b4)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) Qu Wenruo 2017. All rights reserved.
4 */
5
6/*
7 * The module is used to catch unexpected/corrupted tree block data.
8 * Such behavior can be caused either by a fuzzed image or bugs.

--- 111 unchanged lines hidden (view full) ---

120 end = ALIGN(key->offset + len, leaf->fs_info->sectorsize);
121 } else {
122 len = btrfs_file_extent_num_bytes(leaf, extent);
123 end = key->offset + len;
124 }
125 return end;
126}
127
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) Qu Wenruo 2017. All rights reserved.
4 */
5
6/*
7 * The module is used to catch unexpected/corrupted tree block data.
8 * Such behavior can be caused either by a fuzzed image or bugs.

--- 111 unchanged lines hidden (view full) ---

120 end = ALIGN(key->offset + len, leaf->fs_info->sectorsize);
121 } else {
122 len = btrfs_file_extent_num_bytes(leaf, extent);
123 end = key->offset + len;
124 }
125 return end;
126}
127
128/*
129 * Customized report for dir_item, the only new important information is
130 * key->objectid, which represents inode number
131 */
132__printf(3, 4)
133__cold
134static void dir_item_err(const struct extent_buffer *eb, int slot,
135 const char *fmt, ...)
136{
137 const struct btrfs_fs_info *fs_info = eb->fs_info;
138 struct btrfs_key key;
139 struct va_format vaf;
140 va_list args;
141
142 btrfs_item_key_to_cpu(eb, &key, slot);
143 va_start(args, fmt);
144
145 vaf.fmt = fmt;
146 vaf.va = &args;
147
148 btrfs_crit(fs_info,
149 "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
150 btrfs_header_level(eb) == 0 ? "leaf" : "node",
151 btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
152 key.objectid, &vaf);
153 va_end(args);
154}
155
156/*
157 * This functions checks prev_key->objectid, to ensure current key and prev_key
158 * share the same objectid as inode number.
159 *
160 * This is to detect missing INODE_ITEM in subvolume trees.
161 *
162 * Return true if everything is OK or we don't need to check.
163 * Return false if anything is wrong.
164 */
165static bool check_prev_ino(struct extent_buffer *leaf,
166 struct btrfs_key *key, int slot,
167 struct btrfs_key *prev_key)
168{
169 /* No prev key, skip check */
170 if (slot == 0)
171 return true;
172
173 /* Only these key->types needs to be checked */
174 ASSERT(key->type == BTRFS_XATTR_ITEM_KEY ||
175 key->type == BTRFS_INODE_REF_KEY ||
176 key->type == BTRFS_DIR_INDEX_KEY ||
177 key->type == BTRFS_DIR_ITEM_KEY ||
178 key->type == BTRFS_EXTENT_DATA_KEY);
179
180 /*
181 * Only subvolume trees along with their reloc trees need this check.
182 * Things like log tree doesn't follow this ino requirement.
183 */
184 if (!is_fstree(btrfs_header_owner(leaf)))
185 return true;
186
187 if (key->objectid == prev_key->objectid)
188 return true;
189
190 /* Error found */
191 dir_item_err(leaf, slot,
192 "invalid previous key objectid, have %llu expect %llu",
193 prev_key->objectid, key->objectid);
194 return false;
195}
128static int check_extent_data_item(struct extent_buffer *leaf,
129 struct btrfs_key *key, int slot,
130 struct btrfs_key *prev_key)
131{
132 struct btrfs_fs_info *fs_info = leaf->fs_info;
133 struct btrfs_file_extent_item *fi;
134 u32 sectorsize = fs_info->sectorsize;
135 u32 item_size = btrfs_item_size_nr(leaf, slot);

--- 7 unchanged lines hidden (view full) ---

143 }
144
145 /*
146 * Previous key must have the same key->objectid (ino).
147 * It can be XATTR_ITEM, INODE_ITEM or just another EXTENT_DATA.
148 * But if objectids mismatch, it means we have a missing
149 * INODE_ITEM.
150 */
196static int check_extent_data_item(struct extent_buffer *leaf,
197 struct btrfs_key *key, int slot,
198 struct btrfs_key *prev_key)
199{
200 struct btrfs_fs_info *fs_info = leaf->fs_info;
201 struct btrfs_file_extent_item *fi;
202 u32 sectorsize = fs_info->sectorsize;
203 u32 item_size = btrfs_item_size_nr(leaf, slot);

--- 7 unchanged lines hidden (view full) ---

211 }
212
213 /*
214 * Previous key must have the same key->objectid (ino).
215 * It can be XATTR_ITEM, INODE_ITEM or just another EXTENT_DATA.
216 * But if objectids mismatch, it means we have a missing
217 * INODE_ITEM.
218 */
151 if (slot > 0 && is_fstree(btrfs_header_owner(leaf)) &&
152 prev_key->objectid != key->objectid) {
153 file_extent_err(leaf, slot,
154 "invalid previous key objectid, have %llu expect %llu",
155 prev_key->objectid, key->objectid);
219 if (!check_prev_ino(leaf, key, slot, prev_key))
156 return -EUCLEAN;
220 return -EUCLEAN;
157 }
158
159 fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
160
161 if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
162 file_extent_err(leaf, slot,
163 "invalid type for file extent, have %u expect range [0, %u]",
164 btrfs_file_extent_type(leaf, fi),
165 BTRFS_FILE_EXTENT_TYPES);

--- 114 unchanged lines hidden (view full) ---

280 generic_err(leaf, slot,
281 "unaligned item size for csum item, have %u should be aligned to %u",
282 btrfs_item_size_nr(leaf, slot), csumsize);
283 return -EUCLEAN;
284 }
285 return 0;
286}
287
221
222 fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
223
224 if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
225 file_extent_err(leaf, slot,
226 "invalid type for file extent, have %u expect range [0, %u]",
227 btrfs_file_extent_type(leaf, fi),
228 BTRFS_FILE_EXTENT_TYPES);

--- 114 unchanged lines hidden (view full) ---

343 generic_err(leaf, slot,
344 "unaligned item size for csum item, have %u should be aligned to %u",
345 btrfs_item_size_nr(leaf, slot), csumsize);
346 return -EUCLEAN;
347 }
348 return 0;
349}
350
288/*
289 * Customized reported for dir_item, only important new info is key->objectid,
290 * which represents inode number
291 */
292__printf(3, 4)
293__cold
294static void dir_item_err(const struct extent_buffer *eb, int slot,
295 const char *fmt, ...)
296{
297 const struct btrfs_fs_info *fs_info = eb->fs_info;
298 struct btrfs_key key;
299 struct va_format vaf;
300 va_list args;
301
302 btrfs_item_key_to_cpu(eb, &key, slot);
303 va_start(args, fmt);
304
305 vaf.fmt = fmt;
306 vaf.va = &args;
307
308 btrfs_crit(fs_info,
309 "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
310 btrfs_header_level(eb) == 0 ? "leaf" : "node",
311 btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
312 key.objectid, &vaf);
313 va_end(args);
314}
315
316static int check_dir_item(struct extent_buffer *leaf,
317 struct btrfs_key *key, struct btrfs_key *prev_key,
318 int slot)
319{
320 struct btrfs_fs_info *fs_info = leaf->fs_info;
321 struct btrfs_dir_item *di;
322 u32 item_size = btrfs_item_size_nr(leaf, slot);
323 u32 cur = 0;
324
351static int check_dir_item(struct extent_buffer *leaf,
352 struct btrfs_key *key, struct btrfs_key *prev_key,
353 int slot)
354{
355 struct btrfs_fs_info *fs_info = leaf->fs_info;
356 struct btrfs_dir_item *di;
357 u32 item_size = btrfs_item_size_nr(leaf, slot);
358 u32 cur = 0;
359
325 /* Same check as in check_extent_data_item() */
326 if (slot > 0 && is_fstree(btrfs_header_owner(leaf)) &&
327 prev_key->objectid != key->objectid) {
328 dir_item_err(leaf, slot,
329 "invalid previous key objectid, have %llu expect %llu",
330 prev_key->objectid, key->objectid);
360 if (!check_prev_ino(leaf, key, slot, prev_key))
331 return -EUCLEAN;
361 return -EUCLEAN;
332 }
333 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
334 while (cur < item_size) {
335 u32 name_len;
336 u32 data_len;
337 u32 max_name_len;
338 u32 total_size;
339 u32 name_hash;
340 u8 dir_type;

--- 912 unchanged lines hidden (view full) ---

1253static int check_inode_ref(struct extent_buffer *leaf,
1254 struct btrfs_key *key, struct btrfs_key *prev_key,
1255 int slot)
1256{
1257 struct btrfs_inode_ref *iref;
1258 unsigned long ptr;
1259 unsigned long end;
1260
362 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
363 while (cur < item_size) {
364 u32 name_len;
365 u32 data_len;
366 u32 max_name_len;
367 u32 total_size;
368 u32 name_hash;
369 u8 dir_type;

--- 912 unchanged lines hidden (view full) ---

1282static int check_inode_ref(struct extent_buffer *leaf,
1283 struct btrfs_key *key, struct btrfs_key *prev_key,
1284 int slot)
1285{
1286 struct btrfs_inode_ref *iref;
1287 unsigned long ptr;
1288 unsigned long end;
1289
1290 if (!check_prev_ino(leaf, key, slot, prev_key))
1291 return -EUCLEAN;
1261 /* namelen can't be 0, so item_size == sizeof() is also invalid */
1262 if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) {
1263 inode_ref_err(fs_info, leaf, slot,
1264 "invalid item size, have %u expect (%zu, %u)",
1265 btrfs_item_size_nr(leaf, slot),
1266 sizeof(*iref), BTRFS_LEAF_DATA_SIZE(leaf->fs_info));
1267 return -EUCLEAN;
1268 }

--- 297 unchanged lines hidden ---
1292 /* namelen can't be 0, so item_size == sizeof() is also invalid */
1293 if (btrfs_item_size_nr(leaf, slot) <= sizeof(*iref)) {
1294 inode_ref_err(fs_info, leaf, slot,
1295 "invalid item size, have %u expect (%zu, %u)",
1296 btrfs_item_size_nr(leaf, slot),
1297 sizeof(*iref), BTRFS_LEAF_DATA_SIZE(leaf->fs_info));
1298 return -EUCLEAN;
1299 }

--- 297 unchanged lines hidden ---