| From c1d956c0330dc6e6c4706027bf8c77e7fee97c00 Mon Sep 17 00:00:00 2001 |
| From: Josef Bacik <josef@toxicpanda.com> |
| Date: Mon, 27 Jul 2020 10:28:05 -0400 |
| Subject: [PATCH] btrfs: only search for left_info if there is no right_info in |
| try_merge_free_space |
| |
| commit bf53d4687b8f3f6b752f091eb85f62369a515dfd upstream. |
| |
| In try_to_merge_free_space we attempt to find entries to the left and |
| right of the entry we are adding to see if they can be merged. We |
| search for an entry past our current info (saved into right_info), and |
| then if right_info exists and it has a rb_prev() we save the rb_prev() |
| into left_info. |
| |
| However there's a slight problem in the case that we have a right_info, |
| but no entry previous to that entry. At that point we will search for |
| an entry just before the info we're attempting to insert. This will |
| simply find right_info again, and assign it to left_info, making them |
| both the same pointer. |
| |
| Now if right_info _can_ be merged with the range we're inserting, we'll |
| add it to the info and free right_info. However further down we'll |
| access left_info, which was right_info, and thus get a use-after-free. |
| |
| Fix this by only searching for the left entry if we don't find a right |
| entry at all. |
| |
| The CVE referenced had a specially crafted file system that could |
| trigger this use-after-free. However with the tree checker improvements |
| we no longer trigger the conditions for the UAF. But the original |
| conditions still apply, hence this fix. |
| |
| Reference: CVE-2019-19448 |
| Fixes: 963030817060 ("Btrfs: use hybrid extents+bitmap rb tree for free space") |
| CC: stable@vger.kernel.org # 4.4+ |
| Signed-off-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c |
| index 4efc36c35dd9..eaf1a31ceaf2 100644 |
| --- a/fs/btrfs/free-space-cache.c |
| +++ b/fs/btrfs/free-space-cache.c |
| @@ -2166,7 +2166,7 @@ static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl, |
| static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl, |
| struct btrfs_free_space *info, bool update_stat) |
| { |
| - struct btrfs_free_space *left_info; |
| + struct btrfs_free_space *left_info = NULL; |
| struct btrfs_free_space *right_info; |
| bool merged = false; |
| u64 offset = info->offset; |
| @@ -2181,7 +2181,7 @@ static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl, |
| if (right_info && rb_prev(&right_info->offset_index)) |
| left_info = rb_entry(rb_prev(&right_info->offset_index), |
| struct btrfs_free_space, offset_index); |
| - else |
| + else if (!right_info) |
| left_info = tree_search_offset(ctl, offset - 1, 0, 0); |
| |
| if (right_info && !right_info->bitmap) { |
| -- |
| 2.27.0 |
| |