summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2018-05-07 15:46:27 +0800
committerDavid Sterba <dsterba@suse.com>2018-06-07 16:37:32 +0200
commit9e061cae1971ed1933f171378e46a5e52134afbd (patch)
tree93f4661db890948342c8d77da27385c5012644a5
parent8a7b9c9b47f9ff0d56ee016f3d2794112e9e822c (diff)
btrfs-progs: print-tree: Avoid segfault for heavily corrupted item pointers
Normally corrupted leaf should be caught by csum check, but sometimes corrupted item pointers (out of leaf range) can still pass csum check. In fact, our fsck/005 test case image has such corrupted item pointer and btrfs check can surprisingly fix it. Anyway, make print-tree to skip such item and remaining slots to avoid segfault. Please note that, in btrfs-progs we can't put such check into check_tree_block() nor do kernel level comprehensive check as under certain case, btrfs-progs can handle or even repair it. A strict check_tree_block() or backporting kernel btrfs_check_leaf() could break such test cases and reduce the utility of btrfs-progs. Issue: #128 Reported-by: Hubert Kario <hubert@kario.pl> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--print-tree.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/print-tree.c b/print-tree.c
index a1a7954a..9c413d12 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -1179,6 +1179,7 @@ void btrfs_print_leaf(struct extent_buffer *eb)
struct btrfs_item *item;
struct btrfs_disk_key disk_key;
char flags_str[128];
+ u32 leaf_data_size = BTRFS_LEAF_DATA_SIZE(fs_info);
u32 i;
u32 nr;
u64 flags;
@@ -1207,6 +1208,23 @@ void btrfs_print_leaf(struct extent_buffer *eb)
u32 type;
u64 offset;
+ /*
+ * Extra check on item pointers
+ * Here we don't need to be as strict as kernel leaf check.
+ * Only need to ensure all pointers are pointing range inside
+ * the leaf, thus no segfault.
+ */
+ if (btrfs_item_offset_nr(eb, i) > leaf_data_size ||
+ btrfs_item_size_nr(eb, i) + btrfs_item_offset_nr(eb, i) >
+ leaf_data_size) {
+ error(
+"leaf %llu slot %u pointer invalid, offset %u size %u leaf data limit %u",
+ btrfs_header_bytenr(eb), i,
+ btrfs_item_offset_nr(eb, i),
+ btrfs_item_size_nr(eb, i), leaf_data_size);
+ error("skip remaining slots");
+ break;
+ }
item = btrfs_item_nr(i);
item_size = btrfs_item_size(eb, item);
/* Untyped extraction of slot from btrfs_item_ptr */