Btrfs: fix setup_leaf_for_split() to avoid leaf corruption
authorFilipe Manana <fdmanana@suse.com>
Tue, 20 Jan 2015 12:40:53 +0000 (12:40 +0000)
committerChris Mason <clm@fb.com>
Thu, 22 Jan 2015 02:02:03 +0000 (18:02 -0800)
commita8df6fe666f9a3a7c08df70f94351f967462dd95
tree8f9861e5422a5c36c0a4a580281239c4ed14974a
parent57bbddd7fbf468336940d18a4c68a8678163acb0
Btrfs: fix setup_leaf_for_split() to avoid leaf corruption

We were incorrectly detecting when the target key didn't exist anymore
after releasing the path and re-searching the tree. This could make
us split or duplicate (btrfs_split_item() and btrfs_duplicate_item()
are its only callers at the moment) an item when we should not.

For the case of duplicating an item, we currently only duplicate
checksum items (csum tree) and file extent items (fs/subvol trees).
For the checksum items we end up overriding the item completely,
but for file extent items we update only some of their fields in
the copy (done in __btrfs_drop_extents), which means we can end up
having a logical corruption for some values.

Also for the case where we duplicate a file extent item it will make
us produce a leaf with a wrong key order, as btrfs_duplicate_item()
advances us to the next slot and then its caller sets a smaller key
on the new item at that slot (like in __btrfs_drop_extents() e.g.).
Alternatively if the tree search in setup_leaf_for_split() leaves
with path->slots[0] == btrfs_header_nritems(path->nodes[0]), we end
up accessing beyond the leaf's end (when we check if the item's size
has changed) and make our caller insert an item at the invalid slot
btrfs_header_nritems(path->nodes[0]) + 1, causing an invalid memory
access if the leaf is full or nearly full.

This issue has been present since the introduction of this function
in 2009:

    Btrfs: Add btrfs_duplicate_item
    commit ad48fd754676bfae4139be1a897b1ea58f9aaf21

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/ctree.c