1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) Qu Wenruo 2017. All rights reserved.
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.
10 * The objective is to do leaf/node validation checks when tree block is read
11 * from disk, and check *every* possible member, so other code won't
12 * need to checking them again.
14 * Due to the potential and unwanted damage, every checker needs to be
15 * carefully reviewed otherwise so it does not prevent mount of valid images.
19 #include "tree-checker.h"
21 #include "compression.h"
25 * Error message should follow the following format:
26 * corrupt <type>: <identifier>, <reason>[, <bad_value>]
29 * @identifier: the necessary info to locate the leaf/node.
30 * It's recommened to decode key.objecitd/offset if it's
32 * @reason: describe the error
33 * @bad_value: optional, it's recommened to output bad value and its
34 * expected value (range).
36 * Since comma is used to separate the components, only space is allowed
37 * inside each component.
41 * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt.
42 * Allows callers to customize the output.
46 static void generic_err(const struct btrfs_fs_info
*fs_info
,
47 const struct extent_buffer
*eb
, int slot
,
59 "corrupt %s: root=%llu block=%llu slot=%d, %pV",
60 btrfs_header_level(eb
) == 0 ? "leaf" : "node",
61 btrfs_header_owner(eb
), btrfs_header_bytenr(eb
), slot
, &vaf
);
66 * Customized reporter for extent data item, since its key objectid and
67 * offset has its own meaning.
71 static void file_extent_err(const struct btrfs_fs_info
*fs_info
,
72 const struct extent_buffer
*eb
, int slot
,
79 btrfs_item_key_to_cpu(eb
, &key
, slot
);
86 "corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
87 btrfs_header_level(eb
) == 0 ? "leaf" : "node",
88 btrfs_header_owner(eb
), btrfs_header_bytenr(eb
), slot
,
89 key
.objectid
, key
.offset
, &vaf
);
94 * Return 0 if the btrfs_file_extent_##name is aligned to @alignment
97 #define CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, name, alignment) \
99 if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \
100 file_extent_err((fs_info), (leaf), (slot), \
101 "invalid %s for file extent, have %llu, should be aligned to %u", \
102 (#name), btrfs_file_extent_##name((leaf), (fi)), \
104 (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))); \
107 static int check_extent_data_item(struct btrfs_fs_info
*fs_info
,
108 struct extent_buffer
*leaf
,
109 struct btrfs_key
*key
, int slot
)
111 struct btrfs_file_extent_item
*fi
;
112 u32 sectorsize
= fs_info
->sectorsize
;
113 u32 item_size
= btrfs_item_size_nr(leaf
, slot
);
115 if (!IS_ALIGNED(key
->offset
, sectorsize
)) {
116 file_extent_err(fs_info
, leaf
, slot
,
117 "unaligned file_offset for file extent, have %llu should be aligned to %u",
118 key
->offset
, sectorsize
);
122 fi
= btrfs_item_ptr(leaf
, slot
, struct btrfs_file_extent_item
);
124 if (btrfs_file_extent_type(leaf
, fi
) > BTRFS_FILE_EXTENT_TYPES
) {
125 file_extent_err(fs_info
, leaf
, slot
,
126 "invalid type for file extent, have %u expect range [0, %u]",
127 btrfs_file_extent_type(leaf
, fi
),
128 BTRFS_FILE_EXTENT_TYPES
);
133 * Support for new compression/encrption must introduce incompat flag,
134 * and must be caught in open_ctree().
136 if (btrfs_file_extent_compression(leaf
, fi
) > BTRFS_COMPRESS_TYPES
) {
137 file_extent_err(fs_info
, leaf
, slot
,
138 "invalid compression for file extent, have %u expect range [0, %u]",
139 btrfs_file_extent_compression(leaf
, fi
),
140 BTRFS_COMPRESS_TYPES
);
143 if (btrfs_file_extent_encryption(leaf
, fi
)) {
144 file_extent_err(fs_info
, leaf
, slot
,
145 "invalid encryption for file extent, have %u expect 0",
146 btrfs_file_extent_encryption(leaf
, fi
));
149 if (btrfs_file_extent_type(leaf
, fi
) == BTRFS_FILE_EXTENT_INLINE
) {
150 /* Inline extent must have 0 as key offset */
152 file_extent_err(fs_info
, leaf
, slot
,
153 "invalid file_offset for inline file extent, have %llu expect 0",
158 /* Compressed inline extent has no on-disk size, skip it */
159 if (btrfs_file_extent_compression(leaf
, fi
) !=
163 /* Uncompressed inline extent size must match item size */
164 if (item_size
!= BTRFS_FILE_EXTENT_INLINE_DATA_START
+
165 btrfs_file_extent_ram_bytes(leaf
, fi
)) {
166 file_extent_err(fs_info
, leaf
, slot
,
167 "invalid ram_bytes for uncompressed inline extent, have %u expect %llu",
168 item_size
, BTRFS_FILE_EXTENT_INLINE_DATA_START
+
169 btrfs_file_extent_ram_bytes(leaf
, fi
));
175 /* Regular or preallocated extent has fixed item size */
176 if (item_size
!= sizeof(*fi
)) {
177 file_extent_err(fs_info
, leaf
, slot
,
178 "invalid item size for reg/prealloc file extent, have %u expect %zu",
179 item_size
, sizeof(*fi
));
182 if (CHECK_FE_ALIGNED(fs_info
, leaf
, slot
, fi
, ram_bytes
, sectorsize
) ||
183 CHECK_FE_ALIGNED(fs_info
, leaf
, slot
, fi
, disk_bytenr
, sectorsize
) ||
184 CHECK_FE_ALIGNED(fs_info
, leaf
, slot
, fi
, disk_num_bytes
, sectorsize
) ||
185 CHECK_FE_ALIGNED(fs_info
, leaf
, slot
, fi
, offset
, sectorsize
) ||
186 CHECK_FE_ALIGNED(fs_info
, leaf
, slot
, fi
, num_bytes
, sectorsize
))
191 static int check_csum_item(struct btrfs_fs_info
*fs_info
,
192 struct extent_buffer
*leaf
, struct btrfs_key
*key
,
195 u32 sectorsize
= fs_info
->sectorsize
;
196 u32 csumsize
= btrfs_super_csum_size(fs_info
->super_copy
);
198 if (key
->objectid
!= BTRFS_EXTENT_CSUM_OBJECTID
) {
199 generic_err(fs_info
, leaf
, slot
,
200 "invalid key objectid for csum item, have %llu expect %llu",
201 key
->objectid
, BTRFS_EXTENT_CSUM_OBJECTID
);
204 if (!IS_ALIGNED(key
->offset
, sectorsize
)) {
205 generic_err(fs_info
, leaf
, slot
,
206 "unaligned key offset for csum item, have %llu should be aligned to %u",
207 key
->offset
, sectorsize
);
210 if (!IS_ALIGNED(btrfs_item_size_nr(leaf
, slot
), csumsize
)) {
211 generic_err(fs_info
, leaf
, slot
,
212 "unaligned item size for csum item, have %u should be aligned to %u",
213 btrfs_item_size_nr(leaf
, slot
), csumsize
);
220 * Customized reported for dir_item, only important new info is key->objectid,
221 * which represents inode number
225 static void dir_item_err(const struct btrfs_fs_info
*fs_info
,
226 const struct extent_buffer
*eb
, int slot
,
227 const char *fmt
, ...)
229 struct btrfs_key key
;
230 struct va_format vaf
;
233 btrfs_item_key_to_cpu(eb
, &key
, slot
);
240 "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
241 btrfs_header_level(eb
) == 0 ? "leaf" : "node",
242 btrfs_header_owner(eb
), btrfs_header_bytenr(eb
), slot
,
247 static int check_dir_item(struct btrfs_fs_info
*fs_info
,
248 struct extent_buffer
*leaf
,
249 struct btrfs_key
*key
, int slot
)
251 struct btrfs_dir_item
*di
;
252 u32 item_size
= btrfs_item_size_nr(leaf
, slot
);
255 di
= btrfs_item_ptr(leaf
, slot
, struct btrfs_dir_item
);
256 while (cur
< item_size
) {
264 /* header itself should not cross item boundary */
265 if (cur
+ sizeof(*di
) > item_size
) {
266 dir_item_err(fs_info
, leaf
, slot
,
267 "dir item header crosses item boundary, have %zu boundary %u",
268 cur
+ sizeof(*di
), item_size
);
273 dir_type
= btrfs_dir_type(leaf
, di
);
274 if (dir_type
>= BTRFS_FT_MAX
) {
275 dir_item_err(fs_info
, leaf
, slot
,
276 "invalid dir item type, have %u expect [0, %u)",
277 dir_type
, BTRFS_FT_MAX
);
281 if (key
->type
== BTRFS_XATTR_ITEM_KEY
&&
282 dir_type
!= BTRFS_FT_XATTR
) {
283 dir_item_err(fs_info
, leaf
, slot
,
284 "invalid dir item type for XATTR key, have %u expect %u",
285 dir_type
, BTRFS_FT_XATTR
);
288 if (dir_type
== BTRFS_FT_XATTR
&&
289 key
->type
!= BTRFS_XATTR_ITEM_KEY
) {
290 dir_item_err(fs_info
, leaf
, slot
,
291 "xattr dir type found for non-XATTR key");
294 if (dir_type
== BTRFS_FT_XATTR
)
295 max_name_len
= XATTR_NAME_MAX
;
297 max_name_len
= BTRFS_NAME_LEN
;
299 /* Name/data length check */
300 name_len
= btrfs_dir_name_len(leaf
, di
);
301 data_len
= btrfs_dir_data_len(leaf
, di
);
302 if (name_len
> max_name_len
) {
303 dir_item_err(fs_info
, leaf
, slot
,
304 "dir item name len too long, have %u max %u",
305 name_len
, max_name_len
);
308 if (name_len
+ data_len
> BTRFS_MAX_XATTR_SIZE(fs_info
)) {
309 dir_item_err(fs_info
, leaf
, slot
,
310 "dir item name and data len too long, have %u max %u",
312 BTRFS_MAX_XATTR_SIZE(fs_info
));
316 if (data_len
&& dir_type
!= BTRFS_FT_XATTR
) {
317 dir_item_err(fs_info
, leaf
, slot
,
318 "dir item with invalid data len, have %u expect 0",
323 total_size
= sizeof(*di
) + name_len
+ data_len
;
325 /* header and name/data should not cross item boundary */
326 if (cur
+ total_size
> item_size
) {
327 dir_item_err(fs_info
, leaf
, slot
,
328 "dir item data crosses item boundary, have %u boundary %u",
329 cur
+ total_size
, item_size
);
334 * Special check for XATTR/DIR_ITEM, as key->offset is name
335 * hash, should match its name
337 if (key
->type
== BTRFS_DIR_ITEM_KEY
||
338 key
->type
== BTRFS_XATTR_ITEM_KEY
) {
339 char namebuf
[max(BTRFS_NAME_LEN
, XATTR_NAME_MAX
)];
341 read_extent_buffer(leaf
, namebuf
,
342 (unsigned long)(di
+ 1), name_len
);
343 name_hash
= btrfs_name_hash(namebuf
, name_len
);
344 if (key
->offset
!= name_hash
) {
345 dir_item_err(fs_info
, leaf
, slot
,
346 "name hash mismatch with key, have 0x%016x expect 0x%016llx",
347 name_hash
, key
->offset
);
352 di
= (struct btrfs_dir_item
*)((void *)di
+ total_size
);
359 static void block_group_err(const struct btrfs_fs_info
*fs_info
,
360 const struct extent_buffer
*eb
, int slot
,
361 const char *fmt
, ...)
363 struct btrfs_key key
;
364 struct va_format vaf
;
367 btrfs_item_key_to_cpu(eb
, &key
, slot
);
374 "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
375 btrfs_header_level(eb
) == 0 ? "leaf" : "node",
376 btrfs_header_owner(eb
), btrfs_header_bytenr(eb
), slot
,
377 key
.objectid
, key
.offset
, &vaf
);
381 static int check_block_group_item(struct btrfs_fs_info
*fs_info
,
382 struct extent_buffer
*leaf
,
383 struct btrfs_key
*key
, int slot
)
385 struct btrfs_block_group_item bgi
;
386 u32 item_size
= btrfs_item_size_nr(leaf
, slot
);
391 * Here we don't really care about alignment since extent allocator can
392 * handle it. We care more about the size.
394 if (key
->offset
== 0) {
395 block_group_err(fs_info
, leaf
, slot
,
396 "invalid block group size 0");
400 if (item_size
!= sizeof(bgi
)) {
401 block_group_err(fs_info
, leaf
, slot
,
402 "invalid item size, have %u expect %zu",
403 item_size
, sizeof(bgi
));
407 read_extent_buffer(leaf
, &bgi
, btrfs_item_ptr_offset(leaf
, slot
),
409 if (btrfs_block_group_chunk_objectid(&bgi
) !=
410 BTRFS_FIRST_CHUNK_TREE_OBJECTID
) {
411 block_group_err(fs_info
, leaf
, slot
,
412 "invalid block group chunk objectid, have %llu expect %llu",
413 btrfs_block_group_chunk_objectid(&bgi
),
414 BTRFS_FIRST_CHUNK_TREE_OBJECTID
);
418 if (btrfs_block_group_used(&bgi
) > key
->offset
) {
419 block_group_err(fs_info
, leaf
, slot
,
420 "invalid block group used, have %llu expect [0, %llu)",
421 btrfs_block_group_used(&bgi
), key
->offset
);
425 flags
= btrfs_block_group_flags(&bgi
);
426 if (hweight64(flags
& BTRFS_BLOCK_GROUP_PROFILE_MASK
) > 1) {
427 block_group_err(fs_info
, leaf
, slot
,
428 "invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set",
429 flags
& BTRFS_BLOCK_GROUP_PROFILE_MASK
,
430 hweight64(flags
& BTRFS_BLOCK_GROUP_PROFILE_MASK
));
434 type
= flags
& BTRFS_BLOCK_GROUP_TYPE_MASK
;
435 if (type
!= BTRFS_BLOCK_GROUP_DATA
&&
436 type
!= BTRFS_BLOCK_GROUP_METADATA
&&
437 type
!= BTRFS_BLOCK_GROUP_SYSTEM
&&
438 type
!= (BTRFS_BLOCK_GROUP_METADATA
|
439 BTRFS_BLOCK_GROUP_DATA
)) {
440 block_group_err(fs_info
, leaf
, slot
,
441 "invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx",
442 type
, hweight64(type
),
443 BTRFS_BLOCK_GROUP_DATA
, BTRFS_BLOCK_GROUP_METADATA
,
444 BTRFS_BLOCK_GROUP_SYSTEM
,
445 BTRFS_BLOCK_GROUP_METADATA
| BTRFS_BLOCK_GROUP_DATA
);
452 * Common point to switch the item-specific validation.
454 static int check_leaf_item(struct btrfs_fs_info
*fs_info
,
455 struct extent_buffer
*leaf
,
456 struct btrfs_key
*key
, int slot
)
461 case BTRFS_EXTENT_DATA_KEY
:
462 ret
= check_extent_data_item(fs_info
, leaf
, key
, slot
);
464 case BTRFS_EXTENT_CSUM_KEY
:
465 ret
= check_csum_item(fs_info
, leaf
, key
, slot
);
467 case BTRFS_DIR_ITEM_KEY
:
468 case BTRFS_DIR_INDEX_KEY
:
469 case BTRFS_XATTR_ITEM_KEY
:
470 ret
= check_dir_item(fs_info
, leaf
, key
, slot
);
472 case BTRFS_BLOCK_GROUP_ITEM_KEY
:
473 ret
= check_block_group_item(fs_info
, leaf
, key
, slot
);
479 static int check_leaf(struct btrfs_fs_info
*fs_info
, struct extent_buffer
*leaf
,
480 bool check_item_data
)
482 /* No valid key type is 0, so all key should be larger than this key */
483 struct btrfs_key prev_key
= {0, 0, 0};
484 struct btrfs_key key
;
485 u32 nritems
= btrfs_header_nritems(leaf
);
488 if (btrfs_header_level(leaf
) != 0) {
489 generic_err(fs_info
, leaf
, 0,
490 "invalid level for leaf, have %d expect 0",
491 btrfs_header_level(leaf
));
496 * Extent buffers from a relocation tree have a owner field that
497 * corresponds to the subvolume tree they are based on. So just from an
498 * extent buffer alone we can not find out what is the id of the
499 * corresponding subvolume tree, so we can not figure out if the extent
500 * buffer corresponds to the root of the relocation tree or not. So
501 * skip this check for relocation trees.
503 if (nritems
== 0 && !btrfs_header_flag(leaf
, BTRFS_HEADER_FLAG_RELOC
)) {
504 u64 owner
= btrfs_header_owner(leaf
);
505 struct btrfs_root
*check_root
;
507 /* These trees must never be empty */
508 if (owner
== BTRFS_ROOT_TREE_OBJECTID
||
509 owner
== BTRFS_CHUNK_TREE_OBJECTID
||
510 owner
== BTRFS_EXTENT_TREE_OBJECTID
||
511 owner
== BTRFS_DEV_TREE_OBJECTID
||
512 owner
== BTRFS_FS_TREE_OBJECTID
||
513 owner
== BTRFS_DATA_RELOC_TREE_OBJECTID
) {
514 generic_err(fs_info
, leaf
, 0,
515 "invalid root, root %llu must never be empty",
521 generic_err(fs_info
, leaf
, 0,
522 "invalid owner, root 0 is not defined");
525 key
.objectid
= owner
;
526 key
.type
= BTRFS_ROOT_ITEM_KEY
;
527 key
.offset
= (u64
)-1;
529 check_root
= btrfs_get_fs_root(fs_info
, &key
, false);
531 * The only reason we also check NULL here is that during
532 * open_ctree() some roots has not yet been set up.
534 if (!IS_ERR_OR_NULL(check_root
)) {
535 struct extent_buffer
*eb
;
537 eb
= btrfs_root_node(check_root
);
538 /* if leaf is the root, then it's fine */
540 generic_err(fs_info
, leaf
, 0,
541 "invalid nritems, have %u should not be 0 for non-root leaf",
543 free_extent_buffer(eb
);
546 free_extent_buffer(eb
);
555 * Check the following things to make sure this is a good leaf, and
556 * leaf users won't need to bother with similar sanity checks:
559 * 2) item offset and size
560 * No overlap, no hole, all inside the leaf.
562 * If possible, do comprehensive sanity check.
563 * NOTE: All checks must only rely on the item data itself.
565 for (slot
= 0; slot
< nritems
; slot
++) {
566 u32 item_end_expected
;
569 btrfs_item_key_to_cpu(leaf
, &key
, slot
);
571 /* Make sure the keys are in the right order */
572 if (btrfs_comp_cpu_keys(&prev_key
, &key
) >= 0) {
573 generic_err(fs_info
, leaf
, slot
,
574 "bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
575 prev_key
.objectid
, prev_key
.type
,
576 prev_key
.offset
, key
.objectid
, key
.type
,
582 * Make sure the offset and ends are right, remember that the
583 * item data starts at the end of the leaf and grows towards the
587 item_end_expected
= BTRFS_LEAF_DATA_SIZE(fs_info
);
589 item_end_expected
= btrfs_item_offset_nr(leaf
,
591 if (btrfs_item_end_nr(leaf
, slot
) != item_end_expected
) {
592 generic_err(fs_info
, leaf
, slot
,
593 "unexpected item end, have %u expect %u",
594 btrfs_item_end_nr(leaf
, slot
),
600 * Check to make sure that we don't point outside of the leaf,
601 * just in case all the items are consistent to each other, but
602 * all point outside of the leaf.
604 if (btrfs_item_end_nr(leaf
, slot
) >
605 BTRFS_LEAF_DATA_SIZE(fs_info
)) {
606 generic_err(fs_info
, leaf
, slot
,
607 "slot end outside of leaf, have %u expect range [0, %u]",
608 btrfs_item_end_nr(leaf
, slot
),
609 BTRFS_LEAF_DATA_SIZE(fs_info
));
613 /* Also check if the item pointer overlaps with btrfs item. */
614 if (btrfs_item_nr_offset(slot
) + sizeof(struct btrfs_item
) >
615 btrfs_item_ptr_offset(leaf
, slot
)) {
616 generic_err(fs_info
, leaf
, slot
,
617 "slot overlaps with its data, item end %lu data start %lu",
618 btrfs_item_nr_offset(slot
) +
619 sizeof(struct btrfs_item
),
620 btrfs_item_ptr_offset(leaf
, slot
));
624 if (check_item_data
) {
626 * Check if the item size and content meet other
629 ret
= check_leaf_item(fs_info
, leaf
, &key
, slot
);
634 prev_key
.objectid
= key
.objectid
;
635 prev_key
.type
= key
.type
;
636 prev_key
.offset
= key
.offset
;
642 int btrfs_check_leaf_full(struct btrfs_fs_info
*fs_info
,
643 struct extent_buffer
*leaf
)
645 return check_leaf(fs_info
, leaf
, true);
648 int btrfs_check_leaf_relaxed(struct btrfs_fs_info
*fs_info
,
649 struct extent_buffer
*leaf
)
651 return check_leaf(fs_info
, leaf
, false);
654 int btrfs_check_node(struct btrfs_fs_info
*fs_info
, struct extent_buffer
*node
)
656 unsigned long nr
= btrfs_header_nritems(node
);
657 struct btrfs_key key
, next_key
;
659 int level
= btrfs_header_level(node
);
663 if (level
<= 0 || level
>= BTRFS_MAX_LEVEL
) {
664 generic_err(fs_info
, node
, 0,
665 "invalid level for node, have %d expect [1, %d]",
666 level
, BTRFS_MAX_LEVEL
- 1);
669 if (nr
== 0 || nr
> BTRFS_NODEPTRS_PER_BLOCK(fs_info
)) {
671 "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
672 btrfs_header_owner(node
), node
->start
,
673 nr
== 0 ? "small" : "large", nr
,
674 BTRFS_NODEPTRS_PER_BLOCK(fs_info
));
678 for (slot
= 0; slot
< nr
- 1; slot
++) {
679 bytenr
= btrfs_node_blockptr(node
, slot
);
680 btrfs_node_key_to_cpu(node
, &key
, slot
);
681 btrfs_node_key_to_cpu(node
, &next_key
, slot
+ 1);
684 generic_err(fs_info
, node
, slot
,
685 "invalid NULL node pointer");
689 if (!IS_ALIGNED(bytenr
, fs_info
->sectorsize
)) {
690 generic_err(fs_info
, node
, slot
,
691 "unaligned pointer, have %llu should be aligned to %u",
692 bytenr
, fs_info
->sectorsize
);
697 if (btrfs_comp_cpu_keys(&key
, &next_key
) >= 0) {
698 generic_err(fs_info
, node
, slot
,
699 "bad key order, current (%llu %u %llu) next (%llu %u %llu)",
700 key
.objectid
, key
.type
, key
.offset
,
701 next_key
.objectid
, next_key
.type
,