From: Greg Kroah-Hartman Date: Wed, 19 Aug 2020 11:41:43 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v4.14.194~44 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dbb5dc410d5de4054f0fb28db16f912b70e9cf3b;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-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-inode-fix-null-pointer-dereference-if-inode-doesn-t-need-compression.patch btrfs-make-sure-sb_i_version-doesn-t-get-unset-by-remount.patch btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch --- diff --git a/queue-5.4/btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch b/queue-5.4/btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch new file mode 100644 index 00000000000..0dc4a1e3cc1 --- /dev/null +++ b/queue-5.4/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 +@@ -4040,11 +4040,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; + } + } + } +@@ -4057,7 +4054,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-5.4/btrfs-fix-messages-after-changing-compression-level-by-remount.patch b/queue-5.4/btrfs-fix-messages-after-changing-compression-level-by-remount.patch new file mode 100644 index 00000000000..e6cbf5c896d --- /dev/null +++ b/queue-5.4/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 +@@ -435,6 +435,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; + +@@ -517,6 +518,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) { +@@ -561,6 +563,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; +@@ -581,11 +585,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-5.4/btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch b/queue-5.4/btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch new file mode 100644 index 00000000000..4d21bb955da --- /dev/null +++ b/queue-5.4/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 +@@ -7194,7 +7194,7 @@ struct extent_map *btrfs_get_extent(stru + extent_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-5.4/btrfs-inode-fix-null-pointer-dereference-if-inode-doesn-t-need-compression.patch b/queue-5.4/btrfs-inode-fix-null-pointer-dereference-if-inode-doesn-t-need-compression.patch new file mode 100644 index 00000000000..b5b6044af3b --- /dev/null +++ b/queue-5.4/btrfs-inode-fix-null-pointer-dereference-if-inode-doesn-t-need-compression.patch @@ -0,0 +1,105 @@ +From 1e6e238c3002ea3611465ce5f32777ddd6a40126 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Tue, 28 Jul 2020 16:39:26 +0800 +Subject: btrfs: inode: fix NULL pointer dereference if inode doesn't need compression + +From: Qu Wenruo + +commit 1e6e238c3002ea3611465ce5f32777ddd6a40126 upstream. + +[BUG] +There is a bug report of NULL pointer dereference caused in +compress_file_extent(): + + Oops: Kernel access of bad area, sig: 11 [#1] + LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries + Workqueue: btrfs-delalloc btrfs_delalloc_helper [btrfs] + NIP [c008000006dd4d34] compress_file_range.constprop.41+0x75c/0x8a0 [btrfs] + LR [c008000006dd4d1c] compress_file_range.constprop.41+0x744/0x8a0 [btrfs] + Call Trace: + [c000000c69093b00] [c008000006dd4d1c] compress_file_range.constprop.41+0x744/0x8a0 [btrfs] (unreliable) + [c000000c69093bd0] [c008000006dd4ebc] async_cow_start+0x44/0xa0 [btrfs] + [c000000c69093c10] [c008000006e14824] normal_work_helper+0xdc/0x598 [btrfs] + [c000000c69093c80] [c0000000001608c0] process_one_work+0x2c0/0x5b0 + [c000000c69093d10] [c000000000160c38] worker_thread+0x88/0x660 + [c000000c69093db0] [c00000000016b55c] kthread+0x1ac/0x1c0 + [c000000c69093e20] [c00000000000b660] ret_from_kernel_thread+0x5c/0x7c + ---[ end trace f16954aa20d822f6 ]--- + +[CAUSE] +For the following execution route of compress_file_range(), it's +possible to hit NULL pointer dereference: + + compress_file_extent() + |- pages = NULL; + |- start = async_chunk->start = 0; + |- end = async_chunk = 4095; + |- nr_pages = 1; + |- inode_need_compress() == false; <<< Possible, see later explanation + | Now, we have nr_pages = 1, pages = NULL + |- cont: + |- ret = cow_file_range_inline(); + |- if (ret <= 0) { + |- for (i = 0; i < nr_pages; i++) { + |- WARN_ON(pages[i]->mapping); <<< Crash + +To enter above call execution branch, we need the following race: + + Thread 1 (chattr) | Thread 2 (writeback) +--------------------------+------------------------------ + | btrfs_run_delalloc_range + | |- inode_need_compress = true + | |- cow_file_range_async() +btrfs_ioctl_set_flag() | +|- binode_flags |= | + BTRFS_INODE_NOCOMPRESS | + | compress_file_range() + | |- inode_need_compress = false + | |- nr_page = 1 while pages = NULL + | | Then hit the crash + +[FIX] +This patch will fix it by checking @pages before doing accessing it. +This patch is only designed as a hot fix and easy to backport. + +More elegant fix may make btrfs only check inode_need_compress() once to +avoid such race, but that would be another story. + +Reported-by: Luciano Chavez +Fixes: 4d3a800ebb12 ("btrfs: merge nr_pages input and output parameter in compress_pages") +CC: stable@vger.kernel.org # 4.14.x: cecc8d9038d16: btrfs: Move free_pages_out label in inline extent handling branch in compress_file_range +CC: stable@vger.kernel.org # 4.14+ +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/inode.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -641,12 +641,18 @@ cont: + page_error_op | + PAGE_END_WRITEBACK); + +- for (i = 0; i < nr_pages; i++) { +- WARN_ON(pages[i]->mapping); +- put_page(pages[i]); ++ /* ++ * Ensure we only free the compressed pages if we have ++ * them allocated, as we can still reach here with ++ * inode_need_compress() == false. ++ */ ++ if (pages) { ++ for (i = 0; i < nr_pages; i++) { ++ WARN_ON(pages[i]->mapping); ++ put_page(pages[i]); ++ } ++ kfree(pages); + } +- kfree(pages); +- + return 0; + } + } diff --git a/queue-5.4/btrfs-make-sure-sb_i_version-doesn-t-get-unset-by-remount.patch b/queue-5.4/btrfs-make-sure-sb_i_version-doesn-t-get-unset-by-remount.patch new file mode 100644 index 00000000000..a6904cdc321 --- /dev/null +++ b/queue-5.4/btrfs-make-sure-sb_i_version-doesn-t-get-unset-by-remount.patch @@ -0,0 +1,44 @@ +From faa008899a4db21a2df99833cb4ff6fa67009a20 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Thu, 30 Jul 2020 11:18:09 -0400 +Subject: btrfs: make sure SB_I_VERSION doesn't get unset by remount + +From: Josef Bacik + +commit faa008899a4db21a2df99833cb4ff6fa67009a20 upstream. + +There's some inconsistency around SB_I_VERSION handling with mount and +remount. Since we don't really want it to be off ever just work around +this by making sure we don't get the flag cleared on remount. + +There's a tiny cpu cost of setting the bit, otherwise all changes to +i_version also change some of the times (ctime/mtime) so the inode needs +to be synced. We wouldn't save anything by disabling it. + +Reported-by: Eric Sandeen +CC: stable@vger.kernel.org # 5.4+ +Signed-off-by: Josef Bacik +Reviewed-by: David Sterba +[ add perf impact analysis ] +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/super.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/fs/btrfs/super.c ++++ b/fs/btrfs/super.c +@@ -1852,6 +1852,12 @@ static int btrfs_remount(struct super_bl + set_bit(BTRFS_FS_OPEN, &fs_info->flags); + } + out: ++ /* ++ * We need to set SB_I_VERSION here otherwise it'll get cleared by VFS, ++ * since the absence of the flag means it can be toggled off by remount. ++ */ ++ *flags |= SB_I_VERSION; ++ + wake_up_process(fs_info->transaction_kthread); + btrfs_remount_cleanup(fs_info, old_opts); + return 0; diff --git a/queue-5.4/btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch b/queue-5.4/btrfs-only-search-for-left_info-if-there-is-no-right_info-in-try_merge_free_space.patch new file mode 100644 index 00000000000..7af0d7138fc --- /dev/null +++ b/queue-5.4/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 +@@ -2166,7 +2166,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; +@@ -2181,7 +2181,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-5.4/series b/queue-5.4/series index 57c693667ff..eeb6544c1fd 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -21,3 +21,9 @@ btrfs-avoid-possible-signal-interruption-of-btrfs_drop_snapshot-on-relocation-tr btrfs-sysfs-use-nofs-for-device-creation.patch btrfs-don-t-warn-if-we-abort-a-transaction-with-erofs.patch btrfs-fix-race-between-page-release-and-a-fast-fsync.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-inode-fix-null-pointer-dereference-if-inode-doesn-t-need-compression.patch +btrfs-fix-memory-leaks-after-failure-to-lookup-checksums-during-inode-logging.patch +btrfs-make-sure-sb_i_version-doesn-t-get-unset-by-remount.patch +btrfs-fix-return-value-mixup-in-btrfs_get_extent.patch