btrfs-progs: save item data end in u64 to avoid overflow in btrfs_check_leaf()

Similar to kernel check_leaf(), calling btrfs_item_end_nr() may get a
reasonable value even an item has invalid offset/size due to u32
overflow.

Fix it by use u64 variable to store item data end in btrfs_check_leaf()
to avoid u32 overflow.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215299
Reported-by: Wenqing Liu <wenqingliu0120@gmail.com>
Signed-off-by: Su Yue <l@damenly.su>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Su Yue 2022-02-22 17:05:28 +08:00 committed by David Sterba
parent f4da3ea032
commit d0a99313e5

View File

@ -705,6 +705,7 @@ btrfs_check_leaf(struct btrfs_fs_info *fs_info,
*/
for (slot = 0; slot < nritems; slot++) {
u32 item_end_expected;
u64 item_data_end;
btrfs_item_key_to_cpu(leaf, &key, slot);
@ -719,6 +720,8 @@ btrfs_check_leaf(struct btrfs_fs_info *fs_info,
goto fail;
}
item_data_end = (u64)btrfs_item_offset(leaf, slot) +
btrfs_item_size(leaf, slot);
/*
* Make sure the offset and ends are right, remember that the
* item data starts at the end of the leaf and grows towards the
@ -729,11 +732,10 @@ btrfs_check_leaf(struct btrfs_fs_info *fs_info,
else
item_end_expected = btrfs_item_offset(leaf,
slot - 1);
if (btrfs_item_end(leaf, slot) != item_end_expected) {
if (item_data_end != item_end_expected) {
generic_err(leaf, slot,
"unexpected item end, have %u expect %u",
btrfs_item_end(leaf, slot),
item_end_expected);
"unexpected item end, have %llu expect %u",
item_data_end, item_end_expected);
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
goto fail;
}
@ -743,12 +745,10 @@ btrfs_check_leaf(struct btrfs_fs_info *fs_info,
* just in case all the items are consistent to each other, but
* all point outside of the leaf.
*/
if (btrfs_item_end(leaf, slot) >
BTRFS_LEAF_DATA_SIZE(fs_info)) {
if (item_data_end > BTRFS_LEAF_DATA_SIZE(fs_info)) {
generic_err(leaf, slot,
"slot end outside of leaf, have %u expect range [0, %u]",
btrfs_item_end(leaf, slot),
BTRFS_LEAF_DATA_SIZE(fs_info));
"slot end outside of leaf, have %llu expect range [0, %u]",
item_data_end, BTRFS_LEAF_DATA_SIZE(fs_info));
ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS;
goto fail;
}