diff options
author | Filipe Manana <fdmanana@gmail.com> | 2014-06-29 16:45:40 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-07-03 10:04:10 -0400 |
commit | 14f5979633a67de81b9bd4a36a0eb99125728f9b (patch) | |
tree | 3a54c65611af64935341b49dd1d113f182a5d54e /fs | |
parent | 0aeb8a6e67cddeac1d42cf64795fde0641a1cffb (diff) |
Btrfs: fix use-after-free when cloning a trailing file hole
The transaction handle was being used after being freed.
Cc: Chris Mason <clm@fb.com>
Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ioctl.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 02dc64bbf1cb..2a99f4987bb1 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -3142,7 +3142,6 @@ out: | |||
3142 | static void clone_update_extent_map(struct inode *inode, | 3142 | static void clone_update_extent_map(struct inode *inode, |
3143 | const struct btrfs_trans_handle *trans, | 3143 | const struct btrfs_trans_handle *trans, |
3144 | const struct btrfs_path *path, | 3144 | const struct btrfs_path *path, |
3145 | struct btrfs_file_extent_item *fi, | ||
3146 | const u64 hole_offset, | 3145 | const u64 hole_offset, |
3147 | const u64 hole_len) | 3146 | const u64 hole_len) |
3148 | { | 3147 | { |
@@ -3157,7 +3156,11 @@ static void clone_update_extent_map(struct inode *inode, | |||
3157 | return; | 3156 | return; |
3158 | } | 3157 | } |
3159 | 3158 | ||
3160 | if (fi) { | 3159 | if (path) { |
3160 | struct btrfs_file_extent_item *fi; | ||
3161 | |||
3162 | fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
3163 | struct btrfs_file_extent_item); | ||
3161 | btrfs_extent_item_to_extent_map(inode, path, fi, false, em); | 3164 | btrfs_extent_item_to_extent_map(inode, path, fi, false, em); |
3162 | em->generation = -1; | 3165 | em->generation = -1; |
3163 | if (btrfs_file_extent_type(path->nodes[0], fi) == | 3166 | if (btrfs_file_extent_type(path->nodes[0], fi) == |
@@ -3511,18 +3514,15 @@ process_slot: | |||
3511 | btrfs_item_ptr_offset(leaf, slot), | 3514 | btrfs_item_ptr_offset(leaf, slot), |
3512 | size); | 3515 | size); |
3513 | inode_add_bytes(inode, datal); | 3516 | inode_add_bytes(inode, datal); |
3514 | extent = btrfs_item_ptr(leaf, slot, | ||
3515 | struct btrfs_file_extent_item); | ||
3516 | } | 3517 | } |
3517 | 3518 | ||
3518 | /* If we have an implicit hole (NO_HOLES feature). */ | 3519 | /* If we have an implicit hole (NO_HOLES feature). */ |
3519 | if (drop_start < new_key.offset) | 3520 | if (drop_start < new_key.offset) |
3520 | clone_update_extent_map(inode, trans, | 3521 | clone_update_extent_map(inode, trans, |
3521 | path, NULL, drop_start, | 3522 | NULL, drop_start, |
3522 | new_key.offset - drop_start); | 3523 | new_key.offset - drop_start); |
3523 | 3524 | ||
3524 | clone_update_extent_map(inode, trans, path, | 3525 | clone_update_extent_map(inode, trans, path, 0, 0); |
3525 | extent, 0, 0); | ||
3526 | 3526 | ||
3527 | btrfs_mark_buffer_dirty(leaf); | 3527 | btrfs_mark_buffer_dirty(leaf); |
3528 | btrfs_release_path(path); | 3528 | btrfs_release_path(path); |
@@ -3565,12 +3565,10 @@ process_slot: | |||
3565 | btrfs_end_transaction(trans, root); | 3565 | btrfs_end_transaction(trans, root); |
3566 | goto out; | 3566 | goto out; |
3567 | } | 3567 | } |
3568 | clone_update_extent_map(inode, trans, NULL, last_dest_end, | ||
3569 | destoff + len - last_dest_end); | ||
3568 | ret = clone_finish_inode_update(trans, inode, destoff + len, | 3570 | ret = clone_finish_inode_update(trans, inode, destoff + len, |
3569 | destoff, olen); | 3571 | destoff, olen); |
3570 | if (ret) | ||
3571 | goto out; | ||
3572 | clone_update_extent_map(inode, trans, path, NULL, last_dest_end, | ||
3573 | destoff + len - last_dest_end); | ||
3574 | } | 3572 | } |
3575 | 3573 | ||
3576 | out: | 3574 | out: |