| From: Qu Wenruo <wqu@suse.com> |
| Date: Tue, 3 Jul 2018 17:10:06 +0800 |
| Subject: btrfs: tree-checker: Detect invalid and empty essential trees |
| |
| commit ba480dd4db9f1798541eb2d1c423fc95feee8d36 upstream. |
| |
| A crafted image has empty root tree block, which will later cause NULL |
| pointer dereference. |
| |
| The following trees should never be empty: |
| 1) Tree root |
| Must contain at least root items for extent tree, device tree and fs |
| tree |
| |
| 2) Chunk tree |
| Or we can't even bootstrap as it contains the mapping. |
| |
| 3) Fs tree |
| At least inode item for top level inode (.). |
| |
| 4) Device tree |
| Dev extents for chunks |
| |
| 5) Extent tree |
| Must have corresponding extent for each chunk. |
| |
| If any of them is empty, we are sure the fs is corrupted and no need to |
| mount it. |
| |
| Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847 |
| Reported-by: Xu Wen <wen.xu@gatech.edu> |
| Signed-off-by: Qu Wenruo <wqu@suse.com> |
| Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| [bwh: Backported to 4.4: Pass root instead of fs_info to generic_err()] |
| Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/btrfs/tree-checker.c | 15 ++++++++++++++- |
| 1 file changed, 14 insertions(+), 1 deletion(-) |
| |
| --- a/fs/btrfs/tree-checker.c |
| +++ b/fs/btrfs/tree-checker.c |
| @@ -456,9 +456,22 @@ static int check_leaf(struct btrfs_root |
| * skip this check for relocation trees. |
| */ |
| if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { |
| + u64 owner = btrfs_header_owner(leaf); |
| struct btrfs_root *check_root; |
| |
| - key.objectid = btrfs_header_owner(leaf); |
| + /* These trees must never be empty */ |
| + if (owner == BTRFS_ROOT_TREE_OBJECTID || |
| + owner == BTRFS_CHUNK_TREE_OBJECTID || |
| + owner == BTRFS_EXTENT_TREE_OBJECTID || |
| + owner == BTRFS_DEV_TREE_OBJECTID || |
| + owner == BTRFS_FS_TREE_OBJECTID || |
| + owner == BTRFS_DATA_RELOC_TREE_OBJECTID) { |
| + generic_err(root, leaf, 0, |
| + "invalid root, root %llu must never be empty", |
| + owner); |
| + return -EUCLEAN; |
| + } |
| + key.objectid = owner; |
| key.type = BTRFS_ROOT_ITEM_KEY; |
| key.offset = (u64)-1; |
| |