Skip to contentSkip to conversation

btrfs-progs: print-tree: Avoid segfault for heavily corrupted item pointers

PATCH In review Qu Wenruo 3 participants 4 messages May 7, 2018 – May 8, 2018 Btrfs file system

lore
Share & tools
lore

Qu Wenruo

author
#0 lore raw

PATCH 1/2 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 restrict check_tree_block() or backporting kernel btrfs_check_leaf() could break such test cases and reduce the utility of btrfs-progs.

Issue: #128

---
 print-tree.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
print-tree.c +18 -0
index a1a7954abdae..aaff0f618b7e 100644
@@ -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 restrict 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 */
Signature · 1 line
2.17.0
author
#1 lore raw

PATCH 2/2 btrfs-progs: misc-tests: Add test case for dump-tree on heavily corrupted leaf

---
 .../032-bad-item-ptr/bad_item_ptr.raw.xz       | Bin 0 -> 21964 bytes
 tests/misc-tests/032-bad-item-ptr/test.sh      |  17 +++++++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 tests/misc-tests/032-bad-item-ptr/bad_item_ptr.raw.xz
 create mode 100755 tests/misc-tests/032-bad-item-ptr/test.sh
tests/misc-tests/032-bad-item-ptr/bad_item_ptr.raw.xz new file binary +0 -0
new file mode 100644
index 0000000000000000000000000000000000000000..7cf2e89f443c626ad4947901bf659d5377278b3e
GIT binary patch
tests/misc-tests/032-bad-item-ptr/test.sh new file +17 -0
new file mode 100755
index 000000000000..3a73b7bb36f5
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Verify that btrfs inspect dump-tree won't segfault on heavily corrupted
+# tree leaf
+# Issue: #128
+
+source "$TEST_TOP/common"
+
+check_prereq btrfs
+
+check_image() {
+	run_check "$TOP/btrfs" inspect dump-tree "$1"
+	run_mustfail "btrfs check failed to detect such corruption" \
+		  "$TOP/btrfs" check "$1"
+}
+
+check_all_images
Signature · 1 line
2.17.0
#2 lore raw
In reply to Qu Wenruo
Quoted 8 lines · Qu Wenruo

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.

Quoted 8 lines

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 restrict check_tree_block() or backporting kernel btrfs_check_leaf() could break such test cases and reduce the utility of btrfs-progs.

Issue: #128

Mail changed to <[email protected]> (Github version already updated.)

Thanks,
Qu

Quoted 42 lines
---
 print-tree.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
print-tree.c +18 -0
index a1a7954abdae..aaff0f618b7e 100644
@@ -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 restrict 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 */
#3 lore raw
Quoted 17 lines · Qu Wenruo
Quoted 14 lines · Qu Wenruo

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 restrict check_tree_block() or backporting kernel btrfs_check_leaf() could break such test cases and reduce the utility of btrfs-progs.

Quoted 4 lines
Quoted 2 lines

Issue: #128

Mail changed to <[email protected]> (Github version already updated.)

Updated and applied, thanks.