From beb119e2d572bef0f9ca7c18456b691a0c48fe4a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 19 Aug 2020 13:41:28 +0200 Subject: [PATCH] 4.19-stable patches added patches: btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch btrfs-fix-messages-after-changing-compression-level-by-remount.patch btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch --- ...ookup-checksums-during-inode-logging.patch | 54 ++++++++++++ ...hanging-compression-level-by-remount.patch | 84 +++++++++++++++++++ ...turn-value-mixup-in-btrfs_get_extent.patch | 35 ++++++++ ...o-right_info-in-try_merge_free_space.patch | 64 ++++++++++++++ queue-4.19/series | 4 + 5 files changed, 241 insertions(+) create mode 100644 queue-4.19/btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch create mode 100644 queue-4.19/btrfs-fix-messages-after-changing-compression-level-by-remount.patch create mode 100644 queue-4.19/btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch create mode 100644 queue-4.19/btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch diff --git a/queue-4.19/btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch b/queue-4.19/btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch new file mode 100644 index 00000000000..0463b6f4bfa --- /dev/null +++ b/queue-4.19/btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch @@ -0,0 +1,54 @@ +From 4f26433e9b3eb7a55ed70d8f882ae9cd48ba448b Mon Sep 17 00:00:00 2001 +From: Filipe Manana +Date: Wed, 29 Jul 2020 10:17:50 +0100 +Subject: btrfs: fix memory leaks after failure to lookup checksums during inode logging + +From: Filipe Manana + +commit 4f26433e9b3eb7a55ed70d8f882ae9cd48ba448b upstream. + +While logging an inode, at copy_items(), if we fail to lookup the checksums +for an extent we release the destination path, free the ins_data array and +then return immediately. However a previous iteration of the for loop may +have added checksums to the ordered_sums list, in which case we leak the +memory used by them. + +So fix this by making sure we iterate the ordered_sums list and free all +its checksums before returning. + +Fixes: 3650860b90cc2a ("Btrfs: remove almost all of the BUG()'s from tree-log.c") +CC: stable@vger.kernel.org # 4.4+ +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/tree-log.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -3988,11 +3988,8 @@ static noinline int copy_items(struct bt + fs_info->csum_root, + ds + cs, ds + cs + cl - 1, + &ordered_sums, 0); +- if (ret) { +- btrfs_release_path(dst_path); +- kfree(ins_data); +- return ret; +- } ++ if (ret) ++ break; + } + } + } +@@ -4005,7 +4002,6 @@ static noinline int copy_items(struct bt + * we have to do this after the loop above to avoid changing the + * log tree while trying to change the log tree. + */ +- ret = 0; + while (!list_empty(&ordered_sums)) { + struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, + struct btrfs_ordered_sum, diff --git a/queue-4.19/btrfs-fix-messages-after-changing-compression-level-by-remount.patch b/queue-4.19/btrfs-fix-messages-after-changing-compression-level-by-remount.patch new file mode 100644 index 00000000000..843d463fd41 --- /dev/null +++ b/queue-4.19/btrfs-fix-messages-after-changing-compression-level-by-remount.patch @@ -0,0 +1,84 @@ +From 27942c9971cc405c60432eca9395e514a2ae9f5e Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 23 Jul 2020 19:08:55 +0200 +Subject: btrfs: fix messages after changing compression level by remount + +From: David Sterba + +commit 27942c9971cc405c60432eca9395e514a2ae9f5e upstream. + +Reported by Forza on IRC that remounting with compression options does +not reflect the change in level, or at least it does not appear to do so +according to the messages: + + mount -o compress=zstd:1 /dev/sda /mnt + mount -o remount,compress=zstd:15 /mnt + +does not print the change to the level to syslog: + + [ 41.366060] BTRFS info (device vda): use zstd compression, level 1 + [ 41.368254] BTRFS info (device vda): disk space caching is enabled + [ 41.390429] BTRFS info (device vda): disk space caching is enabled + +What really happens is that the message is lost but the level is actualy +changed. + +There's another weird output, if compression is reset to 'no': + + [ 45.413776] BTRFS info (device vda): use no compression, level 4 + +To fix that, save the previous compression level and print the message +in that case too and use separate message for 'no' compression. + +CC: stable@vger.kernel.org # 4.19+ +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/super.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -432,6 +432,7 @@ int btrfs_parse_options(struct btrfs_fs_ + char *compress_type; + bool compress_force = false; + enum btrfs_compression_type saved_compress_type; ++ int saved_compress_level; + bool saved_compress_force; + int no_compress = 0; + +@@ -514,6 +515,7 @@ int btrfs_parse_options(struct btrfs_fs_ + info->compress_type : BTRFS_COMPRESS_NONE; + saved_compress_force = + btrfs_test_opt(info, FORCE_COMPRESS); ++ saved_compress_level = info->compress_level; + if (token == Opt_compress || + token == Opt_compress_force || + strncmp(args[0].from, "zlib", 4) == 0) { +@@ -552,6 +554,8 @@ int btrfs_parse_options(struct btrfs_fs_ + no_compress = 0; + } else if (strncmp(args[0].from, "no", 2) == 0) { + compress_type = "no"; ++ info->compress_level = 0; ++ info->compress_type = 0; + btrfs_clear_opt(info->mount_opt, COMPRESS); + btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS); + compress_force = false; +@@ -572,11 +576,11 @@ int btrfs_parse_options(struct btrfs_fs_ + */ + btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS); + } +- if ((btrfs_test_opt(info, COMPRESS) && +- (info->compress_type != saved_compress_type || +- compress_force != saved_compress_force)) || +- (!btrfs_test_opt(info, COMPRESS) && +- no_compress == 1)) { ++ if (no_compress == 1) { ++ btrfs_info(info, "use no compression"); ++ } else if ((info->compress_type != saved_compress_type) || ++ (compress_force != saved_compress_force) || ++ (info->compress_level != saved_compress_level)) { + btrfs_info(info, "%s %s compression, level %d", + (compress_force) ? "force" : "use", + compress_type, info->compress_level); diff --git a/queue-4.19/btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch b/queue-4.19/btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch new file mode 100644 index 00000000000..0d93dc8e732 --- /dev/null +++ b/queue-4.19/btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch @@ -0,0 +1,35 @@ +From 881a3a11c2b858fe9b69ef79ac5ee9978a266dc9 Mon Sep 17 00:00:00 2001 +From: Pavel Machek +Date: Mon, 3 Aug 2020 11:35:06 +0200 +Subject: btrfs: fix return value mixup in btrfs_get_extent + +From: Pavel Machek + +commit 881a3a11c2b858fe9b69ef79ac5ee9978a266dc9 upstream. + +btrfs_get_extent() sets variable ret, but out: error path expect error +to be in variable err so the error code is lost. + +Fixes: 6bf9e4bd6a27 ("btrfs: inode: Verify inode mode to avoid NULL pointer dereference") +CC: stable@vger.kernel.org # 5.4+ +Reviewed-by: Nikolay Borisov +Signed-off-by: Pavel Machek (CIP) +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -7014,7 +7014,7 @@ struct extent_map *btrfs_get_extent(stru + found_type == BTRFS_FILE_EXTENT_PREALLOC) { + /* Only regular file could have regular/prealloc extent */ + if (!S_ISREG(inode->vfs_inode.i_mode)) { +- ret = -EUCLEAN; ++ err = -EUCLEAN; + btrfs_crit(fs_info, + "regular/prealloc extent found for non-regular inode %llu", + btrfs_ino(inode)); diff --git a/queue-4.19/btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch b/queue-4.19/btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch new file mode 100644 index 00000000000..620d2388578 --- /dev/null +++ b/queue-4.19/btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch @@ -0,0 +1,64 @@ +From bf53d4687b8f3f6b752f091eb85f62369a515dfd Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Mon, 27 Jul 2020 10:28:05 -0400 +Subject: btrfs: only search for left_info if there is no right_info in try_merge_free_space + +From: Josef Bacik + +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 +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/free-space-cache.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/btrfs/free-space-cache.c ++++ b/fs/btrfs/free-space-cache.c +@@ -2169,7 +2169,7 @@ out: + 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; +@@ -2184,7 +2184,7 @@ static bool try_merge_free_space(struct + 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) { diff --git a/queue-4.19/series b/queue-4.19/series index 0ad98c2b3d0..783cfe96ed0 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -11,3 +11,7 @@ btrfs-don-t-allocate-anonymous-block-device-for-user-invisible-roots.patch btrfs-ref-verify-fix-memory-leak-in-add_block_entry.patch btrfs-don-t-traverse-into-the-seed-devices-in-show_devname.patch btrfs-open-device-without-device_list_mutex.patch +btrfs-fix-messages-after-changing-compression-level-by-remount.patch +btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch +btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch +btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch -- 2.47.3