Skip to content

Commit e03418a

Browse files
josefbacikkdave
authored andcommitted
btrfs: make sure that WRITTEN is set on all metadata blocks
We previously would call btrfs_check_leaf() if we had the check integrity code enabled, which meant that we could only run the extended leaf checks if we had WRITTEN set on the header flags. This leaves a gap in our checking, because we could end up with corruption on disk where WRITTEN isn't set on the leaf, and then the extended leaf checks don't get run which we rely on to validate all of the item pointers to make sure we don't access memory outside of the extent buffer. However, since 732fab9 ("btrfs: check-integrity: remove CONFIG_BTRFS_FS_CHECK_INTEGRITY option") we no longer call btrfs_check_leaf() from btrfs_mark_buffer_dirty(), which means we only ever call it on blocks that are being written out, and thus have WRITTEN set, or that are being read in, which should have WRITTEN set. Add checks to make sure we have WRITTEN set appropriately, and then make sure __btrfs_check_leaf() always does the item checking. This will protect us from file systems that have been corrupted and no longer have WRITTEN set on some of the blocks. This was hit on a crafted image tweaking the WRITTEN bit and reported by KASAN as out-of-bound access in the eb accessors. The example is a dir item at the end of an eb. [2.042] BTRFS warning (device loop1): bad eb member start: ptr 0x3fff start 30572544 member offset 16410 size 2 [2.040] general protection fault, probably for non-canonical address 0xe0009d1000000003: 0000 [#1] PREEMPT SMP KASAN NOPTI [2.537] KASAN: maybe wild-memory-access in range [0x0005088000000018-0x000508800000001f] [2.729] CPU: 0 PID: 2587 Comm: mount Not tainted 6.8.2 #1 [2.729] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 [2.621] RIP: 0010:btrfs_get_16+0x34b/0x6d0 [2.621] RSP: 0018:ffff88810871fab8 EFLAGS: 00000206 [2.621] RAX: 0000a11000000003 RBX: ffff888104ff8720 RCX: ffff88811b2288c0 [2.621] RDX: dffffc0000000000 RSI: ffffffff81dd8aca RDI: ffff88810871f748 [2.621] RBP: 000000000000401a R08: 0000000000000001 R09: ffffed10210e3ee9 [2.621] R10: ffff88810871f74f R11: 205d323430333737 R12: 000000000000001a [2.621] R13: 000508800000001a R14: 1ffff110210e3f5d R15: ffffffff850011e8 [2.621] FS: 00007f56ea275840(0000) GS:ffff88811b200000(0000) knlGS:0000000000000000 [2.621] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [2.621] CR2: 00007febd13b75c0 CR3: 000000010bb50000 CR4: 00000000000006f0 [2.621] Call Trace: [2.621] <TASK> [2.621] ? show_regs+0x74/0x80 [2.621] ? die_addr+0x46/0xc0 [2.621] ? exc_general_protection+0x161/0x2a0 [2.621] ? asm_exc_general_protection+0x26/0x30 [2.621] ? btrfs_get_16+0x33a/0x6d0 [2.621] ? btrfs_get_16+0x34b/0x6d0 [2.621] ? btrfs_get_16+0x33a/0x6d0 [2.621] ? __pfx_btrfs_get_16+0x10/0x10 [2.621] ? __pfx_mutex_unlock+0x10/0x10 [2.621] btrfs_match_dir_item_name+0x101/0x1a0 [2.621] btrfs_lookup_dir_item+0x1f3/0x280 [2.621] ? __pfx_btrfs_lookup_dir_item+0x10/0x10 [2.621] btrfs_get_tree+0xd25/0x1910 Reported-by: lei lu <[email protected]> CC: [email protected] # 6.7+ Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Reviewed-by: David Sterba <[email protected]> [ copy more details from report ] Signed-off-by: David Sterba <[email protected]>
1 parent b5357cb commit e03418a

File tree

2 files changed

+16
-15
lines changed

2 files changed

+16
-15
lines changed

fs/btrfs/tree-checker.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,11 @@ enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *leaf)
17971797
return BTRFS_TREE_BLOCK_INVALID_LEVEL;
17981798
}
17991799

1800+
if (unlikely(!btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_WRITTEN))) {
1801+
generic_err(leaf, 0, "invalid flag for leaf, WRITTEN not set");
1802+
return BTRFS_TREE_BLOCK_WRITTEN_NOT_SET;
1803+
}
1804+
18001805
/*
18011806
* Extent buffers from a relocation tree have a owner field that
18021807
* corresponds to the subvolume tree they are based on. So just from an
@@ -1858,6 +1863,7 @@ enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *leaf)
18581863
for (slot = 0; slot < nritems; slot++) {
18591864
u32 item_end_expected;
18601865
u64 item_data_end;
1866+
enum btrfs_tree_block_status ret;
18611867

18621868
btrfs_item_key_to_cpu(leaf, &key, slot);
18631869

@@ -1913,21 +1919,10 @@ enum btrfs_tree_block_status __btrfs_check_leaf(struct extent_buffer *leaf)
19131919
return BTRFS_TREE_BLOCK_INVALID_OFFSETS;
19141920
}
19151921

1916-
/*
1917-
* We only want to do this if WRITTEN is set, otherwise the leaf
1918-
* may be in some intermediate state and won't appear valid.
1919-
*/
1920-
if (btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_WRITTEN)) {
1921-
enum btrfs_tree_block_status ret;
1922-
1923-
/*
1924-
* Check if the item size and content meet other
1925-
* criteria
1926-
*/
1927-
ret = check_leaf_item(leaf, &key, slot, &prev_key);
1928-
if (unlikely(ret != BTRFS_TREE_BLOCK_CLEAN))
1929-
return ret;
1930-
}
1922+
/* Check if the item size and content meet other criteria. */
1923+
ret = check_leaf_item(leaf, &key, slot, &prev_key);
1924+
if (unlikely(ret != BTRFS_TREE_BLOCK_CLEAN))
1925+
return ret;
19311926

19321927
prev_key.objectid = key.objectid;
19331928
prev_key.type = key.type;
@@ -1957,6 +1952,11 @@ enum btrfs_tree_block_status __btrfs_check_node(struct extent_buffer *node)
19571952
int level = btrfs_header_level(node);
19581953
u64 bytenr;
19591954

1955+
if (unlikely(!btrfs_header_flag(node, BTRFS_HEADER_FLAG_WRITTEN))) {
1956+
generic_err(node, 0, "invalid flag for node, WRITTEN not set");
1957+
return BTRFS_TREE_BLOCK_WRITTEN_NOT_SET;
1958+
}
1959+
19601960
if (unlikely(level <= 0 || level >= BTRFS_MAX_LEVEL)) {
19611961
generic_err(node, 0,
19621962
"invalid level for node, have %d expect [1, %d]",

fs/btrfs/tree-checker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ enum btrfs_tree_block_status {
5353
BTRFS_TREE_BLOCK_INVALID_BLOCKPTR,
5454
BTRFS_TREE_BLOCK_INVALID_ITEM,
5555
BTRFS_TREE_BLOCK_INVALID_OWNER,
56+
BTRFS_TREE_BLOCK_WRITTEN_NOT_SET,
5657
};
5758

5859
/*

0 commit comments

Comments
 (0)