From: Greg Kroah-Hartman Date: Mon, 23 Dec 2024 10:42:18 +0000 (+0100) Subject: 5.10-stable patches X-Git-Tag: v6.1.122~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1c094e478969ab901eb8de5d290113d076004eb1;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: btrfs-tree-checker-reject-inline-extent-items-with-0-ref-count.patch drivers-hv-util-avoid-accessing-a-ringbuffer-not-initialized-yet.patch --- diff --git a/queue-5.10/btrfs-tree-checker-reject-inline-extent-items-with-0-ref-count.patch b/queue-5.10/btrfs-tree-checker-reject-inline-extent-items-with-0-ref-count.patch new file mode 100644 index 00000000000..3eca2345ea0 --- /dev/null +++ b/queue-5.10/btrfs-tree-checker-reject-inline-extent-items-with-0-ref-count.patch @@ -0,0 +1,104 @@ +From dfb92681a19e1d5172420baa242806414b3eff6f Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Wed, 4 Dec 2024 13:30:46 +1030 +Subject: btrfs: tree-checker: reject inline extent items with 0 ref count + +From: Qu Wenruo + +commit dfb92681a19e1d5172420baa242806414b3eff6f upstream. + +[BUG] +There is a bug report in the mailing list where btrfs_run_delayed_refs() +failed to drop the ref count for logical 25870311358464 num_bytes +2113536. + +The involved leaf dump looks like this: + + item 166 key (25870311358464 168 2113536) itemoff 10091 itemsize 50 + extent refs 1 gen 84178 flags 1 + ref#0: shared data backref parent 32399126528000 count 0 <<< + ref#1: shared data backref parent 31808973717504 count 1 + +Notice the count number is 0. + +[CAUSE] +There is no concrete evidence yet, but considering 0 -> 1 is also a +single bit flipped, it's possible that hardware memory bitflip is +involved, causing the on-disk extent tree to be corrupted. + +[FIX] +To prevent us reading such corrupted extent item, or writing such +damaged extent item back to disk, enhance the handling of +BTRFS_EXTENT_DATA_REF_KEY and BTRFS_SHARED_DATA_REF_KEY keys for both +inlined and key items, to detect such 0 ref count and reject them. + +CC: stable@vger.kernel.org # 5.4+ +Link: https://lore.kernel.org/linux-btrfs/7c69dd49-c346-4806-86e7-e6f863a66f48@app.fastmail.com/ +Reported-by: Frankie Fisher +Reviewed-by: Filipe Manana +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/tree-checker.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +--- a/fs/btrfs/tree-checker.c ++++ b/fs/btrfs/tree-checker.c +@@ -1367,6 +1367,11 @@ static int check_extent_item(struct exte + dref_offset, fs_info->sectorsize); + return -EUCLEAN; + } ++ if (unlikely(btrfs_extent_data_ref_count(leaf, dref) == 0)) { ++ extent_err(leaf, slot, ++ "invalid data ref count, should have non-zero value"); ++ return -EUCLEAN; ++ } + inline_refs += btrfs_extent_data_ref_count(leaf, dref); + break; + /* Contains parent bytenr and ref count */ +@@ -1378,6 +1383,11 @@ static int check_extent_item(struct exte + inline_offset, fs_info->sectorsize); + return -EUCLEAN; + } ++ if (unlikely(btrfs_shared_data_ref_count(leaf, sref) == 0)) { ++ extent_err(leaf, slot, ++ "invalid shared data ref count, should have non-zero value"); ++ return -EUCLEAN; ++ } + inline_refs += btrfs_shared_data_ref_count(leaf, sref); + break; + default: +@@ -1429,8 +1439,18 @@ static int check_simple_keyed_refs(struc + { + u32 expect_item_size = 0; + +- if (key->type == BTRFS_SHARED_DATA_REF_KEY) ++ if (key->type == BTRFS_SHARED_DATA_REF_KEY) { ++ struct btrfs_shared_data_ref *sref; ++ ++ sref = btrfs_item_ptr(leaf, slot, struct btrfs_shared_data_ref); ++ if (unlikely(btrfs_shared_data_ref_count(leaf, sref) == 0)) { ++ extent_err(leaf, slot, ++ "invalid shared data backref count, should have non-zero value"); ++ return -EUCLEAN; ++ } ++ + expect_item_size = sizeof(struct btrfs_shared_data_ref); ++ } + + if (btrfs_item_size_nr(leaf, slot) != expect_item_size) { + generic_err(leaf, slot, +@@ -1490,6 +1510,11 @@ static int check_extent_data_ref(struct + offset, leaf->fs_info->sectorsize); + return -EUCLEAN; + } ++ if (unlikely(btrfs_extent_data_ref_count(leaf, dref) == 0)) { ++ extent_err(leaf, slot, ++ "invalid extent data backref count, should have non-zero value"); ++ return -EUCLEAN; ++ } + } + return 0; + } diff --git a/queue-5.10/drivers-hv-util-avoid-accessing-a-ringbuffer-not-initialized-yet.patch b/queue-5.10/drivers-hv-util-avoid-accessing-a-ringbuffer-not-initialized-yet.patch new file mode 100644 index 00000000000..b8c203b56aa --- /dev/null +++ b/queue-5.10/drivers-hv-util-avoid-accessing-a-ringbuffer-not-initialized-yet.patch @@ -0,0 +1,169 @@ +From 07a756a49f4b4290b49ea46e089cbe6f79ff8d26 Mon Sep 17 00:00:00 2001 +From: Michael Kelley +Date: Wed, 6 Nov 2024 07:42:47 -0800 +Subject: Drivers: hv: util: Avoid accessing a ringbuffer not initialized yet + +From: Michael Kelley + +commit 07a756a49f4b4290b49ea46e089cbe6f79ff8d26 upstream. + +If the KVP (or VSS) daemon starts before the VMBus channel's ringbuffer is +fully initialized, we can hit the panic below: + +hv_utils: Registering HyperV Utility Driver +hv_vmbus: registering driver hv_utils +... +BUG: kernel NULL pointer dereference, address: 0000000000000000 +CPU: 44 UID: 0 PID: 2552 Comm: hv_kvp_daemon Tainted: G E 6.11.0-rc3+ #1 +RIP: 0010:hv_pkt_iter_first+0x12/0xd0 +Call Trace: +... + vmbus_recvpacket + hv_kvp_onchannelcallback + vmbus_on_event + tasklet_action_common + tasklet_action + handle_softirqs + irq_exit_rcu + sysvec_hyperv_stimer0 + + + asm_sysvec_hyperv_stimer0 +... + kvp_register_done + hvt_op_read + vfs_read + ksys_read + __x64_sys_read + +This can happen because the KVP/VSS channel callback can be invoked +even before the channel is fully opened: +1) as soon as hv_kvp_init() -> hvutil_transport_init() creates +/dev/vmbus/hv_kvp, the kvp daemon can open the device file immediately and +register itself to the driver by writing a message KVP_OP_REGISTER1 to the +file (which is handled by kvp_on_msg() ->kvp_handle_handshake()) and +reading the file for the driver's response, which is handled by +hvt_op_read(), which calls hvt->on_read(), i.e. kvp_register_done(). + +2) the problem with kvp_register_done() is that it can cause the +channel callback to be called even before the channel is fully opened, +and when the channel callback is starting to run, util_probe()-> +vmbus_open() may have not initialized the ringbuffer yet, so the +callback can hit the panic of NULL pointer dereference. + +To reproduce the panic consistently, we can add a "ssleep(10)" for KVP in +__vmbus_open(), just before the first hv_ringbuffer_init(), and then we +unload and reload the driver hv_utils, and run the daemon manually within +the 10 seconds. + +Fix the panic by reordering the steps in util_probe() so the char dev +entry used by the KVP or VSS daemon is not created until after +vmbus_open() has completed. This reordering prevents the race condition +from happening. + +Reported-by: Dexuan Cui +Fixes: e0fa3e5e7df6 ("Drivers: hv: utils: fix a race on userspace daemons registration") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Kelley +Acked-by: Wei Liu +Link: https://lore.kernel.org/r/20241106154247.2271-3-mhklinux@outlook.com +Signed-off-by: Wei Liu +Message-ID: <20241106154247.2271-3-mhklinux@outlook.com> +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hv/hv_kvp.c | 6 ++++++ + drivers/hv/hv_snapshot.c | 6 ++++++ + drivers/hv/hv_util.c | 9 +++++++++ + drivers/hv/hyperv_vmbus.h | 2 ++ + include/linux/hyperv.h | 1 + + 5 files changed, 24 insertions(+) + +--- a/drivers/hv/hv_kvp.c ++++ b/drivers/hv/hv_kvp.c +@@ -750,6 +750,12 @@ hv_kvp_init(struct hv_util_service *srv) + */ + kvp_transaction.state = HVUTIL_DEVICE_INIT; + ++ return 0; ++} ++ ++int ++hv_kvp_init_transport(void) ++{ + hvt = hvutil_transport_init(kvp_devname, CN_KVP_IDX, CN_KVP_VAL, + kvp_on_msg, kvp_on_reset); + if (!hvt) +--- a/drivers/hv/hv_snapshot.c ++++ b/drivers/hv/hv_snapshot.c +@@ -369,6 +369,12 @@ hv_vss_init(struct hv_util_service *srv) + */ + vss_transaction.state = HVUTIL_DEVICE_INIT; + ++ return 0; ++} ++ ++int ++hv_vss_init_transport(void) ++{ + hvt = hvutil_transport_init(vss_devname, CN_VSS_IDX, CN_VSS_VAL, + vss_on_msg, vss_on_reset); + if (!hvt) { +--- a/drivers/hv/hv_util.c ++++ b/drivers/hv/hv_util.c +@@ -142,6 +142,7 @@ static struct hv_util_service util_heart + static struct hv_util_service util_kvp = { + .util_cb = hv_kvp_onchannelcallback, + .util_init = hv_kvp_init, ++ .util_init_transport = hv_kvp_init_transport, + .util_pre_suspend = hv_kvp_pre_suspend, + .util_pre_resume = hv_kvp_pre_resume, + .util_deinit = hv_kvp_deinit, +@@ -150,6 +151,7 @@ static struct hv_util_service util_kvp = + static struct hv_util_service util_vss = { + .util_cb = hv_vss_onchannelcallback, + .util_init = hv_vss_init, ++ .util_init_transport = hv_vss_init_transport, + .util_pre_suspend = hv_vss_pre_suspend, + .util_pre_resume = hv_vss_pre_resume, + .util_deinit = hv_vss_deinit, +@@ -539,6 +541,13 @@ static int util_probe(struct hv_device * + if (ret) + goto error; + ++ if (srv->util_init_transport) { ++ ret = srv->util_init_transport(); ++ if (ret) { ++ vmbus_close(dev->channel); ++ goto error; ++ } ++ } + return 0; + + error: +--- a/drivers/hv/hyperv_vmbus.h ++++ b/drivers/hv/hyperv_vmbus.h +@@ -357,12 +357,14 @@ void vmbus_on_event(unsigned long data); + void vmbus_on_msg_dpc(unsigned long data); + + int hv_kvp_init(struct hv_util_service *srv); ++int hv_kvp_init_transport(void); + void hv_kvp_deinit(void); + int hv_kvp_pre_suspend(void); + int hv_kvp_pre_resume(void); + void hv_kvp_onchannelcallback(void *context); + + int hv_vss_init(struct hv_util_service *srv); ++int hv_vss_init_transport(void); + void hv_vss_deinit(void); + int hv_vss_pre_suspend(void); + int hv_vss_pre_resume(void); +--- a/include/linux/hyperv.h ++++ b/include/linux/hyperv.h +@@ -1510,6 +1510,7 @@ struct hv_util_service { + void *channel; + void (*util_cb)(void *); + int (*util_init)(struct hv_util_service *); ++ int (*util_init_transport)(void); + void (*util_deinit)(void); + int (*util_pre_suspend)(void); + int (*util_pre_resume)(void); diff --git a/queue-5.10/series b/queue-5.10/series index bcd8d461dc9..42d17d60bc3 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -31,3 +31,5 @@ drm-modes-avoid-divide-by-zero-harder-in-drm_mode_vrefresh.patch hwmon-tmp513-fix-interpretation-of-values-of-tempera.patch sh-clk-fix-clk_enable-to-return-0-on-null-clk.patch zram-refuse-to-use-zero-sized-block-device-as-backing-device.patch +btrfs-tree-checker-reject-inline-extent-items-with-0-ref-count.patch +drivers-hv-util-avoid-accessing-a-ringbuffer-not-initialized-yet.patch