--- /dev/null
+From d63c219b7ff39f897da10c160a2edef76320f16c Mon Sep 17 00:00:00 2001
+From: Tommaso Soncin <soncintommaso@gmail.com>
+Date: Wed, 29 Apr 2026 18:08:57 +0200
+Subject: ASoC: amd: yc: Add HP OMEN Gaming Laptop 16-ap0xxx product line in quirk table
+
+From: Tommaso Soncin <soncintommaso@gmail.com>
+
+commit d63c219b7ff39f897da10c160a2edef76320f16c upstream.
+
+Add a DMI quirk for the HP OMEN Gaming Laptop 16-ap0xxx line fixing the
+issue where the internal microphone was not detected.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Tommaso Soncin <soncintommaso@gmail.com>
+Link: https://patch.msgid.link/20260429160858.538986-1-soncintommaso@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/amd/yc/acp6x-mach.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/sound/soc/amd/yc/acp6x-mach.c
++++ b/sound/soc/amd/yc/acp6x-mach.c
+@@ -55,6 +55,13 @@ static const struct dmi_system_id yc_acp
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
++ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Gaming Laptop 16-ap0xxx"),
++ }
++ },
++ {
++ .driver_data = &acp6x_card,
++ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5525"),
+ }
+@@ -655,6 +662,13 @@ static const struct dmi_system_id yc_acp
+ }
+ },
+ {
++ .driver_data = &acp6x_card,
++ .matches = {
++ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
++ DMI_MATCH(DMI_BOARD_NAME, "8E35"),
++ }
++ },
++ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "MECHREVO"),
--- /dev/null
+From 8ed3311131077712cdd0b3afec6909b9388ad3e4 Mon Sep 17 00:00:00 2001
+From: Li Jian <lazycat-xiao@foxmail.com>
+Date: Fri, 17 Apr 2026 18:53:14 +0800
+Subject: ASoC: ES8389: convert to devm_clk_get_optional() to get clock
+
+From: Li Jian <lazycat-xiao@foxmail.com>
+
+commit 8ed3311131077712cdd0b3afec6909b9388ad3e4 upstream.
+
+When enabling ES8390 via ACPI description, es8389 would fail to
+obtain a clock source, causing the driver to fail to initialize.
+This was not an issue with older kernels, but since commit
+abae8e57e49a ("clk: generalize devm_clk_get() a bit"),
+devm_clk_get() would return an error pointer when a clock source
+was not detected (instead of falling back to a static clock),
+causing the driver to fail early.
+
+Use devm_clk_get_optional() instead to return to the previous
+behaviour, allowing the use of a static clock source.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Li Jian <lazycat-xiao@foxmail.com>
+Link: https://patch.msgid.link/tencent_7C78374FB9F4B3A37101E5C719715D8BC40A@qq.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/codecs/es8389.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/es8389.c
++++ b/sound/soc/codecs/es8389.c
+@@ -892,7 +892,7 @@ static int es8389_probe(struct snd_soc_c
+ return ret;
+ }
+
+- es8389->mclk = devm_clk_get(component->dev, "mclk");
++ es8389->mclk = devm_clk_get_optional(component->dev, "mclk");
+ if (IS_ERR(es8389->mclk))
+ return dev_err_probe(component->dev, PTR_ERR(es8389->mclk),
+ "ES8389 is unable to get mclk\n");
--- /dev/null
+From 804dce6c73fdfa44184ee4e8b09abad7f5da408f Mon Sep 17 00:00:00 2001
+From: Joseph Salisbury <joseph.salisbury@oracle.com>
+Date: Mon, 16 Mar 2026 14:05:45 -0400
+Subject: ASoC: fsl_easrc: fix comment typo
+
+From: Joseph Salisbury <joseph.salisbury@oracle.com>
+
+commit 804dce6c73fdfa44184ee4e8b09abad7f5da408f upstream.
+
+The file contains a spelling error in a source comment (funciton).
+
+Typos in comments reduce readability and make text searches less reliable
+for developers and maintainers.
+
+Replace 'funciton' with 'function' in the affected comment. This is a
+comment-only cleanup and does not change behavior.
+
+Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers")
+Cc: stable@vger.kernel.org
+Signed-off-by: Joseph Salisbury <joseph.salisbury@oracle.com>
+Link: https://patch.msgid.link/20260316180545.144032-1-joseph.salisbury@oracle.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/fsl/fsl_easrc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/fsl/fsl_easrc.c
++++ b/sound/soc/fsl/fsl_easrc.c
+@@ -1286,7 +1286,7 @@ static int fsl_easrc_request_context(int
+ /*
+ * Release the context
+ *
+- * This funciton is mainly doing the revert thing in request context
++ * This function is mainly doing the revert thing in request context
+ */
+ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
+ {
--- /dev/null
+From 13d30682e8dee191ac04e93642f0372a723e8b0c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= <cassiogabrielcontato@gmail.com>
+Date: Mon, 27 Apr 2026 23:38:41 -0300
+Subject: ASoC: Intel: bytcr_wm5102: Fix MCLK leak on platform_clock_control error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+
+commit 13d30682e8dee191ac04e93642f0372a723e8b0c upstream.
+
+If byt_wm5102_prepare_and_enable_pll1() fails in the
+SND_SOC_DAPM_EVENT_ON() path, platform_clock_control() returns after
+clk_prepare_enable(priv->mclk) without disabling the clock again.
+
+This leaks an MCLK enable reference on failed power-up attempts. Add the
+missing clk_disable_unprepare() on the error path, matching the unwind
+used by the other Intel platform_clock_control() implementations.
+
+Fixes: 9a87fc1e0619 ("ASoC: Intel: bytcr_wm5102: Add machine driver for BYT/WM5102")
+Cc: stable@vger.kernel.org
+Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
+Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260427-bytcr-wm5102-mclk-leak-v1-1-02b96d08e99c@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/intel/boards/bytcr_wm5102.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/soc/intel/boards/bytcr_wm5102.c
++++ b/sound/soc/intel/boards/bytcr_wm5102.c
+@@ -170,6 +170,7 @@ static int platform_clock_control(struct
+ ret = byt_wm5102_prepare_and_enable_pll1(codec_dai, 48000);
+ if (ret) {
+ dev_err(card->dev, "Error setting codec sysclk: %d\n", ret);
++ clk_disable_unprepare(priv->mclk);
+ return ret;
+ }
+ } else {
--- /dev/null
+From cab45ab95ce7600fc0ff84585c77fd45b7b0d67c Mon Sep 17 00:00:00 2001
+From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+Date: Thu, 2 Apr 2026 08:11:10 +0000
+Subject: ASoC: qcom: q6apm-dai: reset queue ptr on trigger stop
+
+From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+
+commit cab45ab95ce7600fc0ff84585c77fd45b7b0d67c upstream.
+
+Reset queue pointer on SNDRV_PCM_TRIGGER_STOP event to be inline
+with resetting appl_ptr. Without this we will end up with a queue_ptr
+out of sync and driver could try to send data that is not ready yet.
+
+Fix this by resetting the queue_ptr.
+
+Fixes: 3d4a4411aa8bb ("ASoC: q6apm-dai: schedule all available frames to avoid dsp under-runs")
+Cc: Stable@vger.kernel.org
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260402081118.348071-6-srinivas.kandagatla@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/qcom/qdsp6/q6apm-dai.c | 1 +
+ sound/soc/qcom/qdsp6/q6apm.c | 2 ++
+ 2 files changed, 3 insertions(+)
+
+--- a/sound/soc/qcom/qdsp6/q6apm-dai.c
++++ b/sound/soc/qcom/qdsp6/q6apm-dai.c
+@@ -317,6 +317,7 @@ static int q6apm_dai_trigger(struct snd_
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* TODO support be handled via SoftPause Module */
+ prtd->state = Q6APM_STREAM_STOPPED;
++ prtd->queue_ptr = 0;
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+--- a/sound/soc/qcom/qdsp6/q6apm.c
++++ b/sound/soc/qcom/qdsp6/q6apm.c
+@@ -215,6 +215,8 @@ int q6apm_map_memory_regions(struct q6ap
+
+ mutex_lock(&graph->lock);
+
++ data->dsp_buf = 0;
++
+ if (data->buf) {
+ mutex_unlock(&graph->lock);
+ return 0;
--- /dev/null
+From 69acc488aaf39d0ddf6c3cf0e47c1873d39919a2 Mon Sep 17 00:00:00 2001
+From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+Date: Thu, 2 Apr 2026 08:11:09 +0000
+Subject: ASoC: qcom: q6apm-lpass-dai: Fix multiple graph opens
+
+From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+
+commit 69acc488aaf39d0ddf6c3cf0e47c1873d39919a2 upstream.
+
+As prepare can be called mulitple times, this can result in multiple
+graph opens for playback path.
+
+This will result in a memory leaks, fix this by adding a check before
+opening.
+
+Fixes: be1fae62cf25 ("ASoC: q6apm-lpass-dai: close graph on prepare errors")
+Cc: Stable@vger.kernel.org
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260402081118.348071-5-srinivas.kandagatla@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
++++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+@@ -181,7 +181,7 @@ static int q6apm_lpass_dai_prepare(struc
+ * It is recommend to load DSP with source graph first and then sink
+ * graph, so sequence for playback and capture will be different
+ */
+- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai_data->graph[dai->id] == NULL) {
+ graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id);
+ if (IS_ERR(graph)) {
+ dev_err(dai->dev, "Failed to open graph (%d)\n", graph_id);
--- /dev/null
+From 4a0e1bcc98f7281d1605768bd2fe71eacc34f9b7 Mon Sep 17 00:00:00 2001
+From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+Date: Thu, 2 Apr 2026 08:11:07 +0000
+Subject: ASoC: qcom: q6apm: remove child devices when apm is removed
+
+From: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+
+commit 4a0e1bcc98f7281d1605768bd2fe71eacc34f9b7 upstream.
+
+looks like q6apm driver does not remove the child driver q6apm-dai and
+q6apm-bedais when the this driver is removed.
+
+Fix this by depopulating them in remove callback.
+
+With this change when the dsp is shutdown all the devices associated with
+q6apm will now be removed.
+
+Fixes: 5477518b8a0e ("ASoC: qdsp6: audioreach: add q6apm support")
+Cc: Stable@vger.kernel.org
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260402081118.348071-3-srinivas.kandagatla@oss.qualcomm.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/qcom/qdsp6/q6apm.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/soc/qcom/qdsp6/q6apm.c
++++ b/sound/soc/qcom/qdsp6/q6apm.c
+@@ -764,6 +764,7 @@ static int apm_probe(gpr_device_t *gdev)
+
+ static void apm_remove(gpr_device_t *gdev)
+ {
++ of_platform_depopulate(&gdev->dev);
+ snd_soc_unregister_component(&gdev->dev);
+ }
+
--- /dev/null
+From 2e0e3716c7b6f8d71df2fbe709b922e54700f71b Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Mon, 16 Feb 2026 13:19:38 +1030
+Subject: btrfs: do not mark inode incompressible after inline attempt fails
+
+From: Qu Wenruo <wqu@suse.com>
+
+commit 2e0e3716c7b6f8d71df2fbe709b922e54700f71b upstream.
+
+[BUG]
+The following sequence will set the file with nocompress flag:
+
+ # mkfs.btrfs -f $dev
+ # mount $dev $mnt -o max_inline=4,compress
+ # xfs_io -f -c "pwrite 0 2k" -c sync $mnt/foobar
+
+The inode will have NOCOMPRESS flag, even if the content itself (all 0xcd)
+can still be compressed very well:
+
+ item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160
+ generation 9 transid 10 size 2097152 nbytes 1052672
+ block group 0 mode 100600 links 1 uid 0 gid 0 rdev 0
+ sequence 257 flags 0x8(NOCOMPRESS)
+
+Please note that, this behavior is there even before commit 59615e2c1f63
+("btrfs: reject single block sized compression early").
+
+[CAUSE]
+At compress_file_range(), after btrfs_compress_folios() call, we try
+making an inlined extent by calling cow_file_range_inline().
+
+But cow_file_range_inline() calls can_cow_file_range_inline() which has
+more accurate checks on if the range can be inlined.
+
+One of the user configurable conditions is the "max_inline=" mount
+option. If that value is set low (like the example, 4 bytes, which
+cannot store any header), or the compressed content is just slightly
+larger than 2K (the default value, meaning a 50% compression ratio),
+cow_file_range_inline() will return 1 immediately.
+
+And since we're here only to try inline the compressed data, the range
+is no larger than a single fs block.
+
+Thus compression is never going to make it a win, we fall back to
+marking the inode incompressible unavoidably.
+
+[FIX]
+Just add an extra check after inline attempt, so that if the inline
+attempt failed, do not set the nocompress flag.
+
+As there is no way to remove that flag, and the default 50% compression
+ratio is way too strict for the whole inode.
+
+CC: stable@vger.kernel.org # 6.12+
+Reviewed-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/inode.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -1060,6 +1060,12 @@ again:
+ mapping_set_error(mapping, -EIO);
+ return;
+ }
++ /*
++ * If a single block at file offset 0 cannot be inlined, fall back to
++ * regular writes without marking the file incompressible.
++ */
++ if (start == 0 && end <= blocksize)
++ goto cleanup_and_bail_uncompressed;
+
+ /*
+ * We aren't doing an inline extent. Round the compressed size up to a
--- /dev/null
+From 973e57c726c1f8e77259d1c8e519519f1e9aea77 Mon Sep 17 00:00:00 2001
+From: Yochai Eisenrich <yochaie@sweet.security>
+Date: Sun, 22 Mar 2026 08:39:35 +0200
+Subject: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead to info-leak
+
+From: Yochai Eisenrich <yochaie@sweet.security>
+
+commit 973e57c726c1f8e77259d1c8e519519f1e9aea77 upstream.
+
+btrfs_ioctl_space_info() has a TOCTOU race between two passes over the
+block group RAID type lists. The first pass counts entries to determine
+the allocation size, then the second pass fills the buffer. The
+groups_sem rwlock is released between passes, allowing concurrent block
+group removal to reduce the entry count.
+
+When the second pass fills fewer entries than the first pass counted,
+copy_to_user() copies the full alloc_size bytes including trailing
+uninitialized kmalloc bytes to userspace.
+
+Fix by copying only total_spaces entries (the actually-filled count from
+the second pass) instead of alloc_size bytes, and switch to kzalloc so
+any future copy size mismatch cannot leak heap data.
+
+Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl")
+CC: stable@vger.kernel.org # 3.0
+Signed-off-by: Yochai Eisenrich <echelonh@gmail.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ioctl.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -2897,7 +2897,7 @@ static long btrfs_ioctl_space_info(struc
+ return -ENOMEM;
+
+ space_args.total_spaces = 0;
+- dest = kmalloc(alloc_size, GFP_KERNEL);
++ dest = kzalloc(alloc_size, GFP_KERNEL);
+ if (!dest)
+ return -ENOMEM;
+ dest_orig = dest;
+@@ -2953,7 +2953,8 @@ static long btrfs_ioctl_space_info(struc
+ user_dest = (struct btrfs_ioctl_space_info __user *)
+ (arg + sizeof(struct btrfs_ioctl_space_args));
+
+- if (copy_to_user(user_dest, dest_orig, alloc_size))
++ if (copy_to_user(user_dest, dest_orig,
++ space_args.total_spaces * sizeof(*dest_orig)))
+ return -EFAULT;
+
+ out:
--- /dev/null
+From 3f487be81292702a59ea9dbc4088b3360a50e837 Mon Sep 17 00:00:00 2001
+From: Guangshuo Li <lgs201920130244@gmail.com>
+Date: Wed, 1 Apr 2026 18:56:19 +0800
+Subject: btrfs: fix double free in create_space_info() error path
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+commit 3f487be81292702a59ea9dbc4088b3360a50e837 upstream.
+
+When kobject_init_and_add() fails, the call chain is:
+
+create_space_info()
+-> btrfs_sysfs_add_space_info_type()
+-> kobject_init_and_add()
+-> failure
+-> kobject_put(&space_info->kobj)
+-> space_info_release()
+-> kfree(space_info)
+
+Then control returns to create_space_info():
+
+btrfs_sysfs_add_space_info_type() returns error
+-> goto out_free
+-> kfree(space_info)
+
+This causes a double free.
+
+Keep the direct kfree(space_info) for the earlier failure path, but
+after btrfs_sysfs_add_space_info_type() has called kobject_put(), let
+the kobject release callback handle the cleanup.
+
+Fixes: a11224a016d6d ("btrfs: fix memory leaks in create_space_info() error paths")
+CC: stable@vger.kernel.org # 6.19+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/space-info.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/btrfs/space-info.c
++++ b/fs/btrfs/space-info.c
+@@ -311,7 +311,7 @@ static int create_space_info(struct btrf
+
+ ret = btrfs_sysfs_add_space_info_type(space_info);
+ if (ret)
+- goto out_free;
++ return ret;
+
+ list_add(&space_info->list, &info->space_info);
+ if (flags & BTRFS_BLOCK_GROUP_DATA)
--- /dev/null
+From a7449edf96143f192606ec8647e3167e1ecbd728 Mon Sep 17 00:00:00 2001
+From: Guangshuo Li <lgs201920130244@gmail.com>
+Date: Wed, 1 Apr 2026 19:02:19 +0800
+Subject: btrfs: fix double free in create_space_info_sub_group() error path
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+commit a7449edf96143f192606ec8647e3167e1ecbd728 upstream.
+
+When kobject_init_and_add() fails, the call chain is:
+
+create_space_info_sub_group()
+-> btrfs_sysfs_add_space_info_type()
+-> kobject_init_and_add()
+-> failure
+-> kobject_put(&sub_group->kobj)
+-> space_info_release()
+-> kfree(sub_group)
+
+Then control returns to create_space_info_sub_group(), where:
+
+btrfs_sysfs_add_space_info_type() returns error
+-> kfree(sub_group)
+
+Thus, sub_group is freed twice.
+
+Keep parent->sub_group[index] = NULL for the failure path, but after
+btrfs_sysfs_add_space_info_type() has called kobject_put(), let the
+kobject release callback handle the cleanup.
+
+Fixes: f92ee31e031c ("btrfs: introduce btrfs_space_info sub-group")
+CC: stable@vger.kernel.org # 6.18+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/space-info.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/fs/btrfs/space-info.c
++++ b/fs/btrfs/space-info.c
+@@ -276,10 +276,8 @@ static int create_space_info_sub_group(s
+ sub_group->subgroup_id = id;
+
+ ret = btrfs_sysfs_add_space_info_type(sub_group);
+- if (ret) {
+- kfree(sub_group);
++ if (ret)
+ parent->sub_group[index] = NULL;
+- }
+ return ret;
+ }
+
--- /dev/null
+From 999757231c49376cd1a37308d2c8c4c9932571e1 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Thu, 9 Apr 2026 15:46:51 +0100
+Subject: btrfs: fix missing last_unlink_trans update when removing a directory
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit 999757231c49376cd1a37308d2c8c4c9932571e1 upstream.
+
+When removing a directory we are not updating its last_unlink_trans field,
+which can result in incorrect fsync behaviour in case some one fsyncs the
+directory after it was removed because it's holding a file descriptor on
+it.
+
+Example scenario:
+
+ mkdir /mnt/dir1
+ mkdir /mnt/dir1/dir2
+ mkdir /mnt/dir3
+
+ sync -f /mnt
+
+ # Do some change to the directory and fsync it.
+ chmod 700 /mnt/dir1
+ xfs_io -c fsync /mnt/dir1
+
+ # Move dir2 out of dir1 so that dir1 becomes empty.
+ mv /mnt/dir1/dir2 /mnt/dir3/
+
+ open fd on /mnt/dir1
+ call rmdir(2) on path "/mnt/dir1"
+ fsync fd
+
+ <trigger power failure>
+
+When attempting to mount the filesystem, the log replay will fail with
+an -EIO error and dmesg/syslog has the following:
+
+ [445771.626482] BTRFS info (device dm-0): first mount of filesystem 0368bbea-6c5e-44b5-b409-09abe496e650
+ [445771.626486] BTRFS info (device dm-0): using crc32c checksum algorithm
+ [445771.627912] BTRFS info (device dm-0): start tree-log replay
+ [445771.628335] page: refcount:2 mapcount:0 mapping:0000000061443ddc index:0x1d00 pfn:0x7072a5
+ [445771.629453] memcg:ffff89f400351b00
+ [445771.629892] aops:btree_aops [btrfs] ino:1
+ [445771.630737] flags: 0x17fffc00000402a(uptodate|lru|private|writeback|node=0|zone=2|lastcpupid=0x1ffff)
+ [445771.632359] raw: 017fffc00000402a fffff47284d950c8 fffff472907b7c08 ffff89f458e412b8
+ [445771.633713] raw: 0000000000001d00 ffff89f6c51d1a90 00000002ffffffff ffff89f400351b00
+ [445771.635029] page dumped because: eb page dump
+ [445771.635825] BTRFS critical (device dm-0): corrupt leaf: root=5 block=30408704 slot=10 ino=258, invalid nlink: has 2 expect no more than 1 for dir
+ [445771.638088] BTRFS info (device dm-0): leaf 30408704 gen 10 total ptrs 17 free space 14878 owner 5
+ [445771.638091] BTRFS info (device dm-0): refs 4 lock_owner 0 current 3581087
+ [445771.638094] item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160
+ [445771.638097] inode generation 3 transid 9 size 16 nbytes 16384
+ [445771.638098] block group 0 mode 40755 links 1 uid 0 gid 0
+ [445771.638100] rdev 0 sequence 2 flags 0x0
+ [445771.638102] atime 1775744884.0
+ [445771.660056] ctime 1775744885.645502983
+ [445771.660058] mtime 1775744885.645502983
+ [445771.660060] otime 1775744884.0
+ [445771.660062] item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12
+ [445771.660064] index 0 name_len 2
+ [445771.660066] item 2 key (256 DIR_ITEM 1843588421) itemoff 16077 itemsize 34
+ [445771.660068] location key (259 1 0) type 2
+ [445771.660070] transid 9 data_len 0 name_len 4
+ [445771.660075] item 3 key (256 DIR_ITEM 2363071922) itemoff 16043 itemsize 34
+ [445771.660076] location key (257 1 0) type 2
+ [445771.660077] transid 9 data_len 0 name_len 4
+ [445771.660078] item 4 key (256 DIR_INDEX 2) itemoff 16009 itemsize 34
+ [445771.660079] location key (257 1 0) type 2
+ [445771.660080] transid 9 data_len 0 name_len 4
+ [445771.660081] item 5 key (256 DIR_INDEX 3) itemoff 15975 itemsize 34
+ [445771.660082] location key (259 1 0) type 2
+ [445771.660083] transid 9 data_len 0 name_len 4
+ [445771.660084] item 6 key (257 INODE_ITEM 0) itemoff 15815 itemsize 160
+ [445771.660086] inode generation 9 transid 9 size 8 nbytes 0
+ [445771.660087] block group 0 mode 40777 links 1 uid 0 gid 0
+ [445771.660088] rdev 0 sequence 2 flags 0x0
+ [445771.660089] atime 1775744885.641174097
+ [445771.660090] ctime 1775744885.645502983
+ [445771.660091] mtime 1775744885.645502983
+ [445771.660105] otime 1775744885.641174097
+ [445771.660106] item 7 key (257 INODE_REF 256) itemoff 15801 itemsize 14
+ [445771.660107] index 2 name_len 4
+ [445771.660108] item 8 key (257 DIR_ITEM 2676584006) itemoff 15767 itemsize 34
+ [445771.660109] location key (258 1 0) type 2
+ [445771.660110] transid 9 data_len 0 name_len 4
+ [445771.660111] item 9 key (257 DIR_INDEX 2) itemoff 15733 itemsize 34
+ [445771.660112] location key (258 1 0) type 2
+ [445771.660113] transid 9 data_len 0 name_len 4
+ [445771.660114] item 10 key (258 INODE_ITEM 0) itemoff 15573 itemsize 160
+ [445771.660115] inode generation 9 transid 10 size 0 nbytes 0
+ [445771.660116] block group 0 mode 40755 links 2 uid 0 gid 0
+ [445771.660117] rdev 0 sequence 0 flags 0x0
+ [445771.660118] atime 1775744885.645502983
+ [445771.660119] ctime 1775744885.645502983
+ [445771.660120] mtime 1775744885.645502983
+ [445771.660121] otime 1775744885.645502983
+ [445771.660122] item 11 key (258 INODE_REF 257) itemoff 15559 itemsize 14
+ [445771.660123] index 2 name_len 4
+ [445771.660124] item 12 key (258 INODE_REF 259) itemoff 15545 itemsize 14
+ [445771.660125] index 2 name_len 4
+ [445771.660126] item 13 key (259 INODE_ITEM 0) itemoff 15385 itemsize 160
+ [445771.660127] inode generation 9 transid 10 size 8 nbytes 0
+ [445771.660128] block group 0 mode 40755 links 1 uid 0 gid 0
+ [445771.660129] rdev 0 sequence 1 flags 0x0
+ [445771.660130] atime 1775744885.645502983
+ [445771.660130] ctime 1775744885.645502983
+ [445771.660131] mtime 1775744885.645502983
+ [445771.660132] otime 1775744885.645502983
+ [445771.660133] item 14 key (259 INODE_REF 256) itemoff 15371 itemsize 14
+ [445771.660134] index 3 name_len 4
+ [445771.660135] item 15 key (259 DIR_ITEM 2676584006) itemoff 15337 itemsize 34
+ [445771.660136] location key (258 1 0) type 2
+ [445771.660137] transid 10 data_len 0 name_len 4
+ [445771.660138] item 16 key (259 DIR_INDEX 2) itemoff 15303 itemsize 34
+ [445771.660139] location key (258 1 0) type 2
+ [445771.660140] transid 10 data_len 0 name_len 4
+ [445771.660144] BTRFS error (device dm-0): block=30408704 write time tree block corruption detected
+ [445771.661650] ------------[ cut here ]------------
+ [445771.662358] WARNING: fs/btrfs/disk-io.c:326 at btree_csum_one_bio+0x217/0x230 [btrfs], CPU#8: mount/3581087
+ [445771.663588] Modules linked in: btrfs f2fs xfs (...)
+ [445771.671229] CPU: 8 UID: 0 PID: 3581087 Comm: mount Tainted: G W 7.0.0-rc6-btrfs-next-230+ #2 PREEMPT(full)
+ [445771.672575] Tainted: [W]=WARN
+ [445771.672987] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
+ [445771.674460] RIP: 0010:btree_csum_one_bio+0x217/0x230 [btrfs]
+ [445771.675222] Code: 89 44 24 (...)
+ [445771.677364] RSP: 0018:ffffd23882247660 EFLAGS: 00010246
+ [445771.678029] RAX: 0000000000000000 RBX: ffff89f6c51d1a90 RCX: 0000000000000000
+ [445771.678975] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff89f406020000
+ [445771.679983] RBP: ffff89f821204000 R08: 0000000000000000 R09: 00000000ffefffff
+ [445771.680905] R10: ffffd23882247448 R11: 0000000000000003 R12: ffffd23882247668
+ [445771.681978] R13: ffff89f458e40fc0 R14: ffff89f737f4f500 R15: ffff89f737f4f500
+ [445771.682912] FS: 00007f0447a98840(0000) GS:ffff89fb9771d000(0000) knlGS:0000000000000000
+ [445771.684393] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ [445771.685230] CR2: 00007f0447bf1330 CR3: 000000017cb02002 CR4: 0000000000370ef0
+ [445771.686273] Call Trace:
+ [445771.686646] <TASK>
+ [445771.686969] btrfs_submit_bbio+0x83f/0x860 [btrfs]
+ [445771.687750] ? write_one_eb+0x28f/0x340 [btrfs]
+ [445771.688428] btree_writepages+0x2e3/0x550 [btrfs]
+ [445771.689180] ? kmem_cache_alloc_noprof+0x12a/0x490
+ [445771.689963] ? alloc_extent_state+0x19/0x120 [btrfs]
+ [445771.690801] ? kmem_cache_free+0x135/0x380
+ [445771.691328] ? preempt_count_add+0x69/0xa0
+ [445771.691831] ? set_extent_bit+0x252/0x8e0 [btrfs]
+ [445771.692468] ? xas_load+0x9/0xc0
+ [445771.692873] ? xas_find+0x14d/0x1a0
+ [445771.693304] do_writepages+0xc6/0x160
+ [445771.693756] filemap_writeback+0xb8/0xe0
+ [445771.694274] btrfs_write_marked_extents+0x61/0x170 [btrfs]
+ [445771.694999] btrfs_write_and_wait_transaction+0x4e/0xc0 [btrfs]
+ [445771.695818] btrfs_commit_transaction+0x5c8/0xd10 [btrfs]
+ [445771.696530] ? kmem_cache_free+0x135/0x380
+ [445771.697120] ? release_extent_buffer+0x34/0x160 [btrfs]
+ [445771.697786] btrfs_recover_log_trees+0x7be/0x7e0 [btrfs]
+ [445771.698525] ? __pfx_replay_one_buffer+0x10/0x10 [btrfs]
+ [445771.699206] open_ctree+0x11e5/0x1810 [btrfs]
+ [445771.699776] btrfs_get_tree.cold+0xb/0x162 [btrfs]
+ [445771.700463] ? fscontext_read+0x165/0x180
+ [445771.701146] ? rw_verify_area+0x50/0x180
+ [445771.701866] vfs_get_tree+0x25/0xd0
+ [445771.702491] vfs_cmd_create+0x59/0xe0
+ [445771.703125] __do_sys_fsconfig+0x303/0x610
+ [445771.703603] do_syscall_64+0xe9/0xf20
+ [445771.703974] entry_SYSCALL_64_after_hwframe+0x76/0x7e
+ [445771.704700] RIP: 0033:0x7f0447cbd4aa
+ [445771.705108] Code: 73 01 c3 (...)
+ [445771.707263] RSP: 002b:00007ffc4e528318 EFLAGS: 00000246 ORIG_RAX: 00000000000001af
+ [445771.708107] RAX: ffffffffffffffda RBX: 00005561585d8c20 RCX: 00007f0447cbd4aa
+ [445771.708931] RDX: 0000000000000000 RSI: 0000000000000006 RDI: 0000000000000003
+ [445771.709744] RBP: 00005561585d9120 R08: 0000000000000000 R09: 0000000000000000
+ [445771.710674] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ [445771.711477] R13: 00007f0447e4f580 R14: 00007f0447e5126c R15: 00007f0447e36a23
+ [445771.712277] </TASK>
+ [445771.712541] ---[ end trace 0000000000000000 ]---
+ [445771.713382] BTRFS error (device dm-0): error while writing out transaction: -5
+ [445771.714679] BTRFS warning (device dm-0): Skipping commit of aborted transaction.
+ [445771.715562] BTRFS error (device dm-0 state A): Transaction aborted (error -5)
+ [445771.716459] BTRFS: error (device dm-0 state A) in cleanup_transaction:2068: errno=-5 IO failure
+ [445771.717936] BTRFS error (device dm-0 state EA): failed to recover log trees with error: -5
+ [445771.719681] BTRFS error (device dm-0 state EA): open_ctree failed: -5
+
+The problem is that such a fsync should have result in a fallback to a
+transaction commit, but that did not happen because through the
+btrfs_rmdir() we never update the directory's last_unlink_trans field.
+Any inode that had a link removed must have its last_unlink_trans updated
+to the ID of transaction used for the operation, otherwise fsync and log
+replay will not work correctly.
+
+btrfs_rmdir() calls btrfs_unlink_inode() and through that call chain we
+never call btrfs_record_unlink_dir() in order to update last_unlink_trans.
+However btrfs_unlink(), which is used for unlinking regular files, calls
+btrfs_record_unlink_dir() and then calls btrfs_unlink_inode(). So fix
+this by moving the call to btrfs_record_unlink_dir() from btrfs_unlink()
+to btrfs_unlink_inode().
+
+A test case for fstests will follow soon.
+
+Reported-by: Slava0135 <slava.kovalevskiy.2014@gmail.com>
+Link: https://lore.kernel.org/linux-btrfs/CAAJYhww5ov62Hm+n+tmhcL-e_4cBobg+OWogKjOJxVUXivC=MQ@mail.gmail.com/
+CC: stable@vger.kernel.org
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/inode.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4967,6 +4967,8 @@ static int btrfs_rmdir(struct inode *vfs
+ if (ret)
+ goto out;
+
++ btrfs_record_unlink_dir(trans, dir, inode, false);
++
+ /* now the directory is empty */
+ ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name);
+ if (!ret)
--- /dev/null
+From b7cce3e2cca9cd78418f3c3784474b778e7996fe Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 16 Mar 2026 15:04:15 +0100
+Subject: dm: don't report warning when doing deferred remove
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit b7cce3e2cca9cd78418f3c3784474b778e7996fe upstream.
+
+If dm_hash_remove_all was called from dm_deferred_remove, it would write
+a warning "remove_all left %d open device(s)" if there are some other
+devices active.
+
+The warning is bogus, so let's disable it in this case.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Reported-by: Zdenek Kabelac <zkabelac@redhat.com>
+Cc: stable@vger.kernel.org
+Fixes: 2c140a246dc0 ("dm: allow remove to be deferred")
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-ioctl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/md/dm-ioctl.c
++++ b/drivers/md/dm-ioctl.c
+@@ -384,7 +384,7 @@ retry:
+
+ up_write(&_hash_lock);
+
+- if (dev_skipped)
++ if (dev_skipped && !only_deferred)
+ DMWARN("remove_all left %d open device(s)", dev_skipped);
+ }
+
--- /dev/null
+From 2fa49cc884f6496a915c35621ba4da35649bf159 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 9 Apr 2026 17:49:58 +0200
+Subject: dm: fix a buffer overflow in ioctl processing
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 2fa49cc884f6496a915c35621ba4da35649bf159 upstream.
+
+Tony Asleson (using Claude) found a buffer overflow in dm-ioctl in the
+function retrieve_status:
+
+1. The code in retrieve_status checks that the output string fits into
+ the output buffer and writes the output string there
+2. Then, the code aligns the "outptr" variable to the next 8-byte
+ boundary:
+ outptr = align_ptr(outptr);
+3. The alignment doesn't check overflow, so outptr could point past the
+ buffer end
+4. The "for" loop is iterated again, it executes:
+ remaining = len - (outptr - outbuf);
+5. If "outptr" points past "outbuf + len", the arithmetics wraps around
+ and the variable "remaining" contains unusually high number
+6. With "remaining" being high, the code writes more data past the end of
+ the buffer
+
+Luckily, this bug has no security implications because:
+1. Only root can issue device mapper ioctls
+2. The commonly used libraries that communicate with device mapper
+ (libdevmapper and devicemapper-rs) use buffer size that is aligned to
+ 8 bytes - thus, "outptr = align_ptr(outptr)" can't overshoot the input
+ buffer and the bug can't happen accidentally
+
+Reported-by: Tony Asleson <tasleson@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Reviewed-by: Bryn M. Reeves <bmr@redhat.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-ioctl.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/md/dm-ioctl.c
++++ b/drivers/md/dm-ioctl.c
+@@ -1341,6 +1341,10 @@ static void retrieve_status(struct dm_ta
+ used = param->data_start + (outptr - outbuf);
+
+ outptr = align_ptr(outptr);
++ if (!outptr || outptr > outbuf + len) {
++ param->flags |= DM_BUFFER_FULL_FLAG;
++ break;
++ }
+ spec->next = outptr - outbuf;
+ }
+
--- /dev/null
+From 09a65adc7d8bbfce06392cb6d375468e2728ead5 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 20 Apr 2026 19:56:44 +0200
+Subject: dm-thin: fix metadata refcount underflow
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 09a65adc7d8bbfce06392cb6d375468e2728ead5 upstream.
+
+There's a bug in dm-thin in the function rebalance_children. If the
+internal btree node has one entry, the code tries to copy all btree
+entries from the node's child to the node itself and then decrement the
+child's reference count.
+
+If the child node is shared (it has reference count > 1), we won't free
+it, so there would be two pointers to each of the grandchildren nodes.
+But the reference counts of the grandchildren is not increased, thus the
+reference count doesn't match the number of pointers that point to the
+grandchildren. This results in "device mapper: space map common: unable
+to decrement block" errors.
+
+Fix this bug by incrementing reference counts on the grandchildren if the
+btree node is shared.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Fixes: 3241b1d3e0aa ("dm: add persistent data library")
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/persistent-data/dm-btree-remove.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/md/persistent-data/dm-btree-remove.c
++++ b/drivers/md/persistent-data/dm-btree-remove.c
+@@ -490,12 +490,20 @@ static int rebalance_children(struct sha
+
+ if (le32_to_cpu(n->header.nr_entries) == 1) {
+ struct dm_block *child;
++ int is_shared;
+ dm_block_t b = value64(n, 0);
+
++ r = dm_tm_block_is_shared(info->tm, b, &is_shared);
++ if (r)
++ return r;
++
+ r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child);
+ if (r)
+ return r;
+
++ if (is_shared)
++ inc_children(info->tm, dm_block_data(child), vt);
++
+ memcpy(n, dm_block_data(child),
+ dm_bm_block_size(dm_tm_get_bm(info->tm)));
+
--- /dev/null
+From 2b14e0bb63cc671120e7791658f5c494fc66d072 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 5 Feb 2026 20:59:20 -0800
+Subject: dm-verity-fec: correctly reject too-small FEC devices
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 2b14e0bb63cc671120e7791658f5c494fc66d072 upstream.
+
+Fix verity_fec_ctr() to reject too-small FEC devices by correctly
+computing the number of parity blocks as 'f->rounds * f->roots'.
+Previously it incorrectly used 'div64_u64(f->rounds * f->roots,
+v->fec->roots << SECTOR_SHIFT)' which is a much smaller value.
+
+Note that the units of 'rounds' are blocks, not bytes. This matches the
+units of the value returned by dm_bufio_get_device_size(), which are
+also blocks. A later commit will give 'rounds' a clearer name.
+
+Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -625,7 +625,7 @@ int verity_fec_ctr(struct dm_verity *v)
+ {
+ struct dm_verity_fec *f = v->fec;
+ struct dm_target *ti = v->ti;
+- u64 hash_blocks, fec_blocks;
++ u64 hash_blocks;
+ int ret;
+
+ if (!verity_fec_is_enabled(v)) {
+@@ -706,8 +706,7 @@ int verity_fec_ctr(struct dm_verity *v)
+
+ dm_bufio_set_sector_offset(f->bufio, f->start << (v->data_dev_block_bits - SECTOR_SHIFT));
+
+- fec_blocks = div64_u64(f->rounds * f->roots, v->fec->roots << SECTOR_SHIFT);
+- if (dm_bufio_get_device_size(f->bufio) < fec_blocks) {
++ if (dm_bufio_get_device_size(f->bufio) < f->rounds * f->roots) {
+ ti->error = "FEC device is too small";
+ return -E2BIG;
+ }
--- /dev/null
+From 4355142245f7e55336dcc005ec03592df4d546f8 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 5 Feb 2026 20:59:21 -0800
+Subject: dm-verity-fec: correctly reject too-small hash devices
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 4355142245f7e55336dcc005ec03592df4d546f8 upstream.
+
+Fix verity_fec_ctr() to reject too-small hash devices by correctly
+taking hash_start into account.
+
+Note that this is necessary because dm-verity doesn't call
+dm_bufio_set_sector_offset() on the hash device's bufio client
+(v->bufio). Thus, dm_bufio_get_device_size(v->bufio) returns a size
+relative to 0 rather than hash_start. An alternative fix would be to
+call dm_bufio_set_sector_offset() on v->bufio, but then all the code
+that reads from the hash device would have to be adjusted accordingly.
+
+Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -688,7 +688,8 @@ int verity_fec_ctr(struct dm_verity *v)
+ * it to be large enough.
+ */
+ f->hash_blocks = f->blocks - v->data_blocks;
+- if (dm_bufio_get_device_size(v->bufio) < f->hash_blocks) {
++ if (dm_bufio_get_device_size(v->bufio) <
++ v->hash_start + f->hash_blocks) {
+ ti->error = "Hash device is too small for "
+ DM_VERITY_OPT_FEC_BLOCKS;
+ return -E2BIG;
--- /dev/null
+From 48640c88a8ddd482b6456fcbc084b08dd2bac083 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 5 Feb 2026 20:59:22 -0800
+Subject: dm-verity-fec: fix corrected block count stat
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 48640c88a8ddd482b6456fcbc084b08dd2bac083 upstream.
+
+dm_verity_fec::corrected seems to have been intended to count the number
+of corrected blocks. However, it actually counted the number of calls
+to fec_decode_bufs() that corrected at least one error. That's not the
+same thing. For example, in low-memory situations correcting a single
+block can require many calls to fec_decode_bufs().
+
+Fix it to count corrected blocks instead.
+
+Fixes: ae97648e14f7 ("dm verity fec: Expose corrected block count via status")
+Cc: Shubhankar Mishra <shubhankarm@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -163,11 +163,9 @@ error:
+ if (r < 0 && neras)
+ DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
+ v->data_dev->name, (unsigned long long)rsb, r);
+- else if (r > 0) {
++ else if (r > 0)
+ DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
+ v->data_dev->name, (unsigned long long)rsb, r);
+- atomic64_inc(&v->fec->corrected);
+- }
+
+ return r;
+ }
+@@ -439,6 +437,7 @@ int verity_fec_decode(struct dm_verity *
+ }
+
+ memcpy(dest, fio->output, 1 << v->data_dev_block_bits);
++ atomic64_inc(&v->fec->corrected);
+
+ done:
+ fio->level--;
--- /dev/null
+From 430a05cb926f6bdf53e81460a2c3a553257f3f61 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 5 Feb 2026 20:59:24 -0800
+Subject: dm-verity-fec: fix reading parity bytes split across blocks (take 3)
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 430a05cb926f6bdf53e81460a2c3a553257f3f61 upstream.
+
+fec_decode_bufs() assumes that the parity bytes of the first RS codeword
+it decodes are never split across parity blocks.
+
+This assumption is false. Consider v->fec->block_size == 4096 &&
+v->fec->roots == 17 && fio->nbufs == 1, for example. In that case, each
+call to fec_decode_bufs() consumes v->fec->roots * (fio->nbufs <<
+DM_VERITY_FEC_BUF_RS_BITS) = 272 parity bytes.
+
+Considering that the parity data for each message block starts on a
+block boundary, the byte alignment in the parity data will iterate
+through 272*i mod 4096 until the 3 parity blocks have been consumed. On
+the 16th call (i=15), the alignment will be 4080 bytes into the first
+block. Only 16 bytes remain in that block, but 17 parity bytes will be
+needed. The code reads out-of-bounds from the parity block buffer.
+
+Fortunately this doesn't normally happen, since it can occur only for
+certain non-default values of fec_roots *and* when the maximum number of
+buffers couldn't be allocated due to low memory. For example with
+block_size=4096 only the following cases are affected:
+
+ fec_roots=17: nbufs in [1, 3, 5, 15]
+ fec_roots=19: nbufs in [1, 229]
+ fec_roots=21: nbufs in [1, 3, 5, 13, 15, 39, 65, 195]
+ fec_roots=23: nbufs in [1, 89]
+
+Regardless, fix it by refactoring how the parity blocks are read.
+
+Fixes: 6df90c02bae4 ("dm-verity FEC: Fix RS FEC repair for roots unaligned to block size (take 2)")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.c | 100 +++++++++++++++++++--------------------------
+ 1 file changed, 44 insertions(+), 56 deletions(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -33,36 +33,6 @@ static inline u64 fec_interleave(struct
+ return offset + mod * (v->fec->rounds << v->data_dev_block_bits);
+ }
+
+-/*
+- * Read error-correcting codes for the requested RS block. Returns a pointer
+- * to the data block. Caller is responsible for releasing buf.
+- */
+-static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+- unsigned int *offset, unsigned int par_buf_offset,
+- struct dm_buffer **buf, unsigned short ioprio)
+-{
+- u64 position, block, rem;
+- u8 *res;
+-
+- /* We have already part of parity bytes read, skip to the next block */
+- if (par_buf_offset)
+- index++;
+-
+- position = (index + rsb) * v->fec->roots;
+- block = div64_u64_rem(position, v->fec->io_size, &rem);
+- *offset = par_buf_offset ? 0 : (unsigned int)rem;
+-
+- res = dm_bufio_read_with_ioprio(v->fec->bufio, block, buf, ioprio);
+- if (IS_ERR(res)) {
+- DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+- v->data_dev->name, (unsigned long long)rsb,
+- (unsigned long long)block, PTR_ERR(res));
+- *buf = NULL;
+- }
+-
+- return res;
+-}
+-
+ /* Loop over each allocated buffer. */
+ #define fec_for_each_buffer(io, __i) \
+ for (__i = 0; __i < (io)->nbufs; __i++)
+@@ -102,15 +72,29 @@ static int fec_decode_bufs(struct dm_ver
+ {
+ int r, corrected = 0, res;
+ struct dm_buffer *buf;
+- unsigned int n, i, j, offset, par_buf_offset = 0;
++ unsigned int n, i, j, parity_pos, to_copy;
+ uint16_t par_buf[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+ u8 *par, *block;
++ u64 parity_block;
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
+
+- par = fec_read_parity(v, rsb, block_offset, &offset,
+- par_buf_offset, &buf, bio->bi_ioprio);
+- if (IS_ERR(par))
++ /*
++ * Compute the index of the first parity block that will be needed and
++ * the starting position in that block. Then read that block.
++ *
++ * io_size is always a power of 2, but roots might not be. Note that
++ * when it's not, a codeword's parity bytes can span a block boundary.
++ */
++ parity_block = (rsb + block_offset) * v->fec->roots;
++ parity_pos = parity_block & (v->fec->io_size - 1);
++ parity_block >>= v->data_dev_block_bits;
++ par = dm_bufio_read_with_ioprio(v->fec->bufio, parity_block, &buf,
++ bio->bi_ioprio);
++ if (IS_ERR(par)) {
++ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
++ v->data_dev->name, rsb, parity_block, PTR_ERR(par));
+ return PTR_ERR(par);
++ }
+
+ /*
+ * Decode the RS blocks we have in bufs. Each RS block results in
+@@ -118,8 +102,32 @@ static int fec_decode_bufs(struct dm_ver
+ */
+ fec_for_each_buffer_rs_block(fio, n, i) {
+ block = fec_buffer_rs_block(v, fio, n, i);
+- for (j = 0; j < v->fec->roots - par_buf_offset; j++)
+- par_buf[par_buf_offset + j] = par[offset + j];
++
++ /*
++ * Copy the next 'roots' parity bytes to 'par_buf', reading
++ * another parity block if needed.
++ */
++ to_copy = min(v->fec->io_size - parity_pos, v->fec->roots);
++ for (j = 0; j < to_copy; j++)
++ par_buf[j] = par[parity_pos++];
++ if (to_copy < v->fec->roots) {
++ parity_block++;
++ parity_pos = 0;
++
++ dm_bufio_release(buf);
++ par = dm_bufio_read_with_ioprio(v->fec->bufio,
++ parity_block, &buf,
++ bio->bi_ioprio);
++ if (IS_ERR(par)) {
++ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
++ v->data_dev->name, rsb, parity_block,
++ PTR_ERR(par));
++ return PTR_ERR(par);
++ }
++ for (; j < v->fec->roots; j++)
++ par_buf[j] = par[parity_pos++];
++ }
++
+ /* Decode an RS block using Reed-Solomon */
+ res = decode_rs8(fio->rs, block, par_buf, v->fec->rsn,
+ NULL, neras, fio->erasures, 0, NULL);
+@@ -134,26 +142,6 @@ static int fec_decode_bufs(struct dm_ver
+ block_offset++;
+ if (block_offset >= 1 << v->data_dev_block_bits)
+ goto done;
+-
+- /* Read the next block when we run out of parity bytes */
+- offset += (v->fec->roots - par_buf_offset);
+- /* Check if parity bytes are split between blocks */
+- if (offset < v->fec->io_size && (offset + v->fec->roots) > v->fec->io_size) {
+- par_buf_offset = v->fec->io_size - offset;
+- for (j = 0; j < par_buf_offset; j++)
+- par_buf[j] = par[offset + j];
+- offset += par_buf_offset;
+- } else
+- par_buf_offset = 0;
+-
+- if (offset >= v->fec->io_size) {
+- dm_bufio_release(buf);
+-
+- par = fec_read_parity(v, rsb, block_offset, &offset,
+- par_buf_offset, &buf, bio->bi_ioprio);
+- if (IS_ERR(par))
+- return PTR_ERR(par);
+- }
+ }
+ done:
+ r = corrected;
--- /dev/null
+From a7fca324d7d90f7b139d4d32747c83a629fdb446 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 5 Feb 2026 20:59:23 -0800
+Subject: dm-verity-fec: fix the size of dm_verity_fec_io::erasures
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit a7fca324d7d90f7b139d4d32747c83a629fdb446 upstream.
+
+At most 25 entries in dm_verity_fec_io::erasures are used: the maximum
+number of FEC roots plus one. Therefore, set the array size
+accordingly. This reduces the size of dm_verity_fec_io by 912 bytes.
+
+Note: a later commit introduces a constant DM_VERITY_FEC_MAX_ROOTS,
+which allows the size to be more clearly expressed as
+DM_VERITY_FEC_MAX_ROOTS + 1. This commit just fixes the size first.
+
+Fixes: a739ff3f543a ("dm verity: add support for forward error correction")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-fec.h | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/dm-verity-fec.h
++++ b/drivers/md/dm-verity-fec.h
+@@ -47,7 +47,8 @@ struct dm_verity_fec {
+ /* per-bio data */
+ struct dm_verity_fec_io {
+ struct rs_control *rs; /* Reed-Solomon state */
+- int erasures[DM_VERITY_FEC_MAX_RSN]; /* erasures for decode_rs8 */
++ /* erasures for decode_rs8 */
++ int erasures[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN + 1];
+ u8 *output; /* buffer for corrected output */
+ unsigned int level; /* recursion level */
+ unsigned int nbufs; /* number of buffers allocated */
--- /dev/null
+From 07004a8c4b572171934390148ee48c4175c77eed Mon Sep 17 00:00:00 2001
+From: David Carlier <devnexen@gmail.com>
+Date: Sat, 18 Apr 2026 20:17:37 +0100
+Subject: eventfs: Hold eventfs_mutex and SRCU when remount walks events
+
+From: David Carlier <devnexen@gmail.com>
+
+commit 07004a8c4b572171934390148ee48c4175c77eed upstream.
+
+Commit 340f0c7067a9 ("eventfs: Update all the eventfs_inodes from the
+events descriptor") had eventfs_set_attrs() recurse through ei->children
+on remount. The walk only holds the rcu_read_lock() taken by
+tracefs_apply_options() over tracefs_inodes, which is wrong:
+
+ - list_for_each_entry over ei->children races with the list_del_rcu()
+ in eventfs_remove_rec() -- LIST_POISON1 deref, same shape as
+ d2603279c7d6.
+ - eventfs_inodes are freed via call_srcu(&eventfs_srcu, ...).
+ rcu_read_lock() does not extend an SRCU grace period, so ti->private
+ can be reclaimed under the walk.
+ - The writes to ei->attr race with eventfs_set_attr(), which holds
+ eventfs_mutex.
+
+Reproducer:
+
+ while :; do mount -o remount,uid=$((RANDOM%1000)) /sys/kernel/tracing; done &
+ while :; do
+ echo "p:kp submit_bio" > /sys/kernel/tracing/kprobe_events
+ echo > /sys/kernel/tracing/kprobe_events
+ done
+
+Wrap the events portion of tracefs_apply_options() in
+eventfs_remount_lock()/_unlock() that take eventfs_mutex and
+srcu_read_lock(&eventfs_srcu). eventfs_set_attrs() doesn't sleep so the
+nested rcu_read_lock() is fine; lockdep_assert_held() pins the contract.
+
+Comment in tracefs_drop_inode() said "RCU cycle" -- it is SRCU.
+
+Fixes: 340f0c7067a9 ("eventfs: Update all the eventfs_inodes from the events descriptor")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260418191737.10289-1-devnexen@gmail.com
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/tracefs/event_inode.c | 14 ++++++++++++++
+ fs/tracefs/inode.c | 5 ++++-
+ fs/tracefs/internal.h | 3 +++
+ 3 files changed, 21 insertions(+), 1 deletion(-)
+
+--- a/fs/tracefs/event_inode.c
++++ b/fs/tracefs/event_inode.c
+@@ -250,6 +250,8 @@ static void eventfs_set_attrs(struct eve
+ {
+ struct eventfs_inode *ei_child;
+
++ lockdep_assert_held(&eventfs_mutex);
++
+ /* Update events/<system>/<event> */
+ if (WARN_ON_ONCE(level > 3))
+ return;
+@@ -912,3 +914,15 @@ void eventfs_remove_events_dir(struct ev
+ d_invalidate(dentry);
+ d_make_discardable(dentry);
+ }
++
++int eventfs_remount_lock(void)
++{
++ mutex_lock(&eventfs_mutex);
++ return srcu_read_lock(&eventfs_srcu);
++}
++
++void eventfs_remount_unlock(int srcu_idx)
++{
++ srcu_read_unlock(&eventfs_srcu, srcu_idx);
++ mutex_unlock(&eventfs_mutex);
++}
+--- a/fs/tracefs/inode.c
++++ b/fs/tracefs/inode.c
+@@ -336,6 +336,7 @@ static int tracefs_apply_options(struct
+ struct inode *inode = d_inode(sb->s_root);
+ struct tracefs_inode *ti;
+ bool update_uid, update_gid;
++ int srcu_idx;
+ umode_t tmp_mode;
+
+ /*
+@@ -360,6 +361,7 @@ static int tracefs_apply_options(struct
+ update_uid = fsi->opts & BIT(Opt_uid);
+ update_gid = fsi->opts & BIT(Opt_gid);
+
++ srcu_idx = eventfs_remount_lock();
+ rcu_read_lock();
+ list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
+ if (update_uid) {
+@@ -381,6 +383,7 @@ static int tracefs_apply_options(struct
+ eventfs_remount(ti, update_uid, update_gid);
+ }
+ rcu_read_unlock();
++ eventfs_remount_unlock(srcu_idx);
+ }
+
+ return 0;
+@@ -426,7 +429,7 @@ static int tracefs_drop_inode(struct ino
+ * This inode is being freed and cannot be used for
+ * eventfs. Clear the flag so that it doesn't call into
+ * eventfs during the remount flag updates. The eventfs_inode
+- * gets freed after an RCU cycle, so the content will still
++ * gets freed after an SRCU cycle, so the content will still
+ * be safe if the iteration is going on now.
+ */
+ ti->flags &= ~TRACEFS_EVENT_INODE;
+--- a/fs/tracefs/internal.h
++++ b/fs/tracefs/internal.h
+@@ -76,4 +76,7 @@ struct inode *tracefs_get_inode(struct s
+ void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid);
+ void eventfs_d_release(struct dentry *dentry);
+
++int eventfs_remount_lock(void);
++void eventfs_remount_unlock(int srcu_idx);
++
+ #endif /* _TRACEFS_INTERNAL_H */
--- /dev/null
+From 6fabce53f6b9c2419012a9103e1a46d40888cefa Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Tue, 17 Mar 2026 00:59:16 -0700
+Subject: iommu/arm-smmu-v3: Add a missing dma_wmb() for hitless STE update
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 6fabce53f6b9c2419012a9103e1a46d40888cefa upstream.
+
+When writing a new (previously invalid) valid IOPTE to a page table, then
+installing the page table into an STE hitlesslessly (e.g. in S2TTB field),
+there is a window before an STE invalidation, where the page-table may be
+accessed by SMMU but the new IOPTE is still siting in the CPU cache.
+
+This could occur when we allocate an iommu_domain and immediately install
+it hitlessly, while there would be no dma_wmb() for the page table memory
+prior to the earliest point of HW reading the STE.
+
+Fix it by adding a dma_wmb() prior to updating the STE.
+
+Fixes: 56e1a4cc2588 ("iommu/arm-smmu-v3: Add unit tests for arm_smmu_write_entry")
+Cc: stable@vger.kernel.org
+Reported-by: Will Deacon <will@kernel.org>
+Closes: https://lore.kernel.org/linux-iommu/aXdlnLLFUBwjT0V5@willie-the-truck/
+Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+@@ -1236,6 +1236,13 @@ void arm_smmu_write_entry(struct arm_smm
+ __le64 unused_update[NUM_ENTRY_QWORDS];
+ u8 used_qword_diff;
+
++ /*
++ * Many of the entry structures have pointers to other structures that
++ * need to have their updates be visible before any writes of the entry
++ * happen.
++ */
++ dma_wmb();
++
+ used_qword_diff =
+ arm_smmu_entry_qword_diff(writer, entry, target, unused_update);
+ if (hweight8(used_qword_diff) == 1) {
--- /dev/null
+From cc5bd898ff70710ffc41cd8e5c2741cb64750047 Mon Sep 17 00:00:00 2001
+From: Zhenzhong Duan <zhenzhong.duan@intel.com>
+Date: Thu, 2 Apr 2026 14:57:24 +0800
+Subject: iommu/vt-d: Block PASID attachment to nested domain with dirty tracking
+
+From: Zhenzhong Duan <zhenzhong.duan@intel.com>
+
+commit cc5bd898ff70710ffc41cd8e5c2741cb64750047 upstream.
+
+Kernel lacks dirty tracking support on nested domain attached to PASID,
+fails the attachment early if nesting parent domain is dirty tracking
+configured, otherwise dirty pages would be lost.
+
+Cc: stable@vger.kernel.org
+Fixes: 67f6f56b5912 ("iommu/vt-d: Add set_dev_pasid callback for nested domain")
+Suggested-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Yi Liu <yi.l.liu@intel.com>
+Link: https://lore.kernel.org/r/20260330101108.12594-2-zhenzhong.duan@intel.com
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Fixes: 67f6f56b5912 ("iommu/vt-d: Add set_dev_pasid callback for nested domain")
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/intel/nested.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/iommu/intel/nested.c
++++ b/drivers/iommu/intel/nested.c
+@@ -148,6 +148,7 @@ static int intel_nested_set_dev_pasid(st
+ {
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+ struct dmar_domain *dmar_domain = to_dmar_domain(domain);
++ struct iommu_domain *s2_domain = &dmar_domain->s2_domain->domain;
+ struct intel_iommu *iommu = info->iommu;
+ struct dev_pasid_info *dev_pasid;
+ int ret;
+@@ -155,10 +156,13 @@ static int intel_nested_set_dev_pasid(st
+ if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
+ return -EOPNOTSUPP;
+
++ if (s2_domain->dirty_ops)
++ return -EINVAL;
++
+ if (context_copied(iommu, info->bus, info->devfn))
+ return -EBUSY;
+
+- ret = paging_domain_compatible(&dmar_domain->s2_domain->domain, dev);
++ ret = paging_domain_compatible(s2_domain, dev);
+ if (ret)
+ return ret;
+
--- /dev/null
+From aaca2aa92785a6ab8e3183e7184bca447a99cd76 Mon Sep 17 00:00:00 2001
+From: Zhenzhong Duan <zhenzhong.duan@intel.com>
+Date: Sun, 29 Mar 2026 23:07:55 -0400
+Subject: iommufd: Fix return value of iommufd_fault_fops_write()
+
+From: Zhenzhong Duan <zhenzhong.duan@intel.com>
+
+commit aaca2aa92785a6ab8e3183e7184bca447a99cd76 upstream.
+
+copy_from_user() may return number of bytes failed to copy, we should
+not pass over this number to user space to cheat that write() succeed.
+Instead, -EFAULT should be returned.
+
+Link: https://patch.msgid.link/r/20260330030755.12856-1-zhenzhong.duan@intel.com
+Cc: stable@vger.kernel.org
+Fixes: 07838f7fd529 ("iommufd: Add iommufd fault object")
+Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Shuai Xue <xueshuai@linux.alibaba.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -187,9 +187,10 @@ static ssize_t iommufd_fault_fops_write(
+
+ mutex_lock(&fault->mutex);
+ while (count > done) {
+- rc = copy_from_user(&response, buf + done, response_size);
+- if (rc)
++ if (copy_from_user(&response, buf + done, response_size)) {
++ rc = -EFAULT;
+ break;
++ }
+
+ static_assert((int)IOMMUFD_PAGE_RESP_SUCCESS ==
+ (int)IOMMU_PAGE_RESP_SUCCESS);
--- /dev/null
+From 24376458138387fb251e782e624c7776e9826796 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 19 Apr 2026 17:21:55 -0400
+Subject: isofs: validate block number from NFS file handle in isofs_export_iget
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 24376458138387fb251e782e624c7776e9826796 upstream.
+
+isofs_fh_to_dentry() and isofs_fh_to_parent() pass an attacker-
+controlled block number (ifid->block or ifid->parent_block) from
+the NFS file handle to isofs_export_iget(), which only rejects
+block == 0 before calling isofs_iget() and ultimately sb_bread().
+A crafted file handle with fh_len sufficient to pass the check
+added by commit 0405d4b63d08 ("isofs: Prevent the use of too small
+fid") can still drive the server to read any in-range block on the
+backing device as if it were an iso_directory_record. That earlier
+fix was assigned CVE-2025-37780.
+
+sb_bread() on an out-of-range block returns NULL cleanly via the
+EIO path, so there is no memory-safety violation. For in-range
+reads of adjacent-partition data on the same block device, the
+unrelated bytes end up in iso_inode_info fields that reach the NFS
+client as dentry metadata. The deployment surface (isofs exported
+over NFS from loop-mounted images) is narrow and requires an
+authenticated NFS peer, but the malformed-file-handle class is
+reportable as hardening next to the existing CVE-2025-37780 fix.
+
+Reject block >= ISOFS_SB(sb)->s_nzones in isofs_export_iget() so
+the check covers both isofs_fh_to_dentry() and isofs_fh_to_parent()
+call sites with a single line.
+
+Fixes: 0405d4b63d08 ("isofs: Prevent the use of too small fid")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Link: https://patch.msgid.link/20260419212155.2169382-3-michael.bommarito@gmail.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/isofs/export.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/isofs/export.c
++++ b/fs/isofs/export.c
+@@ -24,7 +24,7 @@ isofs_export_iget(struct super_block *sb
+ {
+ struct inode *inode;
+
+- if (block == 0)
++ if (block == 0 || block >= ISOFS_SB(sb)->s_nzones)
+ return ERR_PTR(-ESTALE);
+ inode = isofs_iget(sb, block, offset);
+ if (IS_ERR(inode))
--- /dev/null
+From a36d990f591320e9dd379ab30063ebfe91d47e1f Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 19 Apr 2026 17:21:54 -0400
+Subject: isofs: validate Rock Ridge CE continuation extent against volume size
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit a36d990f591320e9dd379ab30063ebfe91d47e1f upstream.
+
+rock_continue() reads rs->cont_extent verbatim from the Rock Ridge CE
+record and passes it to sb_bread() without checking that the block
+number is within the mounted ISO 9660 volume. commit e595447e177b
+("[PATCH] rock.c: handle corrupted directories") added cont_offset
+and cont_size rejection for the CE continuation but did not validate
+the extent block number itself. commit f54e18f1b831 ("isofs: Fix
+infinite looping over CE entries") later capped the CE chain length
+at RR_MAX_CE_ENTRIES = 32 but again left the block number unchecked.
+
+With a crafted ISO mounted via udisks2 (desktop optical auto-mount)
+or via CAP_SYS_ADMIN mount, rs->cont_extent can therefore point at
+an out-of-range block or at blocks belonging to an adjacent
+filesystem on the same block device. sb_bread() on an out-of-range
+block returns NULL cleanly via the block layer EIO path, so there
+is no memory-safety violation. For in-range reads of adjacent-
+filesystem data, the CE buffer is parsed as Rock Ridge records and
+only the text of SL sub-records reaches userspace through
+readlink(), which makes the info-leak channel narrow and difficult
+to exploit; still, rejecting the malformed CE outright matches the
+rejection shape already present in the same function for
+cont_offset and cont_size.
+
+Add an ISOFS_SB(sb)->s_nzones bounds check to rock_continue() next
+to the existing offset/size rejection, printing the same
+corrupted-directory-entry notice.
+
+Fixes: f54e18f1b831 ("isofs: Fix infinite looping over CE entries")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Link: https://patch.msgid.link/20260419212155.2169382-2-michael.bommarito@gmail.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/isofs/rock.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/fs/isofs/rock.c
++++ b/fs/isofs/rock.c
+@@ -101,6 +101,15 @@ static int rock_continue(struct rock_sta
+ goto out;
+ }
+
++ if ((unsigned)rs->cont_extent >= ISOFS_SB(rs->inode->i_sb)->s_nzones) {
++ printk(KERN_NOTICE "rock: corrupted directory entry. "
++ "extent=%u out of volume (nzones=%lu)\n",
++ (unsigned)rs->cont_extent,
++ ISOFS_SB(rs->inode->i_sb)->s_nzones);
++ ret = -EIO;
++ goto out;
++ }
++
+ if (rs->cont_extent) {
+ struct buffer_head *bh;
+
--- /dev/null
+From 464af6fc2b1dcc74005b7f58ee3812b17777efee Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Mon, 27 Apr 2026 14:25:40 +0200
+Subject: KVM: x86: check for nEPT/nNPT in slow flush hypercalls
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+commit 464af6fc2b1dcc74005b7f58ee3812b17777efee upstream.
+
+Checking is_guest_mode(vcpu) is incorrect, because translate_nested_gpa()
+is only valid if an L2 guest is running *with nested EPT/NPT enabled*.
+Instead use the same condition as translate_nested_gpa() itself.
+
+Cc: stable@vger.kernel.org
+Reviewed-by: Sean Christopherson <seanjc@google.com>
+Fixes: aee738236dca ("KVM: x86: Prepare kvm_hv_flush_tlb() to handle L2's GPAs", 2022-11-18)
+Link: https://patch.msgid.link/20260503200905.106077-1-pbonzini@redhat.com/
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/hyperv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/kvm/hyperv.c
++++ b/arch/x86/kvm/hyperv.c
+@@ -2040,7 +2040,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_v
+ * flush). Translate the address here so the memory can be uniformly
+ * read with kvm_read_guest().
+ */
+- if (!hc->fast && is_guest_mode(vcpu)) {
++ if (!hc->fast && mmu_is_nested(vcpu)) {
+ hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, NULL);
+ if (unlikely(hc->ingpa == INVALID_GPA))
+ return HV_STATUS_INVALID_HYPERCALL_INPUT;
--- /dev/null
+From 33fd0ccd2590b470b65adcca288615ad3b5e3e06 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Sun, 3 May 2026 19:19:32 +0200
+Subject: KVM: x86: Do IRR scan in __kvm_apic_update_irr even if PIR is empty
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+commit 33fd0ccd2590b470b65adcca288615ad3b5e3e06 upstream.
+
+Fall back to apic_find_highest_vector() when PID.ON is set but PIR
+turns out to be empty, to correctly report the highest pending interrupt
+from the existing IRR.
+
+In a nested VM stress test, the following WARNING fires in
+vmx_check_nested_events() when kvm_cpu_has_interrupt() reports a pending
+interrupt but the subsequent kvm_apic_has_interrupt() (which invokes
+vmx_sync_pir_to_irr() again) returns -1:
+
+ WARNING: CPU: 99 PID: 57767 at arch/x86/kvm/vmx/nested.c:4449 vmx_check_nested_events+0x6bf/0x6e0 [kvm_intel]
+ Call Trace:
+ kvm_check_and_inject_events
+ vcpu_enter_guest.constprop.0
+ vcpu_run
+ kvm_arch_vcpu_ioctl_run
+ kvm_vcpu_ioctl
+ __x64_sys_ioctl
+ do_syscall_64
+ entry_SYSCALL_64_after_hwframe
+
+The root cause is a race between vmx_sync_pir_to_irr() on the target vCPU
+and __vmx_deliver_posted_interrupt() on a sender vCPU. The sender
+performs two individually-atomic operations that are not a single
+transaction:
+
+ 1. pi_test_and_set_pir(vector) -- sets the PIR bit
+ 2. pi_test_and_set_on() -- sets PID.ON
+
+The following interleaving triggers the bug:
+
+ Sender vCPU (IPI): Target vCPU (1st sync_pir_to_irr):
+ B1: set PIR[vector]
+ A1: pi_clear_on()
+ A2: pi_harvest_pir() -> sees B1 bit
+ A3: xchg() -> consumes bit, PIR=0
+ (1st sync returns correct max_irr)
+ B2: set PID.ON = 1
+
+ Target vCPU (2nd sync_pir_to_irr):
+ C1: pi_test_on() -> TRUE (from B2)
+ C2: pi_clear_on() -> ON=0
+ C3: pi_harvest_pir() -> PIR empty
+ C4: *max_irr = -1, early return
+ IRR NOT SCANNED
+
+The interrupt is not lost (it resides in the IRR from the first sync and
+is recovered on the next vcpu_enter_guest() iteration), but the incorrect
+max_irr causes a spurious WARNING and a wasted L2 VM-Enter/VM-Exit cycle.
+
+Fixes: b41f8638b9d3 ("KVM: VMX: Isolate pure loads from atomic XCHG when processing PIR")
+Reported-by: Farrah Chen <farrah.chen@intel.com>
+Analyzed-by: Chenyi Qiang <chenyi.qiang@intel.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Sean Christopherson <seanjc@google.com>
+Link: https://lore.kernel.org/kvm/20260428070349.1633238-1-chenyi.qiang@intel.com/T/
+Link: https://patch.msgid.link/20260503201703.108231-2-pbonzini@redhat.com/
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/lapic.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -669,12 +669,14 @@ bool __kvm_apic_update_irr(unsigned long
+ u32 irr_val, prev_irr_val;
+ int max_updated_irr;
+
++ if (!pi_harvest_pir(pir, pir_vals)) {
++ *max_irr = apic_find_highest_vector(regs + APIC_IRR);
++ return false;
++ }
++
+ max_updated_irr = -1;
+ *max_irr = -1;
+
+- if (!pi_harvest_pir(pir, pir_vals))
+- return false;
+-
+ for (i = vec = 0; i <= 7; i++, vec += 32) {
+ u32 *p_irr = (u32 *)(regs + APIC_IRR + i * 0x10);
+
--- /dev/null
+From 85c9f3a2b805eb96d899da7bcc38a16459aa3c16 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Thu, 5 Mar 2026 19:35:55 -0800
+Subject: lib/crc: tests: Make crc_kunit test only the enabled CRC variants
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 85c9f3a2b805eb96d899da7bcc38a16459aa3c16 upstream.
+
+Like commit 4478e8eeb871 ("lib/crypto: tests: Depend on library options
+rather than selecting them") did with the crypto library tests, make
+crc_kunit depend on the code it tests rather than selecting it. This
+follows the standard convention for KUnit and fixes an issue where
+enabling KUNIT_ALL_TESTS enabled non-test code.
+
+crc_kunit does differ from the crypto library tests in that it
+consolidates the tests for multiple CRC variants, with 5 kconfig
+options, into one KUnit suite. Since depending on *all* of these
+kconfig options would greatly restrict the ability to enable crc_kunit,
+instead just depend on *any* of these options. Update crc_kunit
+accordingly to test only the reachable code.
+
+Alternatively we could split crc_kunit into 5 test suites. But keeping
+it as one is simpler for now.
+
+Fixes: e47d9b1a76ed ("lib/crc_kunit.c: add KUnit test suite for CRC library functions")
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20260306033557.250499-2-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ lib/crc/Kconfig | 7 +------
+ lib/crc/tests/crc_kunit.c | 28 ++++++++++++++++++++++------
+ 2 files changed, 23 insertions(+), 12 deletions(-)
+
+--- a/lib/crc/Kconfig
++++ b/lib/crc/Kconfig
+@@ -99,13 +99,8 @@ config CRC_OPTIMIZATIONS
+
+ config CRC_KUNIT_TEST
+ tristate "KUnit tests for CRC functions" if !KUNIT_ALL_TESTS
+- depends on KUNIT
++ depends on KUNIT && (CRC7 || CRC16 || CRC_T10DIF || CRC32 || CRC64)
+ default KUNIT_ALL_TESTS
+- select CRC7
+- select CRC16
+- select CRC_T10DIF
+- select CRC32
+- select CRC64
+ help
+ Unit tests for the CRC library functions.
+
+--- a/lib/crc/tests/crc_kunit.c
++++ b/lib/crc/tests/crc_kunit.c
+@@ -268,8 +268,7 @@ crc_benchmark(struct kunit *test,
+ }
+ }
+
+-/* crc7_be */
+-
++#if IS_REACHABLE(CONFIG_CRC7)
+ static u64 crc7_be_wrapper(u64 crc, const u8 *p, size_t len)
+ {
+ /*
+@@ -294,9 +293,9 @@ static void crc7_be_benchmark(struct kun
+ {
+ crc_benchmark(test, crc7_be_wrapper);
+ }
++#endif /* CONFIG_CRC7 */
+
+-/* crc16 */
+-
++#if IS_REACHABLE(CONFIG_CRC16)
+ static u64 crc16_wrapper(u64 crc, const u8 *p, size_t len)
+ {
+ return crc16(crc, p, len);
+@@ -318,9 +317,9 @@ static void crc16_benchmark(struct kunit
+ {
+ crc_benchmark(test, crc16_wrapper);
+ }
++#endif /* CONFIG_CRC16 */
+
+-/* crc_t10dif */
+-
++#if IS_REACHABLE(CONFIG_CRC_T10DIF)
+ static u64 crc_t10dif_wrapper(u64 crc, const u8 *p, size_t len)
+ {
+ return crc_t10dif_update(crc, p, len);
+@@ -342,6 +341,9 @@ static void crc_t10dif_benchmark(struct
+ {
+ crc_benchmark(test, crc_t10dif_wrapper);
+ }
++#endif /* CONFIG_CRC_T10DIF */
++
++#if IS_REACHABLE(CONFIG_CRC32)
+
+ /* crc32_le */
+
+@@ -414,6 +416,9 @@ static void crc32c_benchmark(struct kuni
+ {
+ crc_benchmark(test, crc32c_wrapper);
+ }
++#endif /* CONFIG_CRC32 */
++
++#if IS_REACHABLE(CONFIG_CRC64)
+
+ /* crc64_be */
+
+@@ -463,24 +468,35 @@ static void crc64_nvme_benchmark(struct
+ {
+ crc_benchmark(test, crc64_nvme_wrapper);
+ }
++#endif /* CONFIG_CRC64 */
+
+ static struct kunit_case crc_test_cases[] = {
++#if IS_REACHABLE(CONFIG_CRC7)
+ KUNIT_CASE(crc7_be_test),
+ KUNIT_CASE(crc7_be_benchmark),
++#endif
++#if IS_REACHABLE(CONFIG_CRC16)
+ KUNIT_CASE(crc16_test),
+ KUNIT_CASE(crc16_benchmark),
++#endif
++#if IS_REACHABLE(CONFIG_CRC_T10DIF)
+ KUNIT_CASE(crc_t10dif_test),
+ KUNIT_CASE(crc_t10dif_benchmark),
++#endif
++#if IS_REACHABLE(CONFIG_CRC32)
+ KUNIT_CASE(crc32_le_test),
+ KUNIT_CASE(crc32_le_benchmark),
+ KUNIT_CASE(crc32_be_test),
+ KUNIT_CASE(crc32_be_benchmark),
+ KUNIT_CASE(crc32c_test),
+ KUNIT_CASE(crc32c_benchmark),
++#endif
++#if IS_REACHABLE(CONFIG_CRC64)
+ KUNIT_CASE(crc64_be_test),
+ KUNIT_CASE(crc64_be_benchmark),
+ KUNIT_CASE(crc64_nvme_test),
+ KUNIT_CASE(crc64_nvme_benchmark),
++#endif
+ {},
+ };
+
--- /dev/null
+From 8c2f1288250a90a4b5cabed5d888d7e3aeed4035 Mon Sep 17 00:00:00 2001
+From: Lukas Wunner <lukas@wunner.de>
+Date: Sun, 12 Apr 2026 16:19:47 +0200
+Subject: lib/crypto: mpi: Fix integer underflow in mpi_read_raw_from_sgl()
+
+From: Lukas Wunner <lukas@wunner.de>
+
+commit 8c2f1288250a90a4b5cabed5d888d7e3aeed4035 upstream.
+
+Yiming reports an integer underflow in mpi_read_raw_from_sgl() when
+subtracting "lzeros" from the unsigned "nbytes".
+
+For this to happen, the scatterlist "sgl" needs to occupy more bytes
+than the "nbytes" parameter and the first "nbytes + 1" bytes of the
+scatterlist must be zero. Under these conditions, the while loop
+iterating over the scatterlist will count more zeroes than "nbytes",
+subtract the number of zeroes from "nbytes" and cause the underflow.
+
+When commit 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers") originally
+introduced the bug, it couldn't be triggered because all callers of
+mpi_read_raw_from_sgl() passed a scatterlist whose length was equal to
+"nbytes".
+
+However since commit 63ba4d67594a ("KEYS: asymmetric: Use new crypto
+interface without scatterlists"), the underflow can now actually be
+triggered. When invoking a KEYCTL_PKEY_ENCRYPT system call with a
+larger "out_len" than "in_len" and filling the "in" buffer with zeroes,
+crypto_akcipher_sync_prep() will create an all-zero scatterlist used for
+both the "src" and "dst" member of struct akcipher_request and thereby
+fulfil the conditions to trigger the bug:
+
+ sys_keyctl()
+ keyctl_pkey_e_d_s()
+ asymmetric_key_eds_op()
+ software_key_eds_op()
+ crypto_akcipher_sync_encrypt()
+ crypto_akcipher_sync_prep()
+ crypto_akcipher_encrypt()
+ rsa_enc()
+ mpi_read_raw_from_sgl()
+
+To the user this will be visible as a DoS as the kernel spins forever,
+causing soft lockup splats as a side effect.
+
+Fix it.
+
+Reported-by: Yiming Qian <yimingqian591@gmail.com> # off-list
+Fixes: 2d4d1eea540b ("lib/mpi: Add mpi sgl helpers")
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Cc: stable@vger.kernel.org # v4.4+
+Reviewed-by: Ignat Korchagin <ignat@linux.win>
+Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
+Link: https://lore.kernel.org/r/59eca92ff4f87e2081777f1423a0efaaadcfdb39.1776003111.git.lukas@wunner.de
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ lib/crypto/mpi/mpicoder.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/lib/crypto/mpi/mpicoder.c
++++ b/lib/crypto/mpi/mpicoder.c
+@@ -347,7 +347,7 @@ MPI mpi_read_raw_from_sgl(struct scatter
+ lzeros = 0;
+ len = 0;
+ while (nbytes > 0) {
+- while (len && !*buff) {
++ while (len && !*buff && lzeros < nbytes) {
+ lzeros++;
+ len--;
+ buff++;
--- /dev/null
+From 07b7d66e65d9cfe6b9c2c34aa22cfcaac37a5c45 Mon Sep 17 00:00:00 2001
+From: "Christian A. Ehrhardt" <lk@c--e.de>
+Date: Thu, 26 Mar 2026 22:49:01 +0100
+Subject: lib/scatterlist: fix length calculations in extract_kvec_to_sg
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+commit 07b7d66e65d9cfe6b9c2c34aa22cfcaac37a5c45 upstream.
+
+Patch series "Fix bugs in extract_iter_to_sg()", v3.
+
+Fix bugs in the kvec and user variants of extract_iter_to_sg. This series
+is growing due to useful remarks made by sashiko.dev.
+
+The main bugs are:
+- The length for an sglist entry when extracting from
+ a kvec can exceed the number of bytes in the page. This
+ is obviously not intended.
+- When extracting a user buffer the sglist is temporarily
+ used as a scratch buffer for extracted page pointers.
+ If the sglist already contains some elements this scratch
+ buffer could overlap with existing entries in the sglist.
+
+The series adds test cases to the kunit_iov_iter test that demonstrate all
+of these bugs. Additionally, there is a memory leak fix for the test
+itself.
+
+The bugs were orignally introduced into kernel v6.3 where the function
+lived in fs/netfs/iterator.c. It was later moved to lib/scatterlist.c in
+v6.5. Thus the actual fix is only marked for backports to v6.5+.
+
+
+This patch (of 5):
+
+When extracting from a kvec to a scatterlist, do not cross page
+boundaries. The required length was already calculated but not used as
+intended.
+
+Adjust the copied length if the loop runs out of sglist entries without
+extracting everything.
+
+While there, return immediately from extract_iter_to_sg if there are no
+sglist entries at all.
+
+A subsequent commit will add kunit test cases that demonstrate that the
+patch is necessary.
+
+Link: https://lkml.kernel.org/r/20260326214905.818170-1-lk@c--e.de
+Link: https://lkml.kernel.org/r/20260326214905.818170-2-lk@c--e.de
+Fixes: 018584697533 ("netfs: Add a function to extract an iterator into a scatterlist")
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Cc: David Gow <davidgow@google.com>
+Cc: David Howells <dhowells@redhat.com>
+Cc: Kees Cook <kees@kernel.org>
+Cc: Petr Mladek <pmladek@suse.com>
+Cc: <stable@vger.kernel.org> [v6.5+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ lib/scatterlist.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/lib/scatterlist.c
++++ b/lib/scatterlist.c
+@@ -1247,7 +1247,7 @@ static ssize_t extract_kvec_to_sg(struct
+ else
+ page = virt_to_page((void *)kaddr);
+
+- sg_set_page(sg, page, len, off);
++ sg_set_page(sg, page, seg, off);
+ sgtable->nents++;
+ sg++;
+ sg_max--;
+@@ -1256,6 +1256,7 @@ static ssize_t extract_kvec_to_sg(struct
+ kaddr += PAGE_SIZE;
+ off = 0;
+ } while (len > 0 && sg_max > 0);
++ ret -= len;
+
+ if (maxsize <= 0 || sg_max == 0)
+ break;
+@@ -1409,7 +1410,7 @@ ssize_t extract_iter_to_sg(struct iov_it
+ struct sg_table *sgtable, unsigned int sg_max,
+ iov_iter_extraction_t extraction_flags)
+ {
+- if (maxsize == 0)
++ if (maxsize == 0 || sg_max == 0)
+ return 0;
+
+ switch (iov_iter_type(iter)) {
--- /dev/null
+From 118cf3f55975352ac357fb194405031458186819 Mon Sep 17 00:00:00 2001
+From: "Christian A. Ehrhardt" <lk@c--e.de>
+Date: Thu, 26 Mar 2026 22:49:02 +0100
+Subject: lib/scatterlist: fix temp buffer in extract_user_to_sg()
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+commit 118cf3f55975352ac357fb194405031458186819 upstream.
+
+Instead of allocating a temporary buffer for extracted user pages
+extract_user_to_sg() uses the end of the to be filled scatterlist as a
+temporary buffer.
+
+Fix the calculation of the start address if the scatterlist already
+contains elements. The unused space starts at sgtable->sgl +
+sgtable->nents not directly at sgtable->nents and the temporary buffer is
+placed at the end of this unused space.
+
+A subsequent commit will add kunit test cases that demonstrate that the
+patch is necessary.
+
+Pointed out by sashiko.dev on a previous iteration of this series.
+
+Link: https://lkml.kernel.org/r/20260326214905.818170-3-lk@c--e.de
+Fixes: 018584697533 ("netfs: Add a function to extract an iterator into a scatterlist")
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Cc: David Howells <dhowells@redhat.com>
+Cc: David Gow <davidgow@google.com>
+Cc: Kees Cook <kees@kernel.org>
+Cc: Petr Mladek <pmladek@suse.com>
+Cc: <stable@vger.kernel.org> [v6.5+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ lib/scatterlist.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/lib/scatterlist.c
++++ b/lib/scatterlist.c
+@@ -1123,8 +1123,7 @@ static ssize_t extract_user_to_sg(struct
+ size_t len, off;
+
+ /* We decant the page list into the tail of the scatterlist */
+- pages = (void *)sgtable->sgl +
+- array_size(sg_max, sizeof(struct scatterlist));
++ pages = (void *)sg + array_size(sg_max, sizeof(struct scatterlist));
+ pages -= sg_max;
+
+ do {
--- /dev/null
+From 1c439de70b1c3eb3c6bffa8245c16b9fc318f114 Mon Sep 17 00:00:00 2001
+From: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
+Date: Tue, 21 Apr 2026 10:27:01 +0200
+Subject: libceph: Fix slab-out-of-bounds access in auth message processing
+
+From: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
+
+commit 1c439de70b1c3eb3c6bffa8245c16b9fc318f114 upstream.
+
+If a (potentially corrupted) message of type CEPH_MSG_AUTH_REPLY
+contains a positive value in its result field, it is treated as an
+error code by ceph_handle_auth_reply() and returned to
+handle_auth_reply(). Thereafter, an attempt is made to send the
+preallocated message of type CEPH_MSG_AUTH, where the returned value is
+interpreted as the size of the front segment to send. If the result
+value in the message is greater than the size of the memory buffer
+allocated for the front segment, an out-of-bounds access occurs, and
+the content of the memory region beyond this buffer is sent out.
+
+This patch fixes the issue by treating only negative values in the
+result field as errors. Positive values are therefore treated as success
+in the same way as a zero value. Additionally, a BUG_ON is added to
+__send_prepared_auth_request() comparing the len parameter to
+front_alloc_len to prevent sending the message if it exceeds the bounds
+of the allocation and to make it easier to catch any logic flaws leading
+to this.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
+Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ceph/auth.c | 2 +-
+ net/ceph/mon_client.c | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+--- a/net/ceph/auth.c
++++ b/net/ceph/auth.c
+@@ -257,7 +257,7 @@ int ceph_handle_auth_reply(struct ceph_a
+ ac->negotiating = false;
+ }
+
+- if (result) {
++ if (result < 0) {
+ pr_err("auth protocol '%s' mauth authentication failed: %d\n",
+ ceph_auth_proto_name(ac->protocol), result);
+ ret = result;
+--- a/net/ceph/mon_client.c
++++ b/net/ceph/mon_client.c
+@@ -174,6 +174,8 @@ int ceph_monmap_contains(struct ceph_mon
+ */
+ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
+ {
++ BUG_ON(len > monc->m_auth->front_alloc_len);
++
+ monc->pending_auth = 1;
+ monc->m_auth->front.iov_len = len;
+ monc->m_auth->hdr.front_len = cpu_to_le32(len);
--- /dev/null
+From 9aa6d860b0930e2f72795665c42c44252a558a0c Mon Sep 17 00:00:00 2001
+From: Junrui Luo <moonafterrain@outlook.com>
+Date: Thu, 16 Apr 2026 11:39:56 +0800
+Subject: md/raid10: fix divide-by-zero in setup_geo() with zero far_copies
+
+From: Junrui Luo <moonafterrain@outlook.com>
+
+commit 9aa6d860b0930e2f72795665c42c44252a558a0c upstream.
+
+setup_geo() extracts near_copies (nc) and far_copies (fc) from the
+user-provided layout parameter without checking for zero. When fc=0
+with the "improved" far set layout selected, 'geo->far_set_size =
+disks / fc' triggers a divide-by-zero.
+
+Validate nc and fc immediately after extraction, returning -1 if
+either is zero.
+
+Fixes: 475901aff158 ("MD RAID10: Improve redundancy for 'far' and 'offset' algorithms (part 1)")
+Cc: stable@vger.kernel.org
+Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
+Link: https://lore.kernel.org/linux-raid/SYBPR01MB7881A5E2556806CC1D318582AF232@SYBPR01MB7881.ausprd01.prod.outlook.com
+Signed-off-by: Yu Kuai <yukuai@fnnas.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/raid10.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/md/raid10.c
++++ b/drivers/md/raid10.c
+@@ -3791,6 +3791,8 @@ static int setup_geo(struct geom *geo, s
+ nc = layout & 255;
+ fc = (layout >> 8) & 255;
+ fo = layout & (1<<16);
++ if (!nc || !fc)
++ return -1;
+ geo->raid_disks = disks;
+ geo->near_copies = nc;
+ geo->far_copies = fc;
--- /dev/null
+From b98b7ff6025ae82570d4915e083f0cbd8d48b3cf Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Sun, 19 Apr 2026 09:10:01 -0700
+Subject: mm/damon/lru_sort: detect and use fresh enabled and kdamond_pid values
+
+From: SeongJae Park <sj@kernel.org>
+
+commit b98b7ff6025ae82570d4915e083f0cbd8d48b3cf upstream.
+
+DAMON_LRU_SORT updates 'enabled' and 'kdamond_pid' parameter values, which
+represents the running status of its kdamond, when the user explicitly
+requests start/stop of the kdamond. The kdamond can, however, be stopped
+in events other than the explicit user request in the following three
+events.
+
+1. ctx->regions_score_histogram allocation failure at beginning of the
+ execution,
+2. damon_commit_ctx() failure due to invalid user input, and
+3. damon_commit_ctx() failure due to its internal allocation failures.
+
+Hence, if the kdamond is stopped by the above three events, the values of
+the status parameters can be stale. Users could show the stale values and
+be confused. This is already bad, but the real consequence is worse.
+DAMON_LRU_SORT avoids unnecessary damon_start() and damon_stop() calls
+based on the 'enabled' parameter value. And the update of 'enabled'
+parameter value depends on the damon_start() and damon_stop() call
+results. Hence, once the kdamond has stopped by the unintentional events,
+the user cannot restart the kdamond before the system reboot. For
+example, the issue can be reproduced via below steps.
+
+ # cd /sys/module/damon_lru_sort/parameters
+ #
+ # # start DAMON_LRU_SORT
+ # echo Y > enabled
+ # ps -ef | grep kdamond
+ root 806 2 0 17:53 ? 00:00:00 [kdamond.0]
+ root 808 803 0 17:53 pts/4 00:00:00 grep kdamond
+ #
+ # # commit wrong input to stop kdamond withou explicit stop request
+ # echo 3 > addr_unit
+ # echo Y > commit_inputs
+ bash: echo: write error: Invalid argument
+ #
+ # # confirm kdamond is stopped
+ # ps -ef | grep kdamond
+ root 811 803 0 17:53 pts/4 00:00:00 grep kdamond
+ #
+ # # users casn now show stable status
+ # cat enabled
+ Y
+ # cat kdamond_pid
+ 806
+ #
+ # # even after fixing the wrong parameter,
+ # # kdamond cannot be restarted.
+ # echo 1 > addr_unit
+ # echo Y > enabled
+ # ps -ef | grep kdamond
+ root 815 803 0 17:54 pts/4 00:00:00 grep kdamond
+
+The problem will only rarely happen in real and common setups for the
+following reasons. The allocation failures are unlikely in such setups
+since those allocations are arguably too small to fail. Also sane users
+on real production environments may not commit wrong input parameters.
+But once it happens, the consequence is quite bad. And the bug is a bug.
+
+The issue stems from the fact that there are multiple events that can
+change the status, and following all the events is challenging.
+Dynamically detect and use the fresh status for the parameters when those
+are requested.
+
+Link: https://lore.kernel.org/20260419161003.79176-3-sj@kernel.org
+Fixes: 40e983cca927 ("mm/damon: introduce DAMON-based LRU-lists Sorting")
+Co-developed-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 6.0.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/lru_sort.c | 85 +++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 55 insertions(+), 30 deletions(-)
+
+--- a/mm/damon/lru_sort.c
++++ b/mm/damon/lru_sort.c
+@@ -161,15 +161,6 @@ module_param(monitor_region_end, ulong,
+ */
+ static unsigned long addr_unit __read_mostly = 1;
+
+-/*
+- * PID of the DAMON thread
+- *
+- * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
+- * Else, -1.
+- */
+-static int kdamond_pid __read_mostly = -1;
+-module_param(kdamond_pid, int, 0400);
+-
+ static struct damos_stat damon_lru_sort_hot_stat;
+ DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat,
+ lru_sort_tried_hot_regions, lru_sorted_hot_regions,
+@@ -391,12 +382,8 @@ static int damon_lru_sort_turn(bool on)
+ {
+ int err;
+
+- if (!on) {
+- err = damon_stop(&ctx, 1);
+- if (!err)
+- kdamond_pid = -1;
+- return err;
+- }
++ if (!on)
++ return damon_stop(&ctx, 1);
+
+ err = damon_lru_sort_apply_parameters();
+ if (err)
+@@ -405,9 +392,6 @@ static int damon_lru_sort_turn(bool on)
+ err = damon_start(&ctx, 1, true);
+ if (err)
+ return err;
+- kdamond_pid = damon_kdamond_pid(ctx);
+- if (kdamond_pid < 0)
+- return kdamond_pid;
+ return damon_call(ctx, &call_control);
+ }
+
+@@ -435,42 +419,83 @@ module_param_cb(addr_unit, &addr_unit_pa
+ MODULE_PARM_DESC(addr_unit,
+ "Scale factor for DAMON_LRU_SORT to ops address conversion (default: 1)");
+
++static bool damon_lru_sort_enabled(void)
++{
++ if (!ctx)
++ return false;
++ return damon_is_running(ctx);
++}
++
+ static int damon_lru_sort_enabled_store(const char *val,
+ const struct kernel_param *kp)
+ {
+- bool is_enabled = enabled;
+- bool enable;
+ int err;
+
+- err = kstrtobool(val, &enable);
++ err = kstrtobool(val, &enabled);
+ if (err)
+ return err;
+
+- if (is_enabled == enable)
++ if (damon_lru_sort_enabled() == enabled)
+ return 0;
+
+ /* Called before init function. The function will handle this. */
+ if (!damon_initialized())
+- goto set_param_out;
++ return 0;
+
+- err = damon_lru_sort_turn(enable);
+- if (err)
+- return err;
++ return damon_lru_sort_turn(enabled);
++}
+
+-set_param_out:
+- enabled = enable;
+- return err;
++static int damon_lru_sort_enabled_load(char *buffer,
++ const struct kernel_param *kp)
++{
++ return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
+ }
+
+ static const struct kernel_param_ops enabled_param_ops = {
+ .set = damon_lru_sort_enabled_store,
+- .get = param_get_bool,
++ .get = damon_lru_sort_enabled_load,
+ };
+
+ module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
+ MODULE_PARM_DESC(enabled,
+ "Enable or disable DAMON_LRU_SORT (default: disabled)");
+
++static int damon_lru_sort_kdamond_pid_store(const char *val,
++ const struct kernel_param *kp)
++{
++ /*
++ * kdamond_pid is read-only, but kernel command line could write it.
++ * Do nothing here.
++ */
++ return 0;
++}
++
++static int damon_lru_sort_kdamond_pid_load(char *buffer,
++ const struct kernel_param *kp)
++{
++ int kdamond_pid = -1;
++
++ if (ctx) {
++ kdamond_pid = damon_kdamond_pid(ctx);
++ if (kdamond_pid < 0)
++ kdamond_pid = -1;
++ }
++ return sprintf(buffer, "%d\n", kdamond_pid);
++}
++
++static const struct kernel_param_ops kdamond_pid_param_ops = {
++ .set = damon_lru_sort_kdamond_pid_store,
++ .get = damon_lru_sort_kdamond_pid_load,
++};
++
++/*
++ * PID of the DAMON thread
++ *
++ * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
++ * Else, -1.
++ */
++module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
++
+ static int __init damon_lru_sort_init(void)
+ {
+ int err;
--- /dev/null
+From 64a140afa5ed1c6f5ba6d451512cbdbbab1ba339 Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Sun, 19 Apr 2026 09:10:00 -0700
+Subject: mm/damon/reclaim: detect and use fresh enabled and kdamond_pid values
+
+From: SeongJae Park <sj@kernel.org>
+
+commit 64a140afa5ed1c6f5ba6d451512cbdbbab1ba339 upstream.
+
+Patch series "mm/damon/modules: detect and use fresh status", v3.
+
+DAMON modules including DAMON_RECLAIM, DAMON_LRU_SORT and DAMON_STAT
+commonly expose the kdamond running status via their parameters. Under
+certain scenarios including wrong user inputs and memory allocation
+failures, those parameter values can be stale. It can confuse users. For
+DAMON_RECLAIM and DAMON_LRU_SORT, it even makes the kdamond unable to be
+restarted before the system reboot.
+
+The problem comes from the fact that there are multiple events for the
+status changes and it is difficult to follow up all the scenarios. Fix
+the issue by detecting and using the status on demand, instead of using a
+cached status that is difficult to be updated.
+
+Patches 1-3 fix the bugs in DAMON_RECLAIM, DAMON_LRU_SORT and DAMON_STAT
+in the order.
+
+
+This patch (of 3):
+
+DAMON_RECLAIM updates 'enabled' and 'kdamond_pid' parameter values, which
+represents the running status of its kdamond, when the user explicitly
+requests start/stop of the kdamond. The kdamond can, however, be stopped
+in events other than the explicit user request in the following three
+events.
+
+1. ctx->regions_score_histogram allocation failure at beginning of the
+ execution,
+2. damon_commit_ctx() failure due to invalid user input, and
+3. damon_commit_ctx() failure due to its internal allocation failures.
+
+Hence, if the kdamond is stopped by the above three events, the values of
+the status parameters can be stale. Users could show the stale values and
+be confused. This is already bad, but the real consequence is worse.
+DAMON_RECLAIM avoids unnecessary damon_start() and damon_stop() calls
+based on the 'enabled' parameter value. And the update of 'enabled'
+parameter value depends on the damon_start() and damon_stop() call
+results. Hence, once the kdamond has stopped by the unintentional events,
+the user cannot restart the kdamond before the system reboot. For
+example, the issue can be reproduced via below steps.
+
+ # cd /sys/module/damon_reclaim/parameters
+ #
+ # # start DAMON_RECLAIM
+ # echo Y > enabled
+ # ps -ef | grep kdamond
+ root 806 2 0 17:53 ? 00:00:00 [kdamond.0]
+ root 808 803 0 17:53 pts/4 00:00:00 grep kdamond
+ #
+ # # commit wrong input to stop kdamond withou explicit stop request
+ # echo 3 > addr_unit
+ # echo Y > commit_inputs
+ bash: echo: write error: Invalid argument
+ #
+ # # confirm kdamond is stopped
+ # ps -ef | grep kdamond
+ root 811 803 0 17:53 pts/4 00:00:00 grep kdamond
+ #
+ # # users casn now show stable status
+ # cat enabled
+ Y
+ # cat kdamond_pid
+ 806
+ #
+ # # even after fixing the wrong parameter,
+ # # kdamond cannot be restarted.
+ # echo 1 > addr_unit
+ # echo Y > enabled
+ # ps -ef | grep kdamond
+ root 815 803 0 17:54 pts/4 00:00:00 grep kdamond
+
+The problem will only rarely happen in real and common setups for the
+following reasons. The allocation failures are unlikely in such setups
+since those allocations are arguably too small to fail. Also sane users
+on real production environments may not commit wrong input parameters.
+But once it happens, the consequence is quite bad. And the bug is a bug.
+
+The issue stems from the fact that there are multiple events that can
+change the status, and following all the events is challenging.
+Dynamically detect and use the fresh status for the parameters when those
+are requested.
+
+Link: https://lore.kernel.org/20260419161003.79176-1-sj@kernel.org
+Link: https://lore.kernel.org/20260419161003.79176-2-sj@kernel.org
+Fixes: e035c280f6df ("mm/damon/reclaim: support online inputs update")
+Co-developed-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 5.19.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/reclaim.c | 85 ++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 55 insertions(+), 30 deletions(-)
+
+--- a/mm/damon/reclaim.c
++++ b/mm/damon/reclaim.c
+@@ -144,15 +144,6 @@ static unsigned long addr_unit __read_mo
+ static bool skip_anon __read_mostly;
+ module_param(skip_anon, bool, 0600);
+
+-/*
+- * PID of the DAMON thread
+- *
+- * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
+- * Else, -1.
+- */
+-static int kdamond_pid __read_mostly = -1;
+-module_param(kdamond_pid, int, 0400);
+-
+ static struct damos_stat damon_reclaim_stat;
+ DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
+ reclaim_tried_regions, reclaimed_regions, quota_exceeds);
+@@ -293,12 +284,8 @@ static int damon_reclaim_turn(bool on)
+ {
+ int err;
+
+- if (!on) {
+- err = damon_stop(&ctx, 1);
+- if (!err)
+- kdamond_pid = -1;
+- return err;
+- }
++ if (!on)
++ return damon_stop(&ctx, 1);
+
+ err = damon_reclaim_apply_parameters();
+ if (err)
+@@ -307,9 +294,6 @@ static int damon_reclaim_turn(bool on)
+ err = damon_start(&ctx, 1, true);
+ if (err)
+ return err;
+- kdamond_pid = damon_kdamond_pid(ctx);
+- if (kdamond_pid < 0)
+- return kdamond_pid;
+ return damon_call(ctx, &call_control);
+ }
+
+@@ -337,42 +321,83 @@ module_param_cb(addr_unit, &addr_unit_pa
+ MODULE_PARM_DESC(addr_unit,
+ "Scale factor for DAMON_RECLAIM to ops address conversion (default: 1)");
+
++static bool damon_reclaim_enabled(void)
++{
++ if (!ctx)
++ return false;
++ return damon_is_running(ctx);
++}
++
+ static int damon_reclaim_enabled_store(const char *val,
+ const struct kernel_param *kp)
+ {
+- bool is_enabled = enabled;
+- bool enable;
+ int err;
+
+- err = kstrtobool(val, &enable);
++ err = kstrtobool(val, &enabled);
+ if (err)
+ return err;
+
+- if (is_enabled == enable)
++ if (damon_reclaim_enabled() == enabled)
+ return 0;
+
+ /* Called before init function. The function will handle this. */
+ if (!damon_initialized())
+- goto set_param_out;
++ return 0;
+
+- err = damon_reclaim_turn(enable);
+- if (err)
+- return err;
++ return damon_reclaim_turn(enabled);
++}
+
+-set_param_out:
+- enabled = enable;
+- return err;
++static int damon_reclaim_enabled_load(char *buffer,
++ const struct kernel_param *kp)
++{
++ return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
+ }
+
+ static const struct kernel_param_ops enabled_param_ops = {
+ .set = damon_reclaim_enabled_store,
+- .get = param_get_bool,
++ .get = damon_reclaim_enabled_load,
+ };
+
+ module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
+ MODULE_PARM_DESC(enabled,
+ "Enable or disable DAMON_RECLAIM (default: disabled)");
+
++static int damon_reclaim_kdamond_pid_store(const char *val,
++ const struct kernel_param *kp)
++{
++ /*
++ * kdamond_pid is read-only, but kernel command line could write it.
++ * Do nothing here.
++ */
++ return 0;
++}
++
++static int damon_reclaim_kdamond_pid_load(char *buffer,
++ const struct kernel_param *kp)
++{
++ int kdamond_pid = -1;
++
++ if (ctx) {
++ kdamond_pid = damon_kdamond_pid(ctx);
++ if (kdamond_pid < 0)
++ kdamond_pid = -1;
++ }
++ return sprintf(buffer, "%d\n", kdamond_pid);
++}
++
++static const struct kernel_param_ops kdamond_pid_param_ops = {
++ .set = damon_reclaim_kdamond_pid_store,
++ .get = damon_reclaim_kdamond_pid_load,
++};
++
++/*
++ * PID of the DAMON thread
++ *
++ * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
++ * Else, -1.
++ */
++module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
++
+ static int __init damon_reclaim_init(void)
+ {
+ int err;
--- /dev/null
+From f98590bc08d4aea435e1c2213e38bae0d9e9a7bb Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Sun, 19 Apr 2026 09:10:02 -0700
+Subject: mm/damon/stat: detect and use fresh enabled value
+
+From: SeongJae Park <sj@kernel.org>
+
+commit f98590bc08d4aea435e1c2213e38bae0d9e9a7bb upstream.
+
+DAMON_STAT updates 'enabled' parameter value, which represents the running
+status of its kdamond, when the user explicitly requests start/stop of the
+kdamond. The kdamond can, however, be stopped even if the user explicitly
+requested the stop, if ctx->regions_score_histogram allocation failure at
+beginning of the execution of the kdamond. Hence, if the kdamond is
+stopped by the allocation failure, the value of the parameter can be
+stale.
+
+Users could show the stale value and be confused. The problem will only
+rarely happen in real and common setups because the allocation is arguably
+too small to fail. Also, unlike the similar bugs that are now fixed in
+DAMON_RECLAIM and DAMON_LRU_SORT, kdamond can be restarted in this case,
+because DAMON_STAT force-updates the enabled parameter value for user
+inputs. The bug is a bug, though.
+
+The issue stems from the fact that there are multiple events that can
+change the status, and following all the events is challenging.
+Dynamically detect and use the fresh status for the parameters when those
+are requested.
+
+The issue was dicovered [1] by Sashiko.
+
+Link: https://lore.kernel.org/20260419161003.79176-4-sj@kernel.org
+Link: https://lore.kernel.org/20260416040602.88665-1-sj@kernel.org [1]
+Fixes: 369c415e6073 ("mm/damon: introduce DAMON_STAT module")
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: Liew Rui Yan <aethernet65535@gmail.com>
+Cc: <stable@vger.kernel.org> # 6.17.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/stat.c | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+--- a/mm/damon/stat.c
++++ b/mm/damon/stat.c
+@@ -19,14 +19,17 @@
+ static int damon_stat_enabled_store(
+ const char *val, const struct kernel_param *kp);
+
++static int damon_stat_enabled_load(char *buffer,
++ const struct kernel_param *kp);
++
+ static const struct kernel_param_ops enabled_param_ops = {
+ .set = damon_stat_enabled_store,
+- .get = param_get_bool,
++ .get = damon_stat_enabled_load,
+ };
+
+ static bool enabled __read_mostly = IS_ENABLED(
+ CONFIG_DAMON_STAT_ENABLED_DEFAULT);
+-module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
++module_param_cb(enabled, &enabled_param_ops, NULL, 0600);
+ MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT");
+
+ static unsigned long estimated_memory_bandwidth __read_mostly;
+@@ -273,17 +276,23 @@ static void damon_stat_stop(void)
+ damon_stat_context = NULL;
+ }
+
++static bool damon_stat_enabled(void)
++{
++ if (!damon_stat_context)
++ return false;
++ return damon_is_running(damon_stat_context);
++}
++
+ static int damon_stat_enabled_store(
+ const char *val, const struct kernel_param *kp)
+ {
+- bool is_enabled = enabled;
+ int err;
+
+ err = kstrtobool(val, &enabled);
+ if (err)
+ return err;
+
+- if (is_enabled == enabled)
++ if (damon_stat_enabled() == enabled)
+ return 0;
+
+ if (!damon_initialized())
+@@ -293,16 +302,17 @@ static int damon_stat_enabled_store(
+ */
+ return 0;
+
+- if (enabled) {
+- err = damon_stat_start();
+- if (err)
+- enabled = false;
+- return err;
+- }
++ if (enabled)
++ return damon_stat_start();
+ damon_stat_stop();
+ return 0;
+ }
+
++static int damon_stat_enabled_load(char *buffer, const struct kernel_param *kp)
++{
++ return sprintf(buffer, "%c\n", damon_stat_enabled() ? 'Y' : 'N');
++}
++
+ static int __init damon_stat_init(void)
+ {
+ int err = 0;
--- /dev/null
+From 1e68eb96e8beb1abefd12dd22c5637795d8a877e Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Thu, 23 Apr 2026 08:02:51 -0700
+Subject: mm/damon/sysfs-schemes: protect memcg_path kfree() with damon_sysfs_lock
+
+From: SeongJae Park <sj@kernel.org>
+
+commit 1e68eb96e8beb1abefd12dd22c5637795d8a877e upstream.
+
+Patch series "mm/damon/sysfs-schemes: fix use-after-free for [memcg_]path".
+
+Reads of 'memcg_path' and 'path' files in DAMON sysfs interface could race
+with their writes, results in use-after-free. Fix those.
+
+
+This patch (of 2):
+
+damon_sysfs_scheme_filter->mmecg_path can be read and written by users,
+via DAMON sysfs memcg_path file. It can also be indirectly read, for the
+parameters {on,off}line committing to DAMON. The reads for parameters
+committing are protected by damon_sysfs_lock to avoid the sysfs files
+being destroyed while any of the parameters are being read. But the
+user-driven direct reads and writes are not protected by any lock, while
+the write is deallocating the memcg_path-pointing buffer. As a result,
+the readers could read the already freed buffer (user-after-free). Note
+that the user-reads don't race when the same open file is used by the
+writer, due to kernfs's open file locking. Nonetheless, doing the reads
+and writes with separate open files would be common. Fix it by protecting
+both the user-direct reads and writes with damon_sysfs_lock.
+
+Link: https://lore.kernel.org/20260423150253.111520-1-sj@kernel.org
+Link: https://lore.kernel.org/20260423150253.111520-2-sj@kernel.org
+Fixes: 4f489fe6afb3 ("mm/damon/sysfs-schemes: free old damon_sysfs_scheme_filter->memcg_path on write")
+Co-developed-by: Junxi Qian <qjx1298677004@gmail.com>
+Signed-off-by: Junxi Qian <qjx1298677004@gmail.com>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 6.16.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/sysfs-schemes.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/mm/damon/sysfs-schemes.c
++++ b/mm/damon/sysfs-schemes.c
+@@ -533,9 +533,14 @@ static ssize_t memcg_path_show(struct ko
+ {
+ struct damon_sysfs_scheme_filter *filter = container_of(kobj,
+ struct damon_sysfs_scheme_filter, kobj);
++ int len;
+
+- return sysfs_emit(buf, "%s\n",
++ if (!mutex_trylock(&damon_sysfs_lock))
++ return -EBUSY;
++ len = sysfs_emit(buf, "%s\n",
+ filter->memcg_path ? filter->memcg_path : "");
++ mutex_unlock(&damon_sysfs_lock);
++ return len;
+ }
+
+ static ssize_t memcg_path_store(struct kobject *kobj,
+@@ -550,8 +555,13 @@ static ssize_t memcg_path_store(struct k
+ return -ENOMEM;
+
+ strscpy(path, buf, count + 1);
++ if (!mutex_trylock(&damon_sysfs_lock)) {
++ kfree(path);
++ return -EBUSY;
++ }
+ kfree(filter->memcg_path);
+ filter->memcg_path = path;
++ mutex_unlock(&damon_sysfs_lock);
+ return count;
+ }
+
--- /dev/null
+From cf3b71421ca00807328c6d9cd242f9de3b77a4bf Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Thu, 23 Apr 2026 08:02:52 -0700
+Subject: mm/damon/sysfs-schemes: protect path kfree() with damon_sysfs_lock
+
+From: SeongJae Park <sj@kernel.org>
+
+commit cf3b71421ca00807328c6d9cd242f9de3b77a4bf upstream.
+
+damon_sysfs_quot_goal->path can be read and written by users, via DAMON
+sysfs 'path' file. It can also be indirectly read, for the parameters
+{on,off}line committing to DAMON. The reads for parameters committing are
+protected by damon_sysfs_lock to avoid the sysfs files being destroyed
+while any of the parameters are being read. But the user-driven direct
+reads and writes are not protected by any lock, while the write is
+deallocating the path-pointing buffer. As a result, the readers could
+read the already freed buffer (user-after-free). Note that the user-reads
+don't race when the same open file is used by the writer, due to kernfs's
+open file locking. Nonetheless, doing the reads and writes with separate
+open files would be common. Fix it by protecting both the user-direct
+reads and writes with damon_sysfs_lock.
+
+Link: https://lore.kernel.org/20260423150253.111520-3-sj@kernel.org
+Fixes: c41e253a411e ("mm/damon/sysfs-schemes: implement path file under quota goal directory")
+Co-developed-by: Junxi Qian <qjx1298677004@gmail.com>
+Signed-off-by: Junxi Qian <qjx1298677004@gmail.com>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 6.19.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/sysfs-schemes.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/mm/damon/sysfs-schemes.c
++++ b/mm/damon/sysfs-schemes.c
+@@ -1197,8 +1197,13 @@ static ssize_t path_show(struct kobject
+ {
+ struct damos_sysfs_quota_goal *goal = container_of(kobj,
+ struct damos_sysfs_quota_goal, kobj);
++ int len;
+
+- return sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
++ if (!mutex_trylock(&damon_sysfs_lock))
++ return -EBUSY;
++ len = sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
++ mutex_unlock(&damon_sysfs_lock);
++ return len;
+ }
+
+ static ssize_t path_store(struct kobject *kobj,
+@@ -1213,8 +1218,13 @@ static ssize_t path_store(struct kobject
+ return -ENOMEM;
+
+ strscpy(path, buf, count + 1);
++ if (!mutex_trylock(&damon_sysfs_lock)) {
++ kfree(path);
++ return -EBUSY;
++ }
+ kfree(goal->path);
+ goal->path = path;
++ mutex_unlock(&damon_sysfs_lock);
+ return count;
+ }
+
--- /dev/null
+From ba9d308ccd6732dd97ed8080d834a4a89e758e14 Mon Sep 17 00:00:00 2001
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+Date: Wed, 8 Apr 2026 17:18:14 +0300
+Subject: nvme-apple: drop invalid put of admin queue reference count
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+commit ba9d308ccd6732dd97ed8080d834a4a89e758e14 upstream.
+
+Commit 03b3bcd319b3 ("nvme: fix admin request_queue lifetime") moved the
+admin queue reference ->put call into nvme_free_ctrl() - a controller
+device release callback performed for every nvme driver doing
+nvme_init_ctrl().
+
+nvme-apple sets refcount of the admin queue to 1 at allocation during the
+probe function and then puts it twice now:
+
+nvme_free_ctrl()
+ blk_put_queue(ctrl->admin_q) // #1
+ ->free_ctrl()
+ apple_nvme_free_ctrl()
+ blk_put_queue(anv->ctrl.admin_q) // #2
+
+Note that there is a commit 941f7298c70c ("nvme-apple: remove an extra
+queue reference") which intended to drop taking an extra admin queue
+reference. Looks like at that moment it accidentally fixed a refcount
+leak, which existed since the driver's introduction. There were two ->get
+calls at driver's probe function and a single ->put inside
+apple_nvme_free_ctrl().
+
+However now after commit 03b3bcd319b3 ("nvme: fix admin request_queue
+lifetime") the refcount is imbalanced again. Fix it by removing extra
+->put call from apple_nvme_free_ctrl(). anv->dev and ctrl->dev point to
+the same device, so use ctrl->dev directly for simplification. Compile
+tested only.
+
+Found by Linux Verification Center (linuxtesting.org).
+
+Fixes: 03b3bcd319b3 ("nvme: fix admin request_queue lifetime")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvme/host/apple.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/drivers/nvme/host/apple.c
++++ b/drivers/nvme/host/apple.c
+@@ -1267,11 +1267,7 @@ static int apple_nvme_get_address(struct
+
+ static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl)
+ {
+- struct apple_nvme *anv = ctrl_to_apple_nvme(ctrl);
+-
+- if (anv->ctrl.admin_q)
+- blk_put_queue(anv->ctrl.admin_q);
+- put_device(anv->dev);
++ put_device(ctrl->dev);
+ }
+
+ static const struct nvme_ctrl_ops nvme_ctrl_ops = {
--- /dev/null
+From aade8abd8b868b6ffa9697aadaea28ec7f65bee6 Mon Sep 17 00:00:00 2001
+From: Chaitanya Kulkarni <kch@nvidia.com>
+Date: Wed, 8 Apr 2026 17:56:47 -0700
+Subject: nvmet: avoid recursive nvmet-wq flush in nvmet_ctrl_free
+
+From: Chaitanya Kulkarni <kch@nvidia.com>
+
+commit aade8abd8b868b6ffa9697aadaea28ec7f65bee6 upstream.
+
+nvmet_tcp_release_queue_work() runs on nvmet-wq and can drop the
+final controller reference through nvmet_cq_put(). If that triggers
+nvmet_ctrl_free(), the teardown path flushes ctrl->async_event_work on
+the same nvmet-wq.
+
+Call chain:
+
+ nvmet_tcp_schedule_release_queue()
+ kref_put(&queue->kref, nvmet_tcp_release_queue)
+ nvmet_tcp_release_queue()
+ queue_work(nvmet_wq, &queue->release_work) <--- nvmet_wq
+ process_one_work()
+ nvmet_tcp_release_queue_work()
+ nvmet_cq_put(&queue->nvme_cq)
+ nvmet_cq_destroy()
+ nvmet_ctrl_put(cq->ctrl)
+ nvmet_ctrl_free()
+ flush_work(&ctrl->async_event_work) <--- nvmet_wq
+
+ Previously Scheduled by :-
+ nvmet_add_async_event
+ queue_work(nvmet_wq, &ctrl->async_event_work);
+
+This trips lockdep with a possible recursive locking warning.
+
+[ 5223.015876] run blktests nvme/003 at 2026-04-07 20:53:55
+[ 5223.061801] loop0: detected capacity change from 0 to 2097152
+[ 5223.072206] nvmet: adding nsid 1 to subsystem blktests-subsystem-1
+[ 5223.088368] nvmet_tcp: enabling port 0 (127.0.0.1:4420)
+[ 5223.126086] nvmet: Created discovery controller 1 for subsystem nqn.2014-08.org.nvmexpress.discovery for NQN nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349.
+[ 5223.128453] nvme nvme1: new ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery", addr 127.0.0.1:4420, hostnqn: nqn.2014-08.org.nvmexpress:uuid:0f01fb42-9f7f-4856-b0b3-51e60b8de349
+[ 5233.199447] nvme nvme1: Removing ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery"
+
+[ 5233.227718] ============================================
+[ 5233.231283] WARNING: possible recursive locking detected
+[ 5233.234696] 7.0.0-rc3nvme+ #20 Tainted: G O N
+[ 5233.238434] --------------------------------------------
+[ 5233.241852] kworker/u192:6/2413 is trying to acquire lock:
+[ 5233.245429] ffff888111632548 ((wq_completion)nvmet-wq){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x26/0x90
+[ 5233.251438]
+ but task is already holding lock:
+[ 5233.255254] ffff888111632548 ((wq_completion)nvmet-wq){+.+.}-{0:0}, at: process_one_work+0x5cc/0x6e0
+[ 5233.261125]
+ other info that might help us debug this:
+[ 5233.265333] Possible unsafe locking scenario:
+
+[ 5233.269217] CPU0
+[ 5233.270795] ----
+[ 5233.272436] lock((wq_completion)nvmet-wq);
+[ 5233.275241] lock((wq_completion)nvmet-wq);
+[ 5233.278020]
+ *** DEADLOCK ***
+
+[ 5233.281793] May be due to missing lock nesting notation
+
+[ 5233.286195] 3 locks held by kworker/u192:6/2413:
+[ 5233.289192] #0: ffff888111632548 ((wq_completion)nvmet-wq){+.+.}-{0:0}, at: process_one_work+0x5cc/0x6e0
+[ 5233.294569] #1: ffffc9000e2a7e40 ((work_completion)(&queue->release_work)){+.+.}-{0:0}, at: process_one_work+0x1c5/0x6e0
+[ 5233.300128] #2: ffffffff82d7dc40 (rcu_read_lock){....}-{1:3}, at: __flush_work+0x62/0x530
+[ 5233.304290]
+ stack backtrace:
+[ 5233.306520] CPU: 4 UID: 0 PID: 2413 Comm: kworker/u192:6 Tainted: G O N 7.0.0-rc3nvme+ #20 PREEMPT(full)
+[ 5233.306524] Tainted: [O]=OOT_MODULE, [N]=TEST
+[ 5233.306525] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014
+[ 5233.306527] Workqueue: nvmet-wq nvmet_tcp_release_queue_work [nvmet_tcp]
+[ 5233.306532] Call Trace:
+[ 5233.306534] <TASK>
+[ 5233.306536] dump_stack_lvl+0x73/0xb0
+[ 5233.306552] print_deadlock_bug+0x225/0x2f0
+[ 5233.306556] __lock_acquire+0x13f0/0x2290
+[ 5233.306563] lock_acquire+0xd0/0x300
+[ 5233.306565] ? touch_wq_lockdep_map+0x26/0x90
+[ 5233.306571] ? __flush_work+0x20b/0x530
+[ 5233.306573] ? touch_wq_lockdep_map+0x26/0x90
+[ 5233.306577] touch_wq_lockdep_map+0x3b/0x90
+[ 5233.306580] ? touch_wq_lockdep_map+0x26/0x90
+[ 5233.306583] ? __flush_work+0x20b/0x530
+[ 5233.306585] __flush_work+0x268/0x530
+[ 5233.306588] ? __pfx_wq_barrier_func+0x10/0x10
+[ 5233.306594] ? xen_error_entry+0x30/0x60
+[ 5233.306600] nvmet_ctrl_free+0x140/0x310 [nvmet]
+[ 5233.306617] nvmet_cq_put+0x74/0x90 [nvmet]
+[ 5233.306629] nvmet_tcp_release_queue_work+0x19f/0x360 [nvmet_tcp]
+[ 5233.306634] process_one_work+0x206/0x6e0
+[ 5233.306640] worker_thread+0x184/0x320
+[ 5233.306643] ? __pfx_worker_thread+0x10/0x10
+[ 5233.306646] kthread+0xf1/0x130
+[ 5233.306648] ? __pfx_kthread+0x10/0x10
+[ 5233.306651] ret_from_fork+0x355/0x450
+[ 5233.306653] ? __pfx_kthread+0x10/0x10
+[ 5233.306656] ret_from_fork_asm+0x1a/0x30
+[ 5233.306664] </TASK>
+
+There is also no need to flush async_event_work from controller
+teardown. The admin queue teardown already fails outstanding AER
+requests before the final controller put :-
+
+ nvmet_sq_destroy(admin sq)
+ nvmet_async_events_failall(ctrl)
+
+The controller has already been removed from the subsystem list before
+nvmet_ctrl_free() quiesces outstanding work.
+
+Replace flush_work() with cancel_work_sync() so a pending
+async_event_work item is canceled and a running instance is waited on
+without recursing into the same workqueue.
+
+Fixes: 06406d81a2d7 ("nvmet: cancel fatal error and flush async work before free controller")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Chaitanya Kulkarni <kch@nvidia.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvme/target/core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvme/target/core.c
++++ b/drivers/nvme/target/core.c
+@@ -1743,7 +1743,7 @@ static void nvmet_ctrl_free(struct kref
+
+ nvmet_stop_keep_alive_timer(ctrl);
+
+- flush_work(&ctrl->async_event_work);
++ cancel_work_sync(&ctrl->async_event_work);
+ cancel_work_sync(&ctrl->fatal_err_work);
+
+ nvmet_destroy_auth(ctrl);
--- /dev/null
+From 5293a8882c549fab4a878bc76b0b6c951f980a61 Mon Sep 17 00:00:00 2001
+From: Chaitanya Kulkarni <kch@nvidia.com>
+Date: Wed, 8 Apr 2026 00:51:31 -0700
+Subject: nvmet-tcp: fix race between ICReq handling and queue teardown
+
+From: Chaitanya Kulkarni <kch@nvidia.com>
+
+commit 5293a8882c549fab4a878bc76b0b6c951f980a61 upstream.
+
+nvmet_tcp_handle_icreq() updates queue->state after sending an
+Initialization Connection Response (ICResp), but it does so without
+serializing against target-side queue teardown.
+
+If an NVMe/TCP host sends an Initialization Connection Request
+(ICReq) and immediately closes the connection, target-side teardown
+may start in softirq context before io_work drains the already
+buffered ICReq. In that case, nvmet_tcp_schedule_release_queue()
+sets queue->state to NVMET_TCP_Q_DISCONNECTING and drops the queue
+reference under state_lock.
+
+If io_work later processes that ICReq, nvmet_tcp_handle_icreq() can
+still overwrite the state back to NVMET_TCP_Q_LIVE. That defeats the
+DISCONNECTING-state guard in nvmet_tcp_schedule_release_queue() and
+allows a later socket state change to re-enter teardown and issue a
+second kref_put() on an already released queue.
+
+The ICResp send failure path has the same problem. If teardown has
+already moved the queue to DISCONNECTING, a send error can still
+overwrite the state with NVMET_TCP_Q_FAILED, again reopening the
+window for a second teardown path to drop the queue reference.
+
+Fix this by serializing both post-send state transitions with
+state_lock and bailing out if teardown has already started.
+
+Use -ESHUTDOWN as an internal sentinel for that bail-out path rather
+than propagating it as a transport error like -ECONNRESET. Keep
+nvmet_tcp_socket_error() setting rcv_state to NVMET_TCP_RECV_ERR before
+honoring that sentinel so receive-side parsing stays quiesced until the
+existing release path completes.
+
+Fixes: c46a6465bac2 ("nvmet-tcp: add NVMe over TCP target driver")
+Cc: stable@vger.kernel.org
+Reported-by: Shivam Kumar <skumar47@syr.edu>
+Tested-by: Shivam Kumar <kumar.shivam43666@gmail.com>
+Signed-off-by: Chaitanya Kulkarni <kch@nvidia.com>
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvme/target/tcp.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/drivers/nvme/target/tcp.c
++++ b/drivers/nvme/target/tcp.c
+@@ -398,6 +398,19 @@ static void nvmet_tcp_build_pdu_iovec(st
+
+ static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue)
+ {
++ /*
++ * Keep rcv_state at RECV_ERR even for the internal -ESHUTDOWN path.
++ * nvmet_tcp_handle_icreq() can return -ESHUTDOWN after the ICReq has
++ * already been consumed and queue teardown has started.
++ *
++ * If nvmet_tcp_data_ready() or nvmet_tcp_write_space() queues
++ * nvmet_tcp_io_work() again before nvmet_tcp_release_queue_work()
++ * cancels it, the queue must not keep that old receive state.
++ * Otherwise the next nvmet_tcp_io_work() run can reach
++ * nvmet_tcp_done_recv_pdu() and try to handle the same ICReq again.
++ *
++ * That is why queue->rcv_state needs to be updated before we return.
++ */
+ queue->rcv_state = NVMET_TCP_RECV_ERR;
+ if (queue->nvme_sq.ctrl)
+ nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl);
+@@ -922,11 +935,24 @@ static int nvmet_tcp_handle_icreq(struct
+ iov.iov_len = sizeof(*icresp);
+ ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
+ if (ret < 0) {
++ spin_lock_bh(&queue->state_lock);
++ if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
++ spin_unlock_bh(&queue->state_lock);
++ return -ESHUTDOWN;
++ }
+ queue->state = NVMET_TCP_Q_FAILED;
++ spin_unlock_bh(&queue->state_lock);
+ return ret; /* queue removal will cleanup */
+ }
+
++ spin_lock_bh(&queue->state_lock);
++ if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
++ spin_unlock_bh(&queue->state_lock);
++ /* Tell nvmet_tcp_socket_error() teardown is in progress. */
++ return -ESHUTDOWN;
++ }
+ queue->state = NVMET_TCP_Q_LIVE;
++ spin_unlock_bh(&queue->state_lock);
+ nvmet_prepare_receive_pdu(queue);
+ return 0;
+ }
--- /dev/null
+From aa69918bd418e700309fdd08509dba324fb24296 Mon Sep 17 00:00:00 2001
+From: Ilya Maximets <i.maximets@ovn.org>
+Date: Fri, 1 May 2026 01:38:37 +0200
+Subject: openvswitch: vport: fix self-deadlock on release of tunnel ports
+
+From: Ilya Maximets <i.maximets@ovn.org>
+
+commit aa69918bd418e700309fdd08509dba324fb24296 upstream.
+
+vports are used concurrently and protected by RCU, so netdev_put()
+must happen after the RCU grace period. So, either in an RCU call or
+after the synchronize_net(). The rtnl_delete_link() must happen under
+RTNL and so can't be executed in RCU context. Calling synchronize_net()
+while holding RTNL is not a good idea for performance and system
+stability under load in general, so calling netdev_put() in RCU call
+is the right solution here.
+
+However,
+when the device is deleted, rtnl_unlock() will call netdev_run_todo()
+and block until all the references are gone. In the current code this
+means that we never reach the call_rcu() and the vport is never freed
+and the reference is never released, causing a self-deadlock on device
+removal.
+
+Fix that by moving the rcu_call() before the rtnl_unlock(), so the
+scheduled RCU callback will be executed when synchronize_net() is
+called from the rtnl_unlock()->netdev_run_todo() while the RTNL itself
+is already released.
+
+Fixes: 6931d21f87bc ("openvswitch: defer tunnel netdev_put to RCU release")
+Cc: stable@vger.kernel.org
+Acked-by: Eelco Chaudron <echaudro@redhat.com>
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+Acked-by: Aaron Conole <aconole@redhat.com>
+Link: https://patch.msgid.link/20260430233848.440994-2-i.maximets@ovn.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/openvswitch/vport-netdev.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/net/openvswitch/vport-netdev.c
++++ b/net/openvswitch/vport-netdev.c
+@@ -196,9 +196,13 @@ void ovs_netdev_tunnel_destroy(struct vp
+ */
+ if (vport->dev->reg_state == NETREG_REGISTERED)
+ rtnl_delete_link(vport->dev, 0, NULL);
+- rtnl_unlock();
+
++ /* We can't put the device reference yet, since it can still be in
++ * use, but rtnl_unlock()->netdev_run_todo() will block until all
++ * the references are released, so the RCU call must be before it.
++ */
+ call_rcu(&vport->rcu, vport_netdev_free);
++ rtnl_unlock();
+ }
+ EXPORT_SYMBOL_GPL(ovs_netdev_tunnel_destroy);
+
--- /dev/null
+From 909f7bf9b080c10df3c3b38533906dbf09ff1d8b Mon Sep 17 00:00:00 2001
+From: Lukas Wunner <lukas@wunner.de>
+Date: Wed, 15 Apr 2026 17:56:06 +0200
+Subject: PCI: Update saved_config_space upon resource assignment
+
+From: Lukas Wunner <lukas@wunner.de>
+
+commit 909f7bf9b080c10df3c3b38533906dbf09ff1d8b upstream.
+
+Bernd reports passthrough failure of a Digital Devices Cine S2 V6 DVB
+adapter plugged into an ASRock X570S PG Riptide board with BIOS version
+P5.41 (09/07/2023):
+
+ ddbridge 0000:05:00.0: detected Digital Devices Cine S2 V6 DVB adapter
+ ddbridge 0000:05:00.0: cannot read registers
+ ddbridge 0000:05:00.0: fail
+
+BIOS assigns an incorrect BAR to the DVB adapter which doesn't fit into the
+upstream bridge window. The kernel corrects the BAR assignment:
+
+ pci 0000:07:00.0: BAR 0 [mem 0xfffffffffc500000-0xfffffffffc50ffff 64bit]: can't claim; no compatible bridge window
+ pci 0000:07:00.0: BAR 0 [mem 0xfc500000-0xfc50ffff 64bit]: assigned
+
+Correction of the BAR assignment happens in an x86-specific fs_initcall,
+pcibios_assign_resources(), after device enumeration in a subsys_initcall.
+This order was introduced at the behest of Linus in 2004:
+
+ https://git.kernel.org/tglx/history/c/a06a30144bbc
+
+No other architecture performs such a late BAR correction.
+
+Bernd bisected the issue to commit a2f1e22390ac ("PCI/ERR: Ensure error
+recoverability at all times"), but it only occurs in the absence of commit
+4d4c10f763d7 ("PCI: Explicitly put devices into D0 when initializing").
+This combination exists in stable kernel v6.12.70, but not in mainline,
+hence Bernd cannot reproduce the issue with mainline.
+
+Since a2f1e22390ac, config space is saved on enumeration, prior to BAR
+correction. Upon passthrough, the corrected BAR is overwritten with the
+incorrect saved value by:
+
+ vfio_pci_core_register_device()
+ vfio_pci_set_power_state()
+ pci_restore_state()
+
+But only if the device's current_state is PCI_UNKNOWN, as it was prior to
+commit 4d4c10f763d7. Since the commit, it is PCI_D0, which changes the
+behavior of vfio_pci_set_power_state() to no longer restore the state
+without saving it first.
+
+Alexandre is reporting the same issue as Bernd, but in his case, mainline
+is affected as well. The difference is that on Alexandre's system, the
+host kernel binds a driver to the device which is unbound prior to
+passthrough, whereas on Bernd's system no driver gets bound by the host
+kernel.
+
+Unbinding sets current_state to PCI_UNKNOWN in pci_device_remove(), so when
+vfio-pci is subsequently bound to the device, pci_restore_state() is once
+again called without invoking pci_save_state() first.
+
+To robustly fix the issue, always update saved_config_space upon resource
+assignment.
+
+Reported-by: Bernd Schumacher <bernd@bschu.de>
+Closes: https://lore.kernel.org/r/acfZrlP0Ua_5D3U4@eldamar.lan/
+Reported-by: Alexandre N. <an.tech@mailo.com>
+Closes: https://lore.kernel.org/r/dd3c3358-de0f-4a56-9c81-04aceaab4058@mailo.com/
+Fixes: a2f1e22390ac ("PCI/ERR: Ensure error recoverability at all times")
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Tested-by: Bernd Schumacher <bernd@bschu.de>
+Tested-by: Alexandre N. <an.tech@mailo.com>
+Cc: stable@vger.kernel.org # v6.12+
+Link: https://patch.msgid.link/febc3f354e0c1f5a9f5b3ee9ffddaa44caccf651.1776268054.git.lukas@wunner.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/setup-res.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -102,6 +102,7 @@ static void pci_std_update_resource(stru
+ }
+
+ pci_write_config_dword(dev, reg, new);
++ dev->saved_config_space[reg / 4] = new;
+ pci_read_config_dword(dev, reg, &check);
+
+ if ((new ^ check) & mask) {
+@@ -112,6 +113,7 @@ static void pci_std_update_resource(stru
+ if (res->flags & IORESOURCE_MEM_64) {
+ new = region.start >> 16 >> 16;
+ pci_write_config_dword(dev, reg + 4, new);
++ dev->saved_config_space[(reg + 4) / 4] = new;
+ pci_read_config_dword(dev, reg + 4, &check);
+ if (check != new) {
+ pci_err(dev, "%s: error updating (high %#010x != %#010x)\n",
--- /dev/null
+From 26735dfdd8930d9ef1fa92e590a9bf77726efdf6 Mon Sep 17 00:00:00 2001
+From: Ulf Hansson <ulf.hansson@linaro.org>
+Date: Fri, 17 Apr 2026 13:13:31 +0200
+Subject: pmdomain: core: Fix detach procedure for virtual devices in genpd
+
+From: Ulf Hansson <ulf.hansson@linaro.org>
+
+commit 26735dfdd8930d9ef1fa92e590a9bf77726efdf6 upstream.
+
+If a device is attached to a PM domain through genpd_dev_pm_attach_by_id(),
+genpd calls pm_runtime_enable() for the corresponding virtual device that
+it registers. While this avoids boilerplate code in drivers, there is no
+corresponding call to pm_runtime_disable() in genpd_dev_pm_detach().
+
+This means these virtual devices are typically detached from its genpd,
+while runtime PM remains enabled for them, which is not how things are
+designed to work. In worst cases it may lead to critical errors, like a
+NULL pointer dereference bug in genpd_runtime_suspend(), which was recently
+reported. For another case, we may end up keeping an unnecessary vote for a
+performance state for the device.
+
+To fix these problems, let's add this missing call to pm_runtime_disable()
+in genpd_dev_pm_detach().
+
+Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Closes: https://lore.kernel.org/all/CAMuHMdWapT40hV3c+CSBqFOW05aWcV1a6v_NiJYgoYi0i9_PDQ@mail.gmail.com/
+Fixes: 3c095f32a92b ("PM / Domains: Add support for multi PM domains per device to genpd")
+Cc: stable@vger.kernel.org
+Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pmdomain/core.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/pmdomain/core.c
++++ b/drivers/pmdomain/core.c
+@@ -3082,6 +3082,7 @@ static const struct bus_type genpd_bus_t
+ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
+ {
+ struct generic_pm_domain *pd;
++ bool is_virt_dev;
+ unsigned int i;
+ int ret = 0;
+
+@@ -3091,6 +3092,13 @@ static void genpd_dev_pm_detach(struct d
+
+ dev_dbg(dev, "removing from PM domain %s\n", pd->name);
+
++ /* Check if the device was created by genpd at attach. */
++ is_virt_dev = dev->bus == &genpd_bus_type;
++
++ /* Disable runtime PM if we enabled it at attach. */
++ if (is_virt_dev)
++ pm_runtime_disable(dev);
++
+ /* Drop the default performance state */
+ if (dev_gpd_data(dev)->default_pstate) {
+ dev_pm_genpd_set_performance_state(dev, 0);
+@@ -3116,7 +3124,7 @@ static void genpd_dev_pm_detach(struct d
+ genpd_queue_power_off_work(pd);
+
+ /* Unregister the device if it was created by genpd. */
+- if (dev->bus == &genpd_bus_type)
++ if (is_virt_dev)
+ device_unregister(dev);
+ }
+
--- /dev/null
+From 30cb24f97d44f6b81c14b85c5323de62eef1fb7f Mon Sep 17 00:00:00 2001
+From: David Carlier <devnexen@gmail.com>
+Date: Sat, 2 May 2026 15:19:45 +0100
+Subject: psp: strip variable-length PSP header in psp_dev_rcv()
+
+From: David Carlier <devnexen@gmail.com>
+
+commit 30cb24f97d44f6b81c14b85c5323de62eef1fb7f upstream.
+
+psp_dev_rcv() unconditionally removes a fixed PSP_ENCAP_HLEN, even
+when psph->hdrlen indicates that the PSP header carries optional
+fields. A frame whose PSP header advertises a non-zero VC or any
+extension would therefore be silently mis-decapsulated: option bytes
+would spill into the inner packet head and downstream parsing would
+fail on a corrupted skb.
+
+Compute the full PSP header length from psph->hdrlen, pull the
+optional bytes into the linear region, and strip the whole header
+when decapsulating. Optional fields (VC, ...) are still ignored,
+just discarded with the rest of the header instead of leaking.
+crypt_offset and the VIRT flag are intentionally not validated here
+- callers know their device's PSP implementation and can decide.
+
+Both in-tree callers gate on hardware-validated PSP, so this is a
+correctness fix rather than a reachable corruption path under
+current configurations.
+
+Fixes: 0eddb8023cee ("psp: provide decapsulation and receive helper for drivers")
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Daniel Zahka <daniel.zahka@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Link: https://patch.msgid.link/20260502141945.14484-1-devnexen@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/psp/psp_main.c | 42 +++++++++++++++++++++++++++++++-----------
+ 1 file changed, 31 insertions(+), 11 deletions(-)
+
+--- a/net/psp/psp_main.c
++++ b/net/psp/psp_main.c
+@@ -263,15 +263,16 @@ EXPORT_SYMBOL(psp_dev_encapsulate);
+
+ /* Receive handler for PSP packets.
+ *
+- * Presently it accepts only already-authenticated packets and does not
+- * support optional fields, such as virtualization cookies. The caller should
+- * ensure that skb->data is pointing to the mac header, and that skb->mac_len
+- * is set. This function does not currently adjust skb->csum (CHECKSUM_COMPLETE
+- * is not supported).
++ * Accepts only already-authenticated packets. The full PSP header is
++ * stripped according to psph->hdrlen; any optional fields it advertises
++ * (virtualization cookies, etc.) are ignored and discarded along with the
++ * rest of the header. The caller should ensure that skb->data is pointing
++ * to the mac header, and that skb->mac_len is set. This function does not
++ * currently adjust skb->csum (CHECKSUM_COMPLETE is not supported).
+ */
+ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv)
+ {
+- int l2_hlen = 0, l3_hlen, encap;
++ int l2_hlen = 0, l3_hlen, encap, psp_hlen;
+ struct psp_skb_ext *pse;
+ struct psphdr *psph;
+ struct ethhdr *eth;
+@@ -312,18 +313,36 @@ int psp_dev_rcv(struct sk_buff *skb, u16
+ if (unlikely(uh->dest != htons(PSP_DEFAULT_UDP_PORT)))
+ return -EINVAL;
+
+- pse = skb_ext_add(skb, SKB_EXT_PSP);
+- if (!pse)
++ psph = (struct psphdr *)(skb->data + l2_hlen + l3_hlen +
++ sizeof(struct udphdr));
++
++ /* Strip the full PSP header per psph->hdrlen; VC/options are pulled
++ * into the linear region only so they can be discarded with the
++ * rest of the header.
++ */
++ psp_hlen = (psph->hdrlen + 1) * 8;
++
++ if (unlikely(psp_hlen < sizeof(struct psphdr)))
++ return -EINVAL;
++
++ if (psp_hlen > sizeof(struct psphdr) &&
++ !pskb_may_pull(skb, l2_hlen + l3_hlen +
++ sizeof(struct udphdr) + psp_hlen))
+ return -EINVAL;
+
+ psph = (struct psphdr *)(skb->data + l2_hlen + l3_hlen +
+ sizeof(struct udphdr));
++
++ pse = skb_ext_add(skb, SKB_EXT_PSP);
++ if (!pse)
++ return -EINVAL;
++
+ pse->spi = psph->spi;
+ pse->dev_id = dev_id;
+ pse->generation = generation;
+ pse->version = FIELD_GET(PSPHDR_VERFL_VERSION, psph->verfl);
+
+- encap = PSP_ENCAP_HLEN;
++ encap = sizeof(struct udphdr) + psp_hlen;
+ encap += strip_icv ? PSP_TRL_SIZE : 0;
+
+ if (proto == htons(ETH_P_IP)) {
+@@ -340,8 +359,9 @@ int psp_dev_rcv(struct sk_buff *skb, u16
+ ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) - encap);
+ }
+
+- memmove(skb->data + PSP_ENCAP_HLEN, skb->data, l2_hlen + l3_hlen);
+- skb_pull(skb, PSP_ENCAP_HLEN);
++ memmove(skb->data + sizeof(struct udphdr) + psp_hlen,
++ skb->data, l2_hlen + l3_hlen);
++ skb_pull(skb, sizeof(struct udphdr) + psp_hlen);
+
+ if (strip_icv)
+ pskb_trim(skb, skb->len - PSP_TRL_SIZE);
--- /dev/null
+From 0c99acbc8b6c6dd526ae475a48ee1897b61072fb Mon Sep 17 00:00:00 2001
+From: Jason Gunthorpe <jgg@nvidia.com>
+Date: Tue, 28 Apr 2026 13:17:48 -0300
+Subject: RDMA/hns: Fix unlocked call to hns_roce_qp_remove()
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+commit 0c99acbc8b6c6dd526ae475a48ee1897b61072fb upstream.
+
+Sashiko points out that hns_roce_qp_remove() requires the caller to hold
+locks. The error flow in hns_roce_create_qp_common() doesn't hold those
+locks for the error unwind so it risks corrupting memory.
+
+Grab the same locks the other two callers use.
+
+Cc: stable@vger.kernel.org
+Fixes: e088a685eae9 ("RDMA/hns: Support rq record doorbell for the user space")
+Link: https://sashiko.dev/#/patchset/0-v2-1c49eeb88c48%2B91-rdma_udata_rep_jgg%40nvidia.com?part=9
+Link: https://patch.msgid.link/r/15-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com
+Reviewed-by: Junxian Huang <huangjunxian6@hisilicon.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/hw/hns/hns_roce_qp.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
++++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
+@@ -1178,6 +1178,7 @@ static int hns_roce_create_qp_common(str
+ struct hns_roce_ib_create_qp_resp resp = {};
+ struct ib_device *ibdev = &hr_dev->ib_dev;
+ struct hns_roce_ib_create_qp ucmd = {};
++ unsigned long flags;
+ int ret;
+
+ mutex_init(&hr_qp->mutex);
+@@ -1264,7 +1265,13 @@ static int hns_roce_create_qp_common(str
+ return 0;
+
+ err_flow_ctrl:
++ spin_lock_irqsave(&hr_dev->qp_list_lock, flags);
++ hns_roce_lock_cqs(init_attr->send_cq ? to_hr_cq(init_attr->send_cq) : NULL,
++ init_attr->recv_cq ? to_hr_cq(init_attr->recv_cq) : NULL);
+ hns_roce_qp_remove(hr_dev, hr_qp);
++ hns_roce_unlock_cqs(init_attr->send_cq ? to_hr_cq(init_attr->send_cq) : NULL,
++ init_attr->recv_cq ? to_hr_cq(init_attr->recv_cq) : NULL);
++ spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
+ err_store:
+ free_qpc(hr_dev, hr_qp);
+ err_qpc:
--- /dev/null
+From b7c958d7c1eb1cb9b2be7b5ee4129fcd66cec978 Mon Sep 17 00:00:00 2001
+From: Osama Abdelkader <osama.abdelkader@gmail.com>
+Date: Mon, 16 Mar 2026 16:16:11 +0100
+Subject: riscv: kvm: fix vector context allocation leak
+
+From: Osama Abdelkader <osama.abdelkader@gmail.com>
+
+commit b7c958d7c1eb1cb9b2be7b5ee4129fcd66cec978 upstream.
+
+When the second kzalloc (host_context.vector.datap) fails in
+kvm_riscv_vcpu_alloc_vector_context, the first allocation
+(guest_context.vector.datap) is leaked. Free it before returning.
+
+Fixes: 0f4b82579716 ("riscv: KVM: Add vector lazy save/restore support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
+Reviewed-by: Andy Chiu <andybnac@gmail.com>
+Link: https://lore.kernel.org/r/20260316151612.13305-1-osama.abdelkader@gmail.com
+Signed-off-by: Anup Patel <anup@brainfault.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/riscv/kvm/vcpu_vector.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/riscv/kvm/vcpu_vector.c
++++ b/arch/riscv/kvm/vcpu_vector.c
+@@ -80,8 +80,11 @@ int kvm_riscv_vcpu_alloc_vector_context(
+ return -ENOMEM;
+
+ vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL);
+- if (!vcpu->arch.host_context.vector.datap)
++ if (!vcpu->arch.host_context.vector.datap) {
++ kfree(vcpu->arch.guest_context.vector.datap);
++ vcpu->arch.guest_context.vector.datap = NULL;
+ return -ENOMEM;
++ }
+
+ return 0;
+ }
--- /dev/null
+From c366a7b5ed7564e41345c380285bd3f6cb98971b Mon Sep 17 00:00:00 2001
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Date: Fri, 17 Apr 2026 15:35:30 +0800
+Subject: s390/debug: Reject zero-length input before trimming a newline
+
+From: Pengpeng Hou <pengpeng@iscas.ac.cn>
+
+commit c366a7b5ed7564e41345c380285bd3f6cb98971b upstream.
+
+debug_get_user_string() duplicates the userspace buffer with
+memdup_user_nul() and then unconditionally looks at buffer[user_len - 1]
+to strip a trailing newline.
+
+A zero-length write reaches this helper unchanged, so the newline trim
+reads before the start of the allocated buffer.
+
+Reject empty writes before accessing the last input byte.
+
+Fixes: 66a464dbc8e0 ("[PATCH] s390: debug feature changes")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
+Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
+Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
+Tested-by: Vasily Gorbik <gor@linux.ibm.com>
+Link: https://lore.kernel.org/r/20260417073530.96002-1-pengpeng@iscas.ac.cn
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kernel/debug.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1414,6 +1414,9 @@ static inline char *debug_get_user_strin
+ {
+ char *buffer;
+
++ if (!user_len)
++ return ERR_PTR(-EINVAL);
++
+ buffer = memdup_user_nul(user_buf, user_len);
+ if (IS_ERR(buffer))
+ return buffer;
--- /dev/null
+From e14622a7584f9608927c59a7d6ae4a0999dc545e Mon Sep 17 00:00:00 2001
+From: Vasily Gorbik <gor@linux.ibm.com>
+Date: Fri, 17 Apr 2026 14:33:43 +0200
+Subject: s390/debug: Reject zero-length input in debug_input_flush_fn()
+
+From: Vasily Gorbik <gor@linux.ibm.com>
+
+commit e14622a7584f9608927c59a7d6ae4a0999dc545e upstream.
+
+debug_input_flush_fn() always copies one byte from the userspace buffer
+with copy_from_user() regardless of the supplied write length. A
+zero-length write therefore reads one byte beyond the caller's buffer.
+If the stale byte happens to be '-' or a digit the debug log is
+silently flushed. With an unmapped buffer the call returns -EFAULT.
+
+Reject zero-length writes before copying from userspace.
+
+Cc: stable@vger.kernel.org # v5.10+
+Acked-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kernel/debug.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/s390/kernel/debug.c
++++ b/arch/s390/kernel/debug.c
+@@ -1584,6 +1584,11 @@ static int debug_input_flush_fn(debug_in
+ char input_buf[1];
+ int rc = user_len;
+
++ if (!user_len) {
++ rc = -EINVAL;
++ goto out;
++ }
++
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0) {
--- /dev/null
+From 04631f55afc543d5431a2bdee7f6cc0f2c0debe7 Mon Sep 17 00:00:00 2001
+From: Ranjan Kumar <ranjan.kumar@broadcom.com>
+Date: Tue, 14 Apr 2026 16:38:11 +0530
+Subject: scsi: mpt3sas: Limit NVMe request size to 2 MiB
+
+From: Ranjan Kumar <ranjan.kumar@broadcom.com>
+
+commit 04631f55afc543d5431a2bdee7f6cc0f2c0debe7 upstream.
+
+The HBA firmware reports NVMe MDTS values based on the underlying drive
+capability. However, because the driver allocates a fixed 4K buffer for
+the PRP list, accommodating at most 512 entries, the driver supports a
+maximum I/O transfer size of 2 MiB.
+
+Limit max_hw_sectors to the smaller of the reported MDTS and the 2 MiB
+driver limit to prevent issuing oversized I/O that may lead to a kernel
+oops.
+
+Cc: stable@vger.kernel.org
+Fixes: 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP")
+Reported-by: Mira Limbeck <m.limbeck@proxmox.com>
+Closes: https://lore.kernel.org/r/291f78bf-4b4a-40dd-867d-053b36c564b3@proxmox.com
+Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9b8b84879d4a
+Suggested-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
+Tested-by: Mira Limbeck <m.limbeck@proxmox.com>
+Link: https://patch.msgid.link/20260414110811.85156-1-ranjan.kumar@broadcom.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/mpt3sas/mpt3sas_scsih.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
++++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+@@ -2738,8 +2738,20 @@ scsih_sdev_configure(struct scsi_device
+ pcie_device->enclosure_level,
+ pcie_device->connector_name);
+
++ /*
++ * The HBA firmware passes the NVMe drive's MDTS
++ * (Maximum Data Transfer Size) up to the driver. However,
++ * the driver hardcodes a 4K buffer size for the PRP list,
++ * accommodating at most 512 entries. This strictly limits
++ * the maximum supported NVMe I/O transfer to 2 MiB.
++ *
++ * Cap max_hw_sectors to the smaller of the drive's reported
++ * MDTS or the 2 MiB driver limit to prevent kernel oopses.
++ */
++ lim->max_hw_sectors = SZ_2M >> SECTOR_SHIFT;
+ if (pcie_device->nvme_mdts)
+- lim->max_hw_sectors = pcie_device->nvme_mdts / 512;
++ lim->max_hw_sectors = min(lim->max_hw_sectors,
++ pcie_device->nvme_mdts >> SECTOR_SHIFT);
+
+ pcie_device_put(pcie_device);
+ spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
clk-imx-imx8-acm-fix-flags-for-acm-clocks.patch
clk-microchip-mpfs-ccc-fix-out-of-bounds-access-during-output-registration.patch
cpuidle-powerpc-avoid-double-clear-when-breaking-snooze.patch
+asoc-amd-yc-add-hp-omen-gaming-laptop-16-ap0xxx-product-line-in-quirk-table.patch
+asoc-es8389-convert-to-devm_clk_get_optional-to-get-clock.patch
+asoc-fsl_easrc-fix-comment-typo.patch
+asoc-intel-bytcr_wm5102-fix-mclk-leak-on-platform_clock_control-error.patch
+asoc-qcom-q6apm-dai-reset-queue-ptr-on-trigger-stop.patch
+asoc-qcom-q6apm-lpass-dai-fix-multiple-graph-opens.patch
+asoc-qcom-q6apm-remove-child-devices-when-apm-is-removed.patch
+btrfs-do-not-mark-inode-incompressible-after-inline-attempt-fails.patch
+btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-which-can-lead-to-info-leak.patch
+btrfs-fix-double-free-in-create_space_info-error-path.patch
+btrfs-fix-double-free-in-create_space_info_sub_group-error-path.patch
+btrfs-fix-missing-last_unlink_trans-update-when-removing-a-directory.patch
+dm-thin-fix-metadata-refcount-underflow.patch
+dm-don-t-report-warning-when-doing-deferred-remove.patch
+dm-fix-a-buffer-overflow-in-ioctl-processing.patch
+eventfs-hold-eventfs_mutex-and-srcu-when-remount-walks-events.patch
+dm-verity-fec-correctly-reject-too-small-fec-devices.patch
+dm-verity-fec-correctly-reject-too-small-hash-devices.patch
+dm-verity-fec-fix-corrected-block-count-stat.patch
+dm-verity-fec-fix-reading-parity-bytes-split-across-blocks-take-3.patch
+dm-verity-fec-fix-the-size-of-dm_verity_fec_io-erasures.patch
+isofs-validate-rock-ridge-ce-continuation-extent-against-volume-size.patch
+isofs-validate-block-number-from-nfs-file-handle-in-isofs_export_iget.patch
+iommufd-fix-return-value-of-iommufd_fault_fops_write.patch
+iommu-vt-d-block-pasid-attachment-to-nested-domain-with-dirty-tracking.patch
+iommu-arm-smmu-v3-add-a-missing-dma_wmb-for-hitless-ste-update.patch
+lib-crypto-mpi-fix-integer-underflow-in-mpi_read_raw_from_sgl.patch
+lib-crc-tests-make-crc_kunit-test-only-the-enabled-crc-variants.patch
+lib-scatterlist-fix-length-calculations-in-extract_kvec_to_sg.patch
+lib-scatterlist-fix-temp-buffer-in-extract_user_to_sg.patch
+libceph-fix-slab-out-of-bounds-access-in-auth-message-processing.patch
+md-raid10-fix-divide-by-zero-in-setup_geo-with-zero-far_copies.patch
+nvme-apple-drop-invalid-put-of-admin-queue-reference-count.patch
+nvmet-tcp-fix-race-between-icreq-handling-and-queue-teardown.patch
+nvmet-avoid-recursive-nvmet-wq-flush-in-nvmet_ctrl_free.patch
+openvswitch-vport-fix-self-deadlock-on-release-of-tunnel-ports.patch
+pmdomain-core-fix-detach-procedure-for-virtual-devices-in-genpd.patch
+psp-strip-variable-length-psp-header-in-psp_dev_rcv.patch
+rdma-hns-fix-unlocked-call-to-hns_roce_qp_remove.patch
+riscv-kvm-fix-vector-context-allocation-leak.patch
+s390-debug-reject-zero-length-input-in-debug_input_flush_fn.patch
+s390-debug-reject-zero-length-input-before-trimming-a-newline.patch
+scsi-mpt3sas-limit-nvme-request-size-to-2-mib.patch
+smb-client-fix-out-of-bounds-read-in-smb2_compound_op.patch
+smb-client-fix-out-of-bounds-read-in-symlink_data.patch
+smb-client-use-kzalloc-to-zero-initialize-security-descriptor-buffer.patch
+smb-client-validate-dacloffset-before-building-dacl-pointers.patch
+kvm-x86-check-for-nept-nnpt-in-slow-flush-hypercalls.patch
+kvm-x86-do-irr-scan-in-__kvm_apic_update_irr-even-if-pir-is-empty.patch
+mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
+mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
+mm-damon-stat-detect-and-use-fresh-enabled-value.patch
+mm-damon-sysfs-schemes-protect-memcg_path-kfree-with-damon_sysfs_lock.patch
+mm-damon-sysfs-schemes-protect-path-kfree-with-damon_sysfs_lock.patch
+pci-update-saved_config_space-upon-resource-assignment.patch
--- /dev/null
+From 8d09328dfda089675e4c049f3f256064a1d1996b Mon Sep 17 00:00:00 2001
+From: Zisen Ye <zisenye@stu.xidian.edu.cn>
+Date: Wed, 6 May 2026 11:49:08 +0800
+Subject: smb/client: fix out-of-bounds read in smb2_compound_op()
+
+From: Zisen Ye <zisenye@stu.xidian.edu.cn>
+
+commit 8d09328dfda089675e4c049f3f256064a1d1996b upstream.
+
+If a server sends a truncated response but a large OutputBufferLength, and
+terminates the EA list early, check_wsl_eas() returns success without
+validating that the entire OutputBufferLength fits within iov_len.
+
+Then smb2_compound_op() does:
+ memcpy(idata->wsl.eas, data[0], size[0]);
+
+Where size[0] is OutputBufferLength. If iov_len is smaller than size[0],
+memcpy can read beyond the end of the rsp_iov allocation and leak adjacent
+kernel heap memory.
+
+Link: https://lore.kernel.org/linux-cifs/d998240c-aca9-420d-9dbd-f5ba24af19e0@chenxiaosong.com/
+Fixes: ea41367b2a60 ("smb: client: introduce SMB2_OP_QUERY_WSL_EA")
+Cc: stable@vger.kernel.org
+Signed-off-by: Zisen Ye <zisenye@stu.xidian.edu.cn>
+Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/smb2inode.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/fs/smb/client/smb2inode.c
++++ b/fs/smb/client/smb2inode.c
+@@ -111,7 +111,7 @@ static int check_wsl_eas(struct kvec *rs
+ u32 outlen, next;
+ u16 vlen;
+ u8 nlen;
+- u8 *end;
++ u8 *ea_end, *iov_end;
+
+ outlen = le32_to_cpu(rsp->OutputBufferLength);
+ if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
+@@ -120,15 +120,19 @@ static int check_wsl_eas(struct kvec *rs
+
+ ea = (void *)((u8 *)rsp_iov->iov_base +
+ le16_to_cpu(rsp->OutputBufferOffset));
+- end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
++ ea_end = (u8 *)ea + outlen;
++ iov_end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
++ if (ea_end > iov_end)
++ return -EINVAL;
++
+ for (;;) {
+- if ((u8 *)ea > end - sizeof(*ea))
++ if ((u8 *)ea > ea_end - sizeof(*ea))
+ return -EINVAL;
+
+ nlen = ea->ea_name_length;
+ vlen = le16_to_cpu(ea->ea_value_length);
+ if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
+- (u8 *)ea->ea_data + nlen + 1 + vlen > end)
++ (u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
+ return -EINVAL;
+
+ switch (vlen) {
--- /dev/null
+From d62b8d236fab503c6fec1d3e9a38bea71feaca20 Mon Sep 17 00:00:00 2001
+From: Zisen Ye <zisenye@stu.xidian.edu.cn>
+Date: Sat, 2 May 2026 18:48:36 +0800
+Subject: smb/client: fix out-of-bounds read in symlink_data()
+
+From: Zisen Ye <zisenye@stu.xidian.edu.cn>
+
+commit d62b8d236fab503c6fec1d3e9a38bea71feaca20 upstream.
+
+Since smb2_check_message() returns success without length validation for
+the symlink error response, in symlink_data() it is possible for
+iov->iov_len to be smaller than sizeof(struct smb2_err_rsp). If the buffer
+only contains the base SMB2 header (64 bytes), accessing
+err->ErrorContextCount (at offset 66) or err->ByteCount later in
+symlink_data() will cause an out-of-bounds read.
+
+Link: https://lore.kernel.org/linux-cifs/297d8d9b-adf7-42fd-a1c2-5b1f230032bc@chenxiaosong.com/
+Fixes: 76894f3e2f71 ("cifs: improve symlink handling for smb2+")
+Cc: Stable@vger.kernel.org
+Signed-off-by: Zisen Ye <zisenye@stu.xidian.edu.cn>
+Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/smb2misc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/smb/client/smb2misc.c
++++ b/fs/smb/client/smb2misc.c
+@@ -241,7 +241,8 @@ smb2_check_message(char *buf, unsigned i
+ if (len != calc_len) {
+ /* create failed on symlink */
+ if (command == SMB2_CREATE_HE &&
+- shdr->Status == STATUS_STOPPED_ON_SYMLINK)
++ shdr->Status == STATUS_STOPPED_ON_SYMLINK &&
++ len > calc_len)
+ return 0;
+ /* Windows 7 server returns 24 bytes more */
+ if (calc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
--- /dev/null
+From 5e489c6c47a2ac15edbaca153b9348e42c1eacab Mon Sep 17 00:00:00 2001
+From: Bjoern Doebel <doebel@amazon.de>
+Date: Thu, 30 Apr 2026 08:57:17 +0000
+Subject: smb: client: use kzalloc to zero-initialize security descriptor buffer
+
+From: Bjoern Doebel <doebel@amazon.de>
+
+commit 5e489c6c47a2ac15edbaca153b9348e42c1eacab upstream.
+
+Commit 62e7dd0a39c2d ("smb: common: change the data type of num_aces
+to le16") split struct smb_acl's __le32 num_aces field into __le16
+num_aces and __le16 reserved. The reserved field corresponds to Sbz2
+in the MS-DTYP ACL wire format, which must be zero [1].
+
+When building an ACL descriptor in build_sec_desc(), we are using a
+kmalloc()'ed descriptor buffer and writing the fields explicitly using
+le16() writes now. This never writes to the 2 byte reserved field,
+leaving it as uninitialized heap data.
+
+When the reserved field happens to contain non-zero slab garbage,
+Samba rejects the security descriptor with "ndr_pull_security_descriptor
+failed: Range Error", causing chmod to fail with EINVAL.
+
+Change kmalloc() to kzalloc() to ensure the entire buffer is
+zero-initialized.
+
+Fixes: 62e7dd0a39c2d ("smb: common: change the data type of num_aces to le16")
+Cc: stable@vger.kernel.org
+
+Signed-off-by: Bjoern Doebel <doebel@amazon.de>
+Assisted-by: Kiro:claude-opus-4.6
+[1] https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/20233ed8-a6c6-4097-aafa-dd545ed24428
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cifsacl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/smb/client/cifsacl.c
++++ b/fs/smb/client/cifsacl.c
+@@ -1732,7 +1732,7 @@ id_mode_to_cifs_acl(struct inode *inode,
+ * descriptor parameters, and security descriptor itself
+ */
+ nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN);
+- pnntsd = kmalloc(nsecdesclen, GFP_KERNEL);
++ pnntsd = kzalloc(nsecdesclen, GFP_KERNEL);
+ if (!pnntsd) {
+ kfree(pntsd);
+ cifs_put_tlink(tlink);
--- /dev/null
+From f98b48151cc502ada59d9778f0112d21f2586ca3 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Mon, 20 Apr 2026 10:47:47 -0400
+Subject: smb: client: validate dacloffset before building DACL pointers
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit f98b48151cc502ada59d9778f0112d21f2586ca3 upstream.
+
+parse_sec_desc(), build_sec_desc(), and the chown path in
+id_mode_to_cifs_acl() all add the server-supplied dacloffset to pntsd
+before proving a DACL header fits inside the returned security
+descriptor.
+
+On 32-bit builds a malicious server can return dacloffset near
+U32_MAX, wrap the derived DACL pointer below end_of_acl, and then slip
+past the later pointer-based bounds checks. build_sec_desc() and
+id_mode_to_cifs_acl() can then dereference DACL fields from the wrapped
+pointer in the chmod/chown rewrite paths.
+
+Validate dacloffset numerically before building any DACL pointer and
+reuse the same helper at the three DACL entry points.
+
+Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/client/cifsacl.c | 35 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 32 insertions(+), 3 deletions(-)
+
+--- a/fs/smb/client/cifsacl.c
++++ b/fs/smb/client/cifsacl.c
+@@ -1264,6 +1264,17 @@ static int parse_sid(struct smb_sid *psi
+ return 0;
+ }
+
++static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
++{
++ if (acl_len < sizeof(struct smb_acl))
++ return false;
++
++ if (dacloffset < sizeof(struct smb_ntsd))
++ return false;
++
++ return dacloffset <= acl_len - sizeof(struct smb_acl);
++}
++
+
+ /* Convert CIFS ACL to POSIX form */
+ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
+@@ -1284,7 +1295,6 @@ static int parse_sec_desc(struct cifs_sb
+ group_sid_ptr = (struct smb_sid *)((char *)pntsd +
+ le32_to_cpu(pntsd->gsidoffset));
+ dacloffset = le32_to_cpu(pntsd->dacloffset);
+- dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
+ pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
+ le32_to_cpu(pntsd->gsidoffset),
+@@ -1315,11 +1325,18 @@ static int parse_sec_desc(struct cifs_sb
+ return rc;
+ }
+
+- if (dacloffset)
++ if (dacloffset) {
++ if (!dacl_offset_valid(acl_len, dacloffset)) {
++ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
++ return -EINVAL;
++ }
++
++ dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
+ group_sid_ptr, fattr, get_mode_from_special_sid);
+- else
++ } else {
+ cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
++ }
+
+ return rc;
+ }
+@@ -1342,6 +1359,11 @@ static int build_sec_desc(struct smb_nts
+
+ dacloffset = le32_to_cpu(pntsd->dacloffset);
+ if (dacloffset) {
++ if (!dacl_offset_valid(secdesclen, dacloffset)) {
++ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
++ return -EINVAL;
++ }
++
+ dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ rc = validate_dacl(dacl_ptr, end_of_acl);
+ if (rc)
+@@ -1710,6 +1732,12 @@ id_mode_to_cifs_acl(struct inode *inode,
+ nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
+ dacloffset = le32_to_cpu(pntsd->dacloffset);
+ if (dacloffset) {
++ if (!dacl_offset_valid(secdesclen, dacloffset)) {
++ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
++ rc = -EINVAL;
++ goto id_mode_to_cifs_acl_exit;
++ }
++
+ dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
+ rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
+ if (rc) {
+@@ -1752,6 +1780,7 @@ id_mode_to_cifs_acl(struct inode *inode,
+ rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
+ cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
+ }
++id_mode_to_cifs_acl_exit:
+ cifs_put_tlink(tlink);
+
+ kfree(pnntsd);