--- /dev/null
+From stable+bounces-245017-greg=kroah.com@vger.kernel.org Sun May 10 18:46:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 09:15:57 -0400
+Subject: ALSA: aloop: Fix peer runtime UAF during format-change stop
+To: stable@vger.kernel.org
+Cc: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>, syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com, "Takashi Iwai" <tiwai@suse.com>, "Takashi Iwai" <tiwai@suse.de>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260510131557.4115089-1-sashal@kernel.org>
+
+From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+
+[ Upstream commit e5c33cdc6f402eab8abd36ecf436b22c9d3a8aff ]
+
+loopback_check_format() may stop the capture side when playback starts
+with parameters that no longer match a running capture stream. Commit
+826af7fa62e3 ("ALSA: aloop: Fix racy access at PCM trigger") moved
+the peer lookup under cable->lock, but the actual snd_pcm_stop() still
+runs after dropping that lock.
+
+A concurrent close can clear the capture entry from cable->streams[] and
+detach or free its runtime while the playback trigger path still holds a
+stale peer substream pointer.
+
+Keep a per-cable count of in-flight peer stops before dropping
+cable->lock, and make free_cable() wait for those stops before
+detaching the runtime. This preserves the existing behavior while
+making the peer runtime lifetime explicit.
+
+Reported-by: syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=8fa95c41eafbc9d2ff6f
+Fixes: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM loopback")
+Cc: stable@vger.kernel.org
+Suggested-by: Takashi Iwai <tiwai@suse.com>
+Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+Link: https://patch.msgid.link/20260424-alsa-aloop-peer-stop-uaf-v2-1-94e68101db8a@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+[ collapsed inc/snd_pcm_stop/dec into the existing inline call site and used spin_lock_irq/unlock_irq instead of scoped_guard ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/drivers/aloop.c | 40 +++++++++++++++++++++++++++-------------
+ 1 file changed, 27 insertions(+), 13 deletions(-)
+
+--- a/sound/drivers/aloop.c
++++ b/sound/drivers/aloop.c
+@@ -98,6 +98,9 @@ struct loopback_ops {
+ struct loopback_cable {
+ spinlock_t lock;
+ struct loopback_pcm *streams[2];
++ /* in-flight peer stops running outside cable->lock */
++ atomic_t stop_count;
++ wait_queue_head_t stop_wait;
+ struct snd_pcm_hardware hw;
+ /* flags */
+ unsigned int valid;
+@@ -341,8 +344,12 @@ static int loopback_check_format(struct
+ if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ return -EIO;
+ } else {
++ /* close must not free the peer runtime below */
++ atomic_inc(&cable->stop_count);
+ snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+ substream, SNDRV_PCM_STATE_DRAINING);
++ if (atomic_dec_and_test(&cable->stop_count))
++ wake_up(&cable->stop_wait);
+ __notify:
+ runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+ substream->runtime;
+@@ -994,24 +1001,29 @@ static void free_cable(struct snd_pcm_su
+ struct loopback *loopback = substream->private_data;
+ int dev = get_cable_index(substream);
+ struct loopback_cable *cable;
++ struct loopback_pcm *dpcm;
++ bool other_alive;
+
+ cable = loopback->cables[substream->number][dev];
+ if (!cable)
+ return;
+- if (cable->streams[!substream->stream]) {
+- /* other stream is still alive */
+- spin_lock_irq(&cable->lock);
+- cable->streams[substream->stream] = NULL;
+- spin_unlock_irq(&cable->lock);
+- } else {
+- struct loopback_pcm *dpcm = substream->runtime->private_data;
+
+- if (cable->ops && cable->ops->close_cable && dpcm)
+- cable->ops->close_cable(dpcm);
+- /* free the cable */
+- loopback->cables[substream->number][dev] = NULL;
+- kfree(cable);
+- }
++ spin_lock_irq(&cable->lock);
++ cable->streams[substream->stream] = NULL;
++ other_alive = cable->streams[!substream->stream] != NULL;
++ spin_unlock_irq(&cable->lock);
++
++ /* Pair with the stop_count increment in loopback_check_format(). */
++ wait_event(cable->stop_wait, !atomic_read(&cable->stop_count));
++ if (other_alive)
++ return;
++
++ dpcm = substream->runtime->private_data;
++ if (cable->ops && cable->ops->close_cable && dpcm)
++ cable->ops->close_cable(dpcm);
++ /* free the cable */
++ loopback->cables[substream->number][dev] = NULL;
++ kfree(cable);
+ }
+
+ static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
+@@ -1206,6 +1218,8 @@ static int loopback_open(struct snd_pcm_
+ goto unlock;
+ }
+ spin_lock_init(&cable->lock);
++ atomic_set(&cable->stop_count, 0);
++ init_waitqueue_head(&cable->stop_wait);
+ cable->hw = loopback_pcm_hardware;
+ if (loopback->timer_source)
+ cable->ops = &loopback_snd_timer_ops;
--- /dev/null
+From stable+bounces-242473-greg=kroah.com@vger.kernel.org Fri May 1 22:47:13 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 13:13:18 -0400
+Subject: ALSA: aoa: i2sbus: clear stale prepared state
+To: stable@vger.kernel.org
+Cc: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>, "kernel test robot" <lkp@intel.com>, "Takashi Iwai" <tiwai@suse.de>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260501171318.3681281-2-sashal@kernel.org>
+
+From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+
+[ Upstream commit 5ed060d5491597490fb53ec69da3edc4b1e8c165 ]
+
+The i2sbus PCM code uses pi->active to constrain the sibling stream to
+an already prepared duplex format and rate in i2sbus_pcm_open().
+
+That state is set from i2sbus_pcm_prepare(), but the current code only
+clears it on close. As a result, the sibling stream can inherit stale
+constraints after the prepared state has been torn down.
+
+Clear pi->active when hw_params() or hw_free() tears down the prepared
+state, and set it again only after prepare succeeds.
+
+Replace the stale FIXME in the duplex constraint comment with a description
+of the current driver behavior: i2sbus still programs a single shared
+transport configuration for both directions, so mixed formats are not
+supported in duplex mode.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202604010125.AvkWBYKI-lkp@intel.com/
+Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa")
+Cc: stable@vger.kernel.org
+Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
+Link: https://patch.msgid.link/20260331-aoa-i2sbus-clear-stale-active-v2-1-3764ae2889a1@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/aoa/soundbus/i2sbus/pcm.c | 55 ++++++++++++++++++++++++++++++++--------
+ 1 file changed, 44 insertions(+), 11 deletions(-)
+
+--- a/sound/aoa/soundbus/i2sbus/pcm.c
++++ b/sound/aoa/soundbus/i2sbus/pcm.c
+@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus
+ * currently in use (if any). */
+ hw->rate_min = 5512;
+ hw->rate_max = 192000;
+- /* if the other stream is active, then we can only
+- * support what it is currently using.
+- * FIXME: I lied. This comment is wrong. We can support
+- * anything that works with the same serial format, ie.
+- * when recording 24 bit sound we can well play 16 bit
+- * sound at the same time iff using the same transfer mode.
++ /* If the other stream is already prepared, keep this stream
++ * on the same duplex format and rate.
++ *
++ * i2sbus_pcm_prepare() still programs one shared transport
++ * configuration for both directions, so mixed duplex formats
++ * are not supported here.
+ */
+ if (other->active) {
+- /* FIXME: is this guaranteed by the alsa api? */
+ hw->formats &= pcm_format_to_bits(i2sdev->format);
+- /* see above, restrict rates to the one we already have */
++ /* Restrict rates to the one already in use. */
+ hw->rate_min = i2sdev->rate;
+ hw->rate_max = i2sdev->rate;
+ }
+@@ -283,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2
+ }
+ #endif
+
++static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
++{
++ struct pcm_info *pi;
++
++ guard(mutex)(&i2sdev->lock);
++
++ get_pcm_info(i2sdev, in, &pi, NULL);
++ pi->active = 0;
++}
++
++static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params, int in)
++{
++ i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
++ return 0;
++}
++
+ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
+ {
+ struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+@@ -291,14 +307,27 @@ static inline int i2sbus_hw_free(struct
+ get_pcm_info(i2sdev, in, &pi, NULL);
+ if (pi->dbdma_ring.stopping)
+ i2sbus_wait_for_stop(i2sdev, pi);
++ i2sbus_pcm_clear_active(i2sdev, in);
+ return 0;
+ }
+
++static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ return i2sbus_hw_params(substream, params, 0);
++}
++
+ static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
+ {
+ return i2sbus_hw_free(substream, 0);
+ }
+
++static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ return i2sbus_hw_params(substream, params, 1);
++}
++
+ static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
+ {
+ return i2sbus_hw_free(substream, 1);
+@@ -335,7 +364,6 @@ static int i2sbus_pcm_prepare(struct i2s
+ return -EINVAL;
+
+ runtime = pi->substream->runtime;
+- pi->active = 1;
+ if (other->active &&
+ ((i2sdev->format != runtime->format)
+ || (i2sdev->rate != runtime->rate)))
+@@ -450,9 +478,11 @@ static int i2sbus_pcm_prepare(struct i2s
+
+ /* early exit if already programmed correctly */
+ /* not locking these is fine since we touch them only in this function */
+- if (in_le32(&i2sdev->intfregs->serial_format) == sfr
+- && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
++ if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
++ in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
++ pi->active = 1;
+ return 0;
++ }
+
+ /* let's notify the codecs about clocks going away.
+ * For now we only do mastering on the i2s cell... */
+@@ -490,6 +520,7 @@ static int i2sbus_pcm_prepare(struct i2s
+ if (cii->codec->switch_clock)
+ cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+
++ pi->active = 1;
+ return 0;
+ }
+
+@@ -746,6 +777,7 @@ static snd_pcm_uframes_t i2sbus_playback
+ static const struct snd_pcm_ops i2sbus_playback_ops = {
+ .open = i2sbus_playback_open,
+ .close = i2sbus_playback_close,
++ .hw_params = i2sbus_playback_hw_params,
+ .hw_free = i2sbus_playback_hw_free,
+ .prepare = i2sbus_playback_prepare,
+ .trigger = i2sbus_playback_trigger,
+@@ -814,6 +846,7 @@ static snd_pcm_uframes_t i2sbus_record_p
+ static const struct snd_pcm_ops i2sbus_record_ops = {
+ .open = i2sbus_record_open,
+ .close = i2sbus_record_close,
++ .hw_params = i2sbus_record_hw_params,
+ .hw_free = i2sbus_record_hw_free,
+ .prepare = i2sbus_record_prepare,
+ .trigger = i2sbus_record_trigger,
--- /dev/null
+From stable+bounces-242487-greg=kroah.com@vger.kernel.org Sat May 2 00:06:49 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 14:35:58 -0400
+Subject: ALSA: aoa: Skip devices with no codecs in i2sbus_resume()
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501183559.3910873-2-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ Upstream commit fd7df93013c5118812e63a52635dc6c3a805a1de ]
+
+In i2sbus_resume(), skip devices with an empty codec list, which avoids
+using an uninitialized 'sysclock_factor' in the 32-bit format path in
+i2sbus_pcm_prepare().
+
+In i2sbus_pcm_prepare(), replace two list_for_each_entry() loops with a
+single list_first_entry() now that the codec list is guaranteed to be
+non-empty by all callers.
+
+Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa")
+Cc: stable@vger.kernel.org
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Link: https://patch.msgid.link/20260310102921.210109-3-thorsten.blum@linux.dev
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/aoa/soundbus/i2sbus/core.c | 3 +++
+ sound/aoa/soundbus/i2sbus/pcm.c | 16 +++++-----------
+ 2 files changed, 8 insertions(+), 11 deletions(-)
+
+--- a/sound/aoa/soundbus/i2sbus/core.c
++++ b/sound/aoa/soundbus/i2sbus/core.c
+@@ -411,6 +411,9 @@ static int i2sbus_resume(struct macio_de
+ int err, ret = 0;
+
+ list_for_each_entry(i2sdev, &control->list, item) {
++ if (list_empty(&i2sdev->sound.codec_list))
++ continue;
++
+ /* reset i2s bus format etc. */
+ i2sbus_pcm_prepare_both(i2sdev);
+
+--- a/sound/aoa/soundbus/i2sbus/pcm.c
++++ b/sound/aoa/soundbus/i2sbus/pcm.c
+@@ -411,6 +411,9 @@ static int i2sbus_pcm_prepare(struct i2s
+ /* set stop command */
+ command->command = cpu_to_le16(DBDMA_STOP);
+
++ cii = list_first_entry(&i2sdev->sound.codec_list,
++ struct codec_info_item, list);
++
+ /* ok, let's set the serial format and stuff */
+ switch (runtime->format) {
+ /* 16 bit formats */
+@@ -418,13 +421,7 @@ static int i2sbus_pcm_prepare(struct i2s
+ case SNDRV_PCM_FORMAT_U16_BE:
+ /* FIXME: if we add different bus factors we need to
+ * do more here!! */
+- bi.bus_factor = 0;
+- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+- bi.bus_factor = cii->codec->bus_factor;
+- break;
+- }
+- if (!bi.bus_factor)
+- return -ENODEV;
++ bi.bus_factor = cii->codec->bus_factor;
+ input_16bit = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_BE:
+@@ -438,10 +435,7 @@ static int i2sbus_pcm_prepare(struct i2s
+ return -EINVAL;
+ }
+ /* we assume all sysclocks are the same! */
+- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+- bi.sysclock_factor = cii->codec->sysclock_factor;
+- break;
+- }
++ bi.sysclock_factor = cii->codec->sysclock_factor;
+
+ if (clock_and_divisors(bi.sysclock_factor,
+ bi.bus_factor,
--- /dev/null
+From stable+bounces-242472-greg=kroah.com@vger.kernel.org Fri May 1 22:47:11 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 13:13:17 -0400
+Subject: ALSA: aoa: Use guard() for mutex locks
+To: stable@vger.kernel.org
+Cc: Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501171318.3681281-1-sashal@kernel.org>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 1cb6ecbb372002ef9e531c5377e5f60122411e40 ]
+
+Replace the manual mutex lock/unlock pairs with guard() for code
+simplification.
+
+Only code refactoring, and no behavior change.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Link: https://patch.msgid.link/20250829151335.7342-14-tiwai@suse.de
+Stable-dep-of: 5ed060d54915 ("ALSA: aoa: i2sbus: clear stale prepared state")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/aoa/codecs/onyx.c | 104 +++++++++++-------------------------
+ sound/aoa/codecs/tas.c | 113 +++++++++++++---------------------------
+ sound/aoa/core/gpio-feature.c | 20 ++-----
+ sound/aoa/core/gpio-pmf.c | 26 +++------
+ sound/aoa/soundbus/i2sbus/pcm.c | 76 ++++++++------------------
+ 5 files changed, 112 insertions(+), 227 deletions(-)
+
+--- a/sound/aoa/codecs/onyx.c
++++ b/sound/aoa/codecs/onyx.c
+@@ -121,10 +121,9 @@ static int onyx_snd_vol_get(struct snd_k
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ s8 l, r;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+- mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
+ ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
+@@ -145,15 +144,13 @@ static int onyx_snd_vol_put(struct snd_k
+ ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)
+ return -EINVAL;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+ onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+
+ if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
+- r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
+- mutex_unlock(&onyx->mutex);
++ r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1])
+ return 0;
+- }
+
+ onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
+ ucontrol->value.integer.value[0]
+@@ -161,7 +158,6 @@ static int onyx_snd_vol_put(struct snd_k
+ onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
+ ucontrol->value.integer.value[1]
+ - VOLUME_RANGE_SHIFT);
+- mutex_unlock(&onyx->mutex);
+
+ return 1;
+ }
+@@ -197,9 +193,8 @@ static int onyx_snd_inputgain_get(struct
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 ig;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
+- mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] =
+ (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
+@@ -216,14 +211,13 @@ static int onyx_snd_inputgain_put(struct
+ if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||
+ ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)
+ return -EINVAL;
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+ n = v;
+ n &= ~ONYX_ADC_PGA_GAIN_MASK;
+ n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
+ & ONYX_ADC_PGA_GAIN_MASK;
+ onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
+- mutex_unlock(&onyx->mutex);
+
+ return n != v;
+ }
+@@ -251,9 +245,8 @@ static int onyx_snd_capture_source_get(s
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ s8 v;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+- mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
+
+@@ -264,13 +257,12 @@ static void onyx_set_capture_source(stru
+ {
+ s8 v;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+ v &= ~ONYX_ADC_INPUT_MIC;
+ if (mic)
+ v |= ONYX_ADC_INPUT_MIC;
+ onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
+- mutex_unlock(&onyx->mutex);
+ }
+
+ static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+@@ -311,9 +303,8 @@ static int onyx_snd_mute_get(struct snd_
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 c;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
+- mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
+ ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
+@@ -328,9 +319,9 @@ static int onyx_snd_mute_put(struct snd_
+ u8 v = 0, c = 0;
+ int err = -EBUSY;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ if (onyx->analog_locked)
+- goto out_unlock;
++ return -EBUSY;
+
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+ c = v;
+@@ -341,9 +332,6 @@ static int onyx_snd_mute_put(struct snd_
+ c |= ONYX_MUTE_RIGHT;
+ err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
+
+- out_unlock:
+- mutex_unlock(&onyx->mutex);
+-
+ return !err ? (v != c) : err;
+ }
+
+@@ -372,9 +360,8 @@ static int onyx_snd_single_bit_get(struc
+ u8 address = (pv >> 8) & 0xff;
+ u8 mask = pv & 0xff;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, address, &c);
+- mutex_unlock(&onyx->mutex);
+
+ ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
+
+@@ -393,11 +380,10 @@ static int onyx_snd_single_bit_put(struc
+ u8 address = (pv >> 8) & 0xff;
+ u8 mask = pv & 0xff;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ if (spdiflock && onyx->spdif_locked) {
+ /* even if alsamixer doesn't care.. */
+- err = -EBUSY;
+- goto out_unlock;
++ return -EBUSY;
+ }
+ onyx_read_register(onyx, address, &v);
+ c = v;
+@@ -406,9 +392,6 @@ static int onyx_snd_single_bit_put(struc
+ c |= mask;
+ err = onyx_write_register(onyx, address, c);
+
+- out_unlock:
+- mutex_unlock(&onyx->mutex);
+-
+ return !err ? (v != c) : err;
+ }
+
+@@ -489,7 +472,7 @@ static int onyx_spdif_get(struct snd_kco
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+ ucontrol->value.iec958.status[0] = v & 0x3e;
+
+@@ -501,7 +484,6 @@ static int onyx_spdif_get(struct snd_kco
+
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ ucontrol->value.iec958.status[4] = v & 0x0f;
+- mutex_unlock(&onyx->mutex);
+
+ return 0;
+ }
+@@ -512,7 +494,7 @@ static int onyx_spdif_put(struct snd_kco
+ struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+ u8 v;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+ v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
+@@ -527,7 +509,6 @@ static int onyx_spdif_put(struct snd_kco
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
+ onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+- mutex_unlock(&onyx->mutex);
+
+ return 1;
+ }
+@@ -672,14 +653,13 @@ static int onyx_usable(struct codec_info
+ struct onyx *onyx = cii->codec_data;
+ int spdif_enabled, analog_enabled;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+ spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
+ onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+ analog_enabled =
+ (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
+ != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
+- mutex_unlock(&onyx->mutex);
+
+ switch (ti->tag) {
+ case 0: return 1;
+@@ -695,9 +675,8 @@ static int onyx_prepare(struct codec_inf
+ {
+ u8 v;
+ struct onyx *onyx = cii->codec_data;
+- int err = -EBUSY;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+
+ #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+ if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
+@@ -706,10 +685,9 @@ static int onyx_prepare(struct codec_inf
+ if (onyx_write_register(onyx,
+ ONYX_REG_DAC_CONTROL,
+ v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
+- goto out_unlock;
++ return -EBUSY;
+ onyx->analog_locked = 1;
+- err = 0;
+- goto out_unlock;
++ return 0;
+ }
+ #endif
+ switch (substream->runtime->rate) {
+@@ -719,8 +697,7 @@ static int onyx_prepare(struct codec_inf
+ /* these rates are ok for all outputs */
+ /* FIXME: program spdif channel control bits here so that
+ * userspace doesn't have to if it only plays pcm! */
+- err = 0;
+- goto out_unlock;
++ return 0;
+ default:
+ /* got some rate that the digital output can't do,
+ * so disable and lock it */
+@@ -728,16 +705,12 @@ static int onyx_prepare(struct codec_inf
+ if (onyx_write_register(onyx,
+ ONYX_REG_DIG_INFO4,
+ v & ~ONYX_SPDIF_ENABLE))
+- goto out_unlock;
++ return -EBUSY;
+ onyx->spdif_locked = 1;
+- err = 0;
+- goto out_unlock;
++ return 0;
+ }
+
+- out_unlock:
+- mutex_unlock(&onyx->mutex);
+-
+- return err;
++ return -EBUSY;
+ }
+
+ static int onyx_open(struct codec_info_item *cii,
+@@ -745,9 +718,8 @@ static int onyx_open(struct codec_info_i
+ {
+ struct onyx *onyx = cii->codec_data;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx->open_count++;
+- mutex_unlock(&onyx->mutex);
+
+ return 0;
+ }
+@@ -757,11 +729,10 @@ static int onyx_close(struct codec_info_
+ {
+ struct onyx *onyx = cii->codec_data;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ onyx->open_count--;
+ if (!onyx->open_count)
+ onyx->spdif_locked = onyx->analog_locked = 0;
+- mutex_unlock(&onyx->mutex);
+
+ return 0;
+ }
+@@ -771,7 +742,7 @@ static int onyx_switch_clock(struct code
+ {
+ struct onyx *onyx = cii->codec_data;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ /* this *MUST* be more elaborate later... */
+ switch (what) {
+ case CLOCK_SWITCH_PREPARE_SLAVE:
+@@ -783,7 +754,6 @@ static int onyx_switch_clock(struct code
+ default: /* silence warning */
+ break;
+ }
+- mutex_unlock(&onyx->mutex);
+
+ return 0;
+ }
+@@ -794,27 +764,21 @@ static int onyx_suspend(struct codec_inf
+ {
+ struct onyx *onyx = cii->codec_data;
+ u8 v;
+- int err = -ENXIO;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+- goto out_unlock;
++ return -ENXIO;
+ onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
+ /* Apple does a sleep here but the datasheet says to do it on resume */
+- err = 0;
+- out_unlock:
+- mutex_unlock(&onyx->mutex);
+-
+- return err;
++ return 0;
+ }
+
+ static int onyx_resume(struct codec_info_item *cii)
+ {
+ struct onyx *onyx = cii->codec_data;
+ u8 v;
+- int err = -ENXIO;
+
+- mutex_lock(&onyx->mutex);
++ guard(mutex)(&onyx->mutex);
+
+ /* reset codec */
+ onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+@@ -826,17 +790,13 @@ static int onyx_resume(struct codec_info
+
+ /* take codec out of suspend (if it still is after reset) */
+ if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+- goto out_unlock;
++ return -ENXIO;
+ onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
+ /* FIXME: should divide by sample rate, but 8k is the lowest we go */
+ msleep(2205000/8000);
+ /* reset all values */
+ onyx_register_init(onyx);
+- err = 0;
+- out_unlock:
+- mutex_unlock(&onyx->mutex);
+-
+- return err;
++ return 0;
+ }
+
+ #endif /* CONFIG_PM */
+--- a/sound/aoa/codecs/tas.c
++++ b/sound/aoa/codecs/tas.c
+@@ -235,10 +235,9 @@ static int tas_snd_vol_get(struct snd_kc
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->cached_volume_l;
+ ucontrol->value.integer.value[1] = tas->cached_volume_r;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -254,18 +253,15 @@ static int tas_snd_vol_put(struct snd_kc
+ ucontrol->value.integer.value[1] > 177)
+ return -EINVAL;
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ if (tas->cached_volume_l == ucontrol->value.integer.value[0]
+- && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
+- mutex_unlock(&tas->mtx);
++ && tas->cached_volume_r == ucontrol->value.integer.value[1])
+ return 0;
+- }
+
+ tas->cached_volume_l = ucontrol->value.integer.value[0];
+ tas->cached_volume_r = ucontrol->value.integer.value[1];
+ if (tas->hw_enabled)
+ tas_set_volume(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -285,10 +281,9 @@ static int tas_snd_mute_get(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = !tas->mute_l;
+ ucontrol->value.integer.value[1] = !tas->mute_r;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -297,18 +292,15 @@ static int tas_snd_mute_put(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ if (tas->mute_l == !ucontrol->value.integer.value[0]
+- && tas->mute_r == !ucontrol->value.integer.value[1]) {
+- mutex_unlock(&tas->mtx);
++ && tas->mute_r == !ucontrol->value.integer.value[1])
+ return 0;
+- }
+
+ tas->mute_l = !ucontrol->value.integer.value[0];
+ tas->mute_r = !ucontrol->value.integer.value[1];
+ if (tas->hw_enabled)
+ tas_set_volume(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -337,10 +329,9 @@ static int tas_snd_mixer_get(struct snd_
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->mixer_l[idx];
+ ucontrol->value.integer.value[1] = tas->mixer_r[idx];
+- mutex_unlock(&tas->mtx);
+
+ return 0;
+ }
+@@ -351,19 +342,16 @@ static int tas_snd_mixer_put(struct snd_
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
+- && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
+- mutex_unlock(&tas->mtx);
++ && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
+ return 0;
+- }
+
+ tas->mixer_l[idx] = ucontrol->value.integer.value[0];
+ tas->mixer_r[idx] = ucontrol->value.integer.value[1];
+
+ if (tas->hw_enabled)
+ tas_set_mixer(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -396,9 +384,8 @@ static int tas_snd_drc_range_get(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->drc_range;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -411,16 +398,13 @@ static int tas_snd_drc_range_put(struct
+ ucontrol->value.integer.value[0] > TAS3004_DRC_MAX)
+ return -EINVAL;
+
+- mutex_lock(&tas->mtx);
+- if (tas->drc_range == ucontrol->value.integer.value[0]) {
+- mutex_unlock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
++ if (tas->drc_range == ucontrol->value.integer.value[0])
+ return 0;
+- }
+
+ tas->drc_range = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas3004_set_drc(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -440,9 +424,8 @@ static int tas_snd_drc_switch_get(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->drc_enabled;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -451,16 +434,13 @@ static int tas_snd_drc_switch_put(struct
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
+- if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
+- mutex_unlock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
++ if (tas->drc_enabled == ucontrol->value.integer.value[0])
+ return 0;
+- }
+
+ tas->drc_enabled = !!ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas3004_set_drc(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -486,9 +466,8 @@ static int tas_snd_capture_source_get(st
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -500,7 +479,7 @@ static int tas_snd_capture_source_put(st
+
+ if (ucontrol->value.enumerated.item[0] > 1)
+ return -EINVAL;
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ oldacr = tas->acr;
+
+ /*
+@@ -512,13 +491,10 @@ static int tas_snd_capture_source_put(st
+ if (ucontrol->value.enumerated.item[0])
+ tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL |
+ TAS_ACR_B_MON_SEL_RIGHT;
+- if (oldacr == tas->acr) {
+- mutex_unlock(&tas->mtx);
++ if (oldacr == tas->acr)
+ return 0;
+- }
+ if (tas->hw_enabled)
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -557,9 +533,8 @@ static int tas_snd_treble_get(struct snd
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->treble;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -571,16 +546,13 @@ static int tas_snd_treble_put(struct snd
+ if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN ||
+ ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX)
+ return -EINVAL;
+- mutex_lock(&tas->mtx);
+- if (tas->treble == ucontrol->value.integer.value[0]) {
+- mutex_unlock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
++ if (tas->treble == ucontrol->value.integer.value[0])
+ return 0;
+- }
+
+ tas->treble = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas_set_treble(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -608,9 +580,8 @@ static int tas_snd_bass_get(struct snd_k
+ {
+ struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ ucontrol->value.integer.value[0] = tas->bass;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -622,16 +593,13 @@ static int tas_snd_bass_put(struct snd_k
+ if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN ||
+ ucontrol->value.integer.value[0] > TAS3004_BASS_MAX)
+ return -EINVAL;
+- mutex_lock(&tas->mtx);
+- if (tas->bass == ucontrol->value.integer.value[0]) {
+- mutex_unlock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
++ if (tas->bass == ucontrol->value.integer.value[0])
+ return 0;
+- }
+
+ tas->bass = ucontrol->value.integer.value[0];
+ if (tas->hw_enabled)
+ tas_set_bass(tas);
+- mutex_unlock(&tas->mtx);
+ return 1;
+ }
+
+@@ -722,13 +690,13 @@ static int tas_switch_clock(struct codec
+ break;
+ case CLOCK_SWITCH_SLAVE:
+ /* Clocks are back, re-init the codec */
+- mutex_lock(&tas->mtx);
+- tas_reset_init(tas);
+- tas_set_volume(tas);
+- tas_set_mixer(tas);
+- tas->hw_enabled = 1;
+- tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+- mutex_unlock(&tas->mtx);
++ scoped_guard(mutex, &tas->mtx) {
++ tas_reset_init(tas);
++ tas_set_volume(tas);
++ tas_set_mixer(tas);
++ tas->hw_enabled = 1;
++ tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
++ }
+ break;
+ default:
+ /* doesn't happen as of now */
+@@ -743,23 +711,21 @@ static int tas_switch_clock(struct codec
+ * our i2c device is suspended, and then take note of that! */
+ static int tas_suspend(struct tas *tas)
+ {
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ tas->hw_enabled = 0;
+ tas->acr |= TAS_ACR_ANALOG_PDOWN;
+ tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+ static int tas_resume(struct tas *tas)
+ {
+ /* reset codec */
+- mutex_lock(&tas->mtx);
++ guard(mutex)(&tas->mtx);
+ tas_reset_init(tas);
+ tas_set_volume(tas);
+ tas_set_mixer(tas);
+ tas->hw_enabled = 1;
+- mutex_unlock(&tas->mtx);
+ return 0;
+ }
+
+@@ -802,14 +768,13 @@ static int tas_init_codec(struct aoa_cod
+ return -EINVAL;
+ }
+
+- mutex_lock(&tas->mtx);
+- if (tas_reset_init(tas)) {
+- printk(KERN_ERR PFX "tas failed to initialise\n");
+- mutex_unlock(&tas->mtx);
+- return -ENXIO;
++ scoped_guard(mutex, &tas->mtx) {
++ if (tas_reset_init(tas)) {
++ printk(KERN_ERR PFX "tas failed to initialise\n");
++ return -ENXIO;
++ }
++ tas->hw_enabled = 1;
+ }
+- tas->hw_enabled = 1;
+- mutex_unlock(&tas->mtx);
+
+ if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
+ aoa_get_card(),
+--- a/sound/aoa/core/gpio-feature.c
++++ b/sound/aoa/core/gpio-feature.c
+@@ -212,10 +212,9 @@ static void ftr_handle_notify(struct wor
+ struct gpio_notification *notif =
+ container_of(work, struct gpio_notification, work.work);
+
+- mutex_lock(¬if->mutex);
++ guard(mutex)(¬if->mutex);
+ if (notif->notify)
+ notif->notify(notif->data);
+- mutex_unlock(¬if->mutex);
+ }
+
+ static void gpio_enable_dual_edge(int gpio)
+@@ -341,19 +340,17 @@ static int ftr_set_notify(struct gpio_ru
+ if (!irq)
+ return -ENODEV;
+
+- mutex_lock(¬if->mutex);
++ guard(mutex)(¬if->mutex);
+
+ old = notif->notify;
+
+- if (!old && !notify) {
+- err = 0;
+- goto out_unlock;
+- }
++ if (!old && !notify)
++ return 0;
+
+ if (old && notify) {
+ if (old == notify && notif->data == data)
+ err = 0;
+- goto out_unlock;
++ return err;
+ }
+
+ if (old && !notify)
+@@ -362,16 +359,13 @@ static int ftr_set_notify(struct gpio_ru
+ if (!old && notify) {
+ err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
+ if (err)
+- goto out_unlock;
++ return err;
+ }
+
+ notif->notify = notify;
+ notif->data = data;
+
+- err = 0;
+- out_unlock:
+- mutex_unlock(¬if->mutex);
+- return err;
++ return 0;
+ }
+
+ static int ftr_get_detect(struct gpio_runtime *rt,
+--- a/sound/aoa/core/gpio-pmf.c
++++ b/sound/aoa/core/gpio-pmf.c
+@@ -74,10 +74,9 @@ static void pmf_handle_notify(struct wor
+ struct gpio_notification *notif =
+ container_of(work, struct gpio_notification, work.work);
+
+- mutex_lock(¬if->mutex);
++ guard(mutex)(¬if->mutex);
+ if (notif->notify)
+ notif->notify(notif->data);
+- mutex_unlock(¬if->mutex);
+ }
+
+ static void pmf_gpio_init(struct gpio_runtime *rt)
+@@ -154,19 +153,17 @@ static int pmf_set_notify(struct gpio_ru
+ return -EINVAL;
+ }
+
+- mutex_lock(¬if->mutex);
++ guard(mutex)(¬if->mutex);
+
+ old = notif->notify;
+
+- if (!old && !notify) {
+- err = 0;
+- goto out_unlock;
+- }
++ if (!old && !notify)
++ return 0;
+
+ if (old && notify) {
+ if (old == notify && notif->data == data)
+ err = 0;
+- goto out_unlock;
++ return err;
+ }
+
+ if (old && !notify) {
+@@ -178,10 +175,8 @@ static int pmf_set_notify(struct gpio_ru
+ if (!old && notify) {
+ irq_client = kzalloc(sizeof(struct pmf_irq_client),
+ GFP_KERNEL);
+- if (!irq_client) {
+- err = -ENOMEM;
+- goto out_unlock;
+- }
++ if (!irq_client)
++ return -ENOMEM;
+ irq_client->data = notif;
+ irq_client->handler = pmf_handle_notify_irq;
+ irq_client->owner = THIS_MODULE;
+@@ -192,17 +187,14 @@ static int pmf_set_notify(struct gpio_ru
+ printk(KERN_ERR "snd-aoa: gpio layer failed to"
+ " register %s irq (%d)\n", name, err);
+ kfree(irq_client);
+- goto out_unlock;
++ return err;
+ }
+ notif->gpio_private = irq_client;
+ }
+ notif->notify = notify;
+ notif->data = data;
+
+- err = 0;
+- out_unlock:
+- mutex_unlock(¬if->mutex);
+- return err;
++ return 0;
+ }
+
+ static int pmf_get_detect(struct gpio_runtime *rt,
+--- a/sound/aoa/soundbus/i2sbus/pcm.c
++++ b/sound/aoa/soundbus/i2sbus/pcm.c
+@@ -79,11 +79,10 @@ static int i2sbus_pcm_open(struct i2sbus
+ u64 formats = 0;
+ unsigned int rates = 0;
+ struct transfer_info v;
+- int result = 0;
+ int bus_factor = 0, sysclock_factor = 0;
+ int found_this;
+
+- mutex_lock(&i2sdev->lock);
++ guard(mutex)(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, &other);
+
+@@ -92,8 +91,7 @@ static int i2sbus_pcm_open(struct i2sbus
+
+ if (pi->active) {
+ /* alsa messed up */
+- result = -EBUSY;
+- goto out_unlock;
++ return -EBUSY;
+ }
+
+ /* we now need to assign the hw */
+@@ -117,10 +115,8 @@ static int i2sbus_pcm_open(struct i2sbus
+ ti++;
+ }
+ }
+- if (!masks_inited || !bus_factor || !sysclock_factor) {
+- result = -ENODEV;
+- goto out_unlock;
+- }
++ if (!masks_inited || !bus_factor || !sysclock_factor)
++ return -ENODEV;
+ /* bus dependent stuff */
+ hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
+@@ -194,15 +190,12 @@ static int i2sbus_pcm_open(struct i2sbus
+ hw->periods_max = MAX_DBDMA_COMMANDS;
+ err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+- if (err < 0) {
+- result = err;
+- goto out_unlock;
+- }
++ if (err < 0)
++ return err;
+ list_for_each_entry(cii, &sdev->codec_list, list) {
+ if (cii->codec->open) {
+ err = cii->codec->open(cii, pi->substream);
+ if (err) {
+- result = err;
+ /* unwind */
+ found_this = 0;
+ list_for_each_entry_reverse(rev,
+@@ -214,14 +207,12 @@ static int i2sbus_pcm_open(struct i2sbus
+ if (rev == cii)
+ found_this = 1;
+ }
+- goto out_unlock;
++ return err;
+ }
+ }
+ }
+
+- out_unlock:
+- mutex_unlock(&i2sdev->lock);
+- return result;
++ return 0;
+ }
+
+ #undef CHECK_RATE
+@@ -232,7 +223,7 @@ static int i2sbus_pcm_close(struct i2sbu
+ struct pcm_info *pi;
+ int err = 0, tmp;
+
+- mutex_lock(&i2sdev->lock);
++ guard(mutex)(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, NULL);
+
+@@ -246,7 +237,6 @@ static int i2sbus_pcm_close(struct i2sbu
+
+ pi->substream = NULL;
+ pi->active = 0;
+- mutex_unlock(&i2sdev->lock);
+ return err;
+ }
+
+@@ -330,33 +320,26 @@ static int i2sbus_pcm_prepare(struct i2s
+ int input_16bit;
+ struct pcm_info *pi, *other;
+ int cnt;
+- int result = 0;
+ unsigned int cmd, stopaddr;
+
+- mutex_lock(&i2sdev->lock);
++ guard(mutex)(&i2sdev->lock);
+
+ get_pcm_info(i2sdev, in, &pi, &other);
+
+- if (pi->dbdma_ring.running) {
+- result = -EBUSY;
+- goto out_unlock;
+- }
++ if (pi->dbdma_ring.running)
++ return -EBUSY;
+ if (pi->dbdma_ring.stopping)
+ i2sbus_wait_for_stop(i2sdev, pi);
+
+- if (!pi->substream || !pi->substream->runtime) {
+- result = -EINVAL;
+- goto out_unlock;
+- }
++ if (!pi->substream || !pi->substream->runtime)
++ return -EINVAL;
+
+ runtime = pi->substream->runtime;
+ pi->active = 1;
+ if (other->active &&
+ ((i2sdev->format != runtime->format)
+- || (i2sdev->rate != runtime->rate))) {
+- result = -EINVAL;
+- goto out_unlock;
+- }
++ || (i2sdev->rate != runtime->rate)))
++ return -EINVAL;
+
+ i2sdev->format = runtime->format;
+ i2sdev->rate = runtime->rate;
+@@ -412,10 +395,8 @@ static int i2sbus_pcm_prepare(struct i2s
+ bi.bus_factor = cii->codec->bus_factor;
+ break;
+ }
+- if (!bi.bus_factor) {
+- result = -ENODEV;
+- goto out_unlock;
+- }
++ if (!bi.bus_factor)
++ return -ENODEV;
+ input_16bit = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S32_BE:
+@@ -426,8 +407,7 @@ static int i2sbus_pcm_prepare(struct i2s
+ input_16bit = 0;
+ break;
+ default:
+- result = -EINVAL;
+- goto out_unlock;
++ return -EINVAL;
+ }
+ /* we assume all sysclocks are the same! */
+ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+@@ -438,10 +418,8 @@ static int i2sbus_pcm_prepare(struct i2s
+ if (clock_and_divisors(bi.sysclock_factor,
+ bi.bus_factor,
+ runtime->rate,
+- &sfr) < 0) {
+- result = -EINVAL;
+- goto out_unlock;
+- }
++ &sfr) < 0)
++ return -EINVAL;
+ switch (bi.bus_factor) {
+ case 32:
+ sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
+@@ -457,10 +435,8 @@ static int i2sbus_pcm_prepare(struct i2s
+ int err = 0;
+ if (cii->codec->prepare)
+ err = cii->codec->prepare(cii, &bi, pi->substream);
+- if (err) {
+- result = err;
+- goto out_unlock;
+- }
++ if (err)
++ return err;
+ }
+ /* codecs are fine with it, so set our clocks */
+ if (input_16bit)
+@@ -476,7 +452,7 @@ static int i2sbus_pcm_prepare(struct i2s
+ /* not locking these is fine since we touch them only in this function */
+ if (in_le32(&i2sdev->intfregs->serial_format) == sfr
+ && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
+- goto out_unlock;
++ return 0;
+
+ /* let's notify the codecs about clocks going away.
+ * For now we only do mastering on the i2s cell... */
+@@ -514,9 +490,7 @@ static int i2sbus_pcm_prepare(struct i2s
+ if (cii->codec->switch_clock)
+ cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+
+- out_unlock:
+- mutex_unlock(&i2sdev->lock);
+- return result;
++ return 0;
+ }
+
+ #ifdef CONFIG_PM
--- /dev/null
+From stable+bounces-242652-greg=kroah.com@vger.kernel.org Sun May 3 16:28:28 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 3 May 2026 06:58:21 -0400
+Subject: ALSA: core: Fix potential data race at fasync handling
+To: stable@vger.kernel.org
+Cc: Takashi Iwai <tiwai@suse.de>, Jake Lamberson <lamberson.jake@gmail.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260503105821.1029617-1-sashal@kernel.org>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 8146cd333d235ed32d48bb803fdf743472d7c783 ]
+
+In snd_fasync_work_fn(), which is the offload work for traversing and
+processing the pending fasync list, the call of kill_fasync() is done
+outside the snd_fasync_lock for avoiding deadlocks. The problem is
+that its the references of fasync->on, fasync->signal and fasync->poll
+are done there also outside the lock. Since these may be modified by
+snd_kill_fasync() call concurrently from other process, inconsistent
+values might be passed to kill_fasync(). Although there shouldn't be
+critical UAF, it's still better to be addressed.
+
+This patch moves the kill_fasync() argument evaluations inside the
+snd_fasync_lock for avoiding the data races above. The handling in
+fasync->on flag is optimized in the loop to skip directly.
+
+Also, for more clarity, snd_fasync_free() takes the lock and unlink
+the pending entry more directly instead of clearing fasync->on flag.
+
+Reported-by: Jake Lamberson <lamberson.jake@gmail.com>
+Fixes: ef34a0ae7a26 ("ALSA: core: Add async signal helpers")
+Cc: <stable@vger.kernel.org>
+Link: https://patch.msgid.link/20260420061721.3253644-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+[ replaced scoped_guard(spinlock_irq, &snd_fasync_lock) with explicit spin_lock_irq()/spin_unlock_irq() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/core/misc.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/sound/core/misc.c
++++ b/sound/core/misc.c
+@@ -171,14 +171,18 @@ static LIST_HEAD(snd_fasync_list);
+ static void snd_fasync_work_fn(struct work_struct *work)
+ {
+ struct snd_fasync *fasync;
++ int signal, poll;
+
+ spin_lock_irq(&snd_fasync_lock);
+ while (!list_empty(&snd_fasync_list)) {
+ fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
+ list_del_init(&fasync->list);
++ if (!fasync->on)
++ continue;
++ signal = fasync->signal;
++ poll = fasync->poll;
+ spin_unlock_irq(&snd_fasync_lock);
+- if (fasync->on)
+- kill_fasync(&fasync->fasync, fasync->signal, fasync->poll);
++ kill_fasync(&fasync->fasync, signal, poll);
+ spin_lock_irq(&snd_fasync_lock);
+ }
+ spin_unlock_irq(&snd_fasync_lock);
+@@ -234,7 +238,11 @@ void snd_fasync_free(struct snd_fasync *
+ {
+ if (!fasync)
+ return;
+- fasync->on = 0;
++
++ spin_lock_irq(&snd_fasync_lock);
++ list_del_init(&fasync->list);
++ spin_unlock_irq(&snd_fasync_lock);
++
+ flush_work(&snd_fasync_work);
+ kfree(fasync);
+ }
--- /dev/null
+From stable+bounces-241760-greg=kroah.com@vger.kernel.org Wed Apr 29 00:24:42 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 Apr 2026 14:53:11 -0400
+Subject: arm64/mm: Enable batched TLB flush in unmap_hotplug_range()
+To: stable@vger.kernel.org
+Cc: Anshuman Khandual <anshuman.khandual@arm.com>, Will Deacon <will@kernel.org>, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, "David Hildenbrand (Arm)" <david@kernel.org>, Ryan Roberts <ryan.roberts@arm.com>, Catalin Marinas <catalin.marinas@arm.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260428185311.3151505-1-sashal@kernel.org>
+
+From: Anshuman Khandual <anshuman.khandual@arm.com>
+
+[ Upstream commit 48478b9f791376b4b89018d7afdfd06865498f65 ]
+
+During a memory hot remove operation, both linear and vmemmap mappings for
+the memory range being removed, get unmapped via unmap_hotplug_range() but
+mapped pages get freed only for vmemmap mapping. This is just a sequential
+operation where each table entry gets cleared, followed by a leaf specific
+TLB flush, and then followed by memory free operation when applicable.
+
+This approach was simple and uniform both for vmemmap and linear mappings.
+But linear mapping might contain CONT marked block memory where it becomes
+necessary to first clear out all entire in the range before a TLB flush.
+This is as per the architecture requirement. Hence batch all TLB flushes
+during the table tear down walk and finally do it in unmap_hotplug_range().
+
+Prior to this fix, it was hypothetically possible for a speculative access
+to a higher address in the contiguous block to fill the TLB with shattered
+entries for the entire contiguous range after a lower address had already
+been cleared and invalidated. Due to the table entries being shattered, the
+subsequent TLB invalidation for the higher address would not then clear the
+TLB entries for the lower address, meaning stale TLB entries could persist.
+
+Besides it also helps in improving the performance via TLBI range operation
+along with reduced synchronization instructions. The time spent executing
+unmap_hotplug_range() improved 97% measured over a 2GB memory hot removal
+in KVM guest.
+
+This scheme is not applicable during vmemmap mapping tear down where memory
+needs to be freed and hence a TLB flush is required after clearing out page
+table entry.
+
+Cc: Will Deacon <will@kernel.org>
+Cc: linux-arm-kernel@lists.infradead.org
+Cc: linux-kernel@vger.kernel.org
+Closes: https://lore.kernel.org/all/aWZYXhrT6D2M-7-N@willie-the-truck/
+Fixes: bbd6ec605c0f ("arm64/mm: Enable memory hot remove")
+Cc: stable@vger.kernel.org
+Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
+Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
+Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+[ replaced `__pte_clear()` with `pte_clear()` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/mm/mmu.c | 36 ++++++++++++++++++++----------------
+ 1 file changed, 20 insertions(+), 16 deletions(-)
+
+--- a/arch/arm64/mm/mmu.c
++++ b/arch/arm64/mm/mmu.c
+@@ -886,10 +886,14 @@ static void unmap_hotplug_pte_range(pmd_
+
+ WARN_ON(!pte_present(pte));
+ pte_clear(&init_mm, addr, ptep);
+- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+- if (free_mapped)
++ if (free_mapped) {
++ /* CONT blocks are not supported in the vmemmap */
++ WARN_ON(pte_cont(pte));
++ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+ free_hotplug_page_range(pte_page(pte),
+ PAGE_SIZE, altmap);
++ }
++ /* unmap_hotplug_range() flushes TLB for !free_mapped */
+ } while (addr += PAGE_SIZE, addr < end);
+ }
+
+@@ -910,15 +914,14 @@ static void unmap_hotplug_pmd_range(pud_
+ WARN_ON(!pmd_present(pmd));
+ if (pmd_sect(pmd)) {
+ pmd_clear(pmdp);
+-
+- /*
+- * One TLBI should be sufficient here as the PMD_SIZE
+- * range is mapped with a single block entry.
+- */
+- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+- if (free_mapped)
++ if (free_mapped) {
++ /* CONT blocks are not supported in the vmemmap */
++ WARN_ON(pmd_cont(pmd));
++ flush_tlb_kernel_range(addr, addr + PMD_SIZE);
+ free_hotplug_page_range(pmd_page(pmd),
+ PMD_SIZE, altmap);
++ }
++ /* unmap_hotplug_range() flushes TLB for !free_mapped */
+ continue;
+ }
+ WARN_ON(!pmd_table(pmd));
+@@ -943,15 +946,12 @@ static void unmap_hotplug_pud_range(p4d_
+ WARN_ON(!pud_present(pud));
+ if (pud_sect(pud)) {
+ pud_clear(pudp);
+-
+- /*
+- * One TLBI should be sufficient here as the PUD_SIZE
+- * range is mapped with a single block entry.
+- */
+- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+- if (free_mapped)
++ if (free_mapped) {
++ flush_tlb_kernel_range(addr, addr + PUD_SIZE);
+ free_hotplug_page_range(pud_page(pud),
+ PUD_SIZE, altmap);
++ }
++ /* unmap_hotplug_range() flushes TLB for !free_mapped */
+ continue;
+ }
+ WARN_ON(!pud_table(pud));
+@@ -981,6 +981,7 @@ static void unmap_hotplug_p4d_range(pgd_
+ static void unmap_hotplug_range(unsigned long addr, unsigned long end,
+ bool free_mapped, struct vmem_altmap *altmap)
+ {
++ unsigned long start = addr;
+ unsigned long next;
+ pgd_t *pgdp, pgd;
+
+@@ -1002,6 +1003,9 @@ static void unmap_hotplug_range(unsigned
+ WARN_ON(!pgd_present(pgd));
+ unmap_hotplug_p4d_range(pgdp, addr, next, free_mapped, altmap);
+ } while (addr = next, addr < end);
++
++ if (!free_mapped)
++ flush_tlb_kernel_range(start, end);
+ }
+
+ static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr,
--- /dev/null
+From stable+bounces-244878-greg=kroah.com@vger.kernel.org Sat May 9 07:03:27 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 21:33:20 -0400
+Subject: Bluetooth: hci_event: fix potential UAF in SSP passkey handlers
+To: stable@vger.kernel.org
+Cc: Shuvam Pandey <shuvampandey1@gmail.com>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509013320.2851098-1-sashal@kernel.org>
+
+From: Shuvam Pandey <shuvampandey1@gmail.com>
+
+[ Upstream commit 85fa3512048793076eef658f66489112dcc91993 ]
+
+hci_conn lookup and field access must be covered by hdev lock in
+hci_user_passkey_notify_evt() and hci_keypress_notify_evt(), otherwise
+the connection can be freed concurrently.
+
+Extend the hci_dev_lock critical section to cover all conn usage in both
+handlers.
+
+Keep the existing keypress notification behavior unchanged by routing
+the early exits through a common unlock path.
+
+Fixes: 92a25256f142 ("Bluetooth: mgmt: Implement support for passkey notification")
+Cc: stable@vger.kernel.org
+Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/hci_event.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -4953,9 +4953,11 @@ static void hci_user_passkey_notify_evt(
+
+ BT_DBG("%s", hdev->name);
+
++ hci_dev_lock(hdev);
++
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (!conn)
+- return;
++ goto unlock;
+
+ conn->passkey_notify = __le32_to_cpu(ev->passkey);
+ conn->passkey_entered = 0;
+@@ -4964,6 +4966,9 @@ static void hci_user_passkey_notify_evt(
+ mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+ conn->dst_type, conn->passkey_notify,
+ conn->passkey_entered);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+@@ -4973,14 +4978,16 @@ static void hci_keypress_notify_evt(stru
+
+ BT_DBG("%s", hdev->name);
+
++ hci_dev_lock(hdev);
++
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (!conn)
+- return;
++ goto unlock;
+
+ switch (ev->type) {
+ case HCI_KEYPRESS_STARTED:
+ conn->passkey_entered = 0;
+- return;
++ goto unlock;
+
+ case HCI_KEYPRESS_ENTERED:
+ conn->passkey_entered++;
+@@ -4995,13 +5002,16 @@ static void hci_keypress_notify_evt(stru
+ break;
+
+ case HCI_KEYPRESS_COMPLETED:
+- return;
++ goto unlock;
+ }
+
+ if (hci_dev_test_flag(hdev, HCI_MGMT))
+ mgmt_user_passkey_notify(hdev, &conn->dst, conn->type,
+ conn->dst_type, conn->passkey_notify,
+ conn->passkey_entered);
++
++unlock:
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
--- /dev/null
+From stable+bounces-244882-greg=kroah.com@vger.kernel.org Sat May 9 07:35:52 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 22:04:53 -0400
+Subject: can: ucan: fix devres lifetime
+To: stable@vger.kernel.org
+Cc: Johan Hovold <johan@kernel.org>, Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>, Marc Kleine-Budde <mkl@pengutronix.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509020453.2868235-2-sashal@kernel.org>
+
+From: Johan Hovold <johan@kernel.org>
+
+[ Upstream commit fed4626501c871890da287bec62a96e52da1af89 ]
+
+USB drivers bind to USB interfaces and any device managed resources
+should have their lifetime tied to the interface rather than parent USB
+device. This avoids issues like memory leaks when drivers are unbound
+without their devices being physically disconnected (e.g. on probe
+deferral or configuration changes).
+
+Fix the control message buffer lifetime so that it is released on driver
+unbind.
+
+Fixes: 9f2d3eae88d2 ("can: ucan: add driver for Theobroma Systems UCAN devices")
+Cc: stable@vger.kernel.org # 4.19
+Cc: Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://patch.msgid.link/20260327104520.1310158-1-johan@kernel.org
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/can/usb/ucan.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/can/usb/ucan.c
++++ b/drivers/net/can/usb/ucan.c
+@@ -1396,7 +1396,7 @@ static int ucan_probe(struct usb_interfa
+ */
+
+ /* Prepare Memory for control transfers */
+- ctl_msg_buffer = devm_kzalloc(&udev->dev,
++ ctl_msg_buffer = devm_kzalloc(&intf->dev,
+ sizeof(union ucan_ctl_payload),
+ GFP_KERNEL);
+ if (!ctl_msg_buffer) {
--- /dev/null
+From stable+bounces-244881-greg=kroah.com@vger.kernel.org Sat May 9 07:35:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 22:04:52 -0400
+Subject: can: ucan: fix typos in comments
+To: stable@vger.kernel.org
+Cc: Julia Lawall <Julia.Lawall@inria.fr>, Marc Kleine-Budde <mkl@pengutronix.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509020453.2868235-1-sashal@kernel.org>
+
+From: Julia Lawall <Julia.Lawall@inria.fr>
+
+[ Upstream commit c34983c94166689358372d4af8d5def57752860c ]
+
+Various spelling mistakes in comments.
+Detected with the help of Coccinelle.
+
+Link: https://lore.kernel.org/all/20220314115354.144023-28-Julia.Lawall@inria.fr
+Signed-off-by: Julia Lawall <Julia.Lawall@inria.fr>
+Acked-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Stable-dep-of: fed4626501c8 ("can: ucan: fix devres lifetime")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/can/usb/ucan.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/can/usb/ucan.c
++++ b/drivers/net/can/usb/ucan.c
+@@ -1395,7 +1395,7 @@ static int ucan_probe(struct usb_interfa
+ * Stage 3 for the final driver initialisation.
+ */
+
+- /* Prepare Memory for control transferes */
++ /* Prepare Memory for control transfers */
+ ctl_msg_buffer = devm_kzalloc(&udev->dev,
+ sizeof(union ucan_ctl_payload),
+ GFP_KERNEL);
+@@ -1529,7 +1529,7 @@ static int ucan_probe(struct usb_interfa
+ ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
+ sizeof(union ucan_ctl_payload));
+ if (ret > 0) {
+- /* copy string while ensuring zero terminiation */
++ /* copy string while ensuring zero termination */
+ strncpy(firmware_str, up->ctl_msg_buffer->raw,
+ sizeof(union ucan_ctl_payload));
+ firmware_str[sizeof(union ucan_ctl_payload)] = '\0';
--- /dev/null
+From stable+bounces-244965-greg=kroah.com@vger.kernel.org Sat May 9 20:52:42 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 May 2026 11:22:35 -0400
+Subject: ceph: only d_add() negative dentries when they are unhashed
+To: stable@vger.kernel.org
+Cc: Max Kellermann <max.kellermann@ionos.com>, Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>, Ilya Dryomov <idryomov@gmail.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509152235.3512498-1-sashal@kernel.org>
+
+From: Max Kellermann <max.kellermann@ionos.com>
+
+[ Upstream commit 803447f93d75ab6e40c85e6d12b5630d281d70d6 ]
+
+Ceph can call d_add(dentry, NULL) on a negative dentry that is already
+present in the primary dcache hash.
+
+In the current VFS that is not safe. d_add() goes through __d_add()
+to __d_rehash(), which unconditionally reinserts dentry->d_hash into
+the hlist_bl bucket. If the dentry is already hashed, reinserting the
+same node can corrupt the bucket, including creating a self-loop.
+Once that happens, __d_lookup() can spin forever in the hlist_bl walk,
+typically looping only on the d_name.hash mismatch check and
+eventually triggering RCU stall reports like this one:
+
+ rcu: INFO: rcu_sched self-detected stall on CPU
+ rcu: 87-....: (2100 ticks this GP) idle=3a4c/1/0x4000000000000000 softirq=25003319/25003319 fqs=829
+ rcu: (t=2101 jiffies g=79058445 q=698988 ncpus=192)
+ CPU: 87 UID: 2952868916 PID: 3933303 Comm: php-cgi8.3 Not tainted 6.18.17-i1-amd #950 NONE
+ Hardware name: Dell Inc. PowerEdge R7615/0G9DHV, BIOS 1.6.6 09/22/2023
+ RIP: 0010:__d_lookup+0x46/0xb0
+ Code: c1 e8 07 48 8d 04 c2 48 8b 00 49 89 fc 49 89 f5 48 89 c3 48 83 e3 fe 48 83 f8 01 77 0f eb 2d 0f 1f 44 00 00 48 8b 1b 48 85 db <74> 20 39 6b 18 75 f3 48 8d 7b 78 e8 ba 85 d0 00 4c 39 63 10 74 1f
+ RSP: 0018:ff745a70c8253898 EFLAGS: 00000282
+ RAX: ff26e470054cb208 RBX: ff26e470054cb208 RCX: 000000006e958966
+ RDX: ff26e48267340000 RSI: ff745a70c82539b0 RDI: ff26e458f74655c0
+ RBP: 000000006e958966 R08: 0000000000000180 R09: 9cd08d909b919a89
+ R10: ff26e458f74655c0 R11: 0000000000000000 R12: ff26e458f74655c0
+ R13: ff745a70c82539b0 R14: d0d0d0d0d0d0d0d0 R15: 2f2f2f2f2f2f2f2f
+ FS: 00007f5770896980(0000) GS:ff26e482c5d88000(0000) knlGS:0000000000000000
+ CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 00007f5764de50c0 CR3: 000000a72abb5001 CR4: 0000000000771ef0
+ PKRU: 55555554
+ Call Trace:
+ <TASK>
+ lookup_fast+0x9f/0x100
+ walk_component+0x1f/0x150
+ link_path_walk+0x20e/0x3d0
+ path_lookupat+0x68/0x180
+ filename_lookup+0xdc/0x1e0
+ vfs_statx+0x6c/0x140
+ vfs_fstatat+0x67/0xa0
+ __do_sys_newfstatat+0x24/0x60
+ do_syscall_64+0x6a/0x230
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+This is reachable with reused cached negative dentries. A Ceph lookup
+or atomic_open can be handed a negative dentry that is already hashed,
+and fs/ceph/dir.c then hits one of two paths that incorrectly assume
+"negative" also means "unhashed":
+
+ - ceph_finish_lookup():
+ MDS reply is -ENOENT with no trace
+ -> d_add(dentry, NULL)
+
+ - ceph_lookup():
+ local ENOENT fast path for a complete directory with shared caps
+ -> d_add(dentry, NULL)
+
+Both paths can therefore re-add an already-hashed negative dentry.
+
+Ceph already uses the correct pattern elsewhere: ceph_fill_trace() only
+calls d_add(dn, NULL) for a negative null-dentry reply when d_unhashed(dn)
+is true.
+
+Fix both fs/ceph/dir.c sites the same way: only call d_add() for a
+negative dentry when it is actually unhashed. If the negative dentry
+is already hashed, leave it in place and reuse it as-is.
+
+This preserves the existing behavior for unhashed dentries while
+avoiding d_hash list corruption for reused hashed negatives.
+
+Cc: stable@vger.kernel.org
+Fixes: 2817b000b02c ("ceph: directory operations")
+Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
+Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+[ kept existing dout() debug call instead of upstream's doutc() form when adding the d_unhashed() guard around d_add() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ceph/dir.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/fs/ceph/dir.c
++++ b/fs/ceph/dir.c
+@@ -721,7 +721,8 @@ struct dentry *ceph_finish_lookup(struct
+ d_drop(dentry);
+ err = -ENOENT;
+ } else {
+- d_add(dentry, NULL);
++ if (d_unhashed(dentry))
++ d_add(dentry, NULL);
+ }
+ }
+ }
+@@ -777,7 +778,8 @@ static struct dentry *ceph_lookup(struct
+ __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
+ spin_unlock(&ci->i_ceph_lock);
+ dout(" dir %p complete, -ENOENT\n", dir);
+- d_add(dentry, NULL);
++ if (d_unhashed(dentry))
++ d_add(dentry, NULL);
+ di->lease_shared_gen = atomic_read(&ci->i_shared_gen);
+ return NULL;
+ }
--- /dev/null
+From stable+bounces-245031-greg=kroah.com@vger.kernel.org Sun May 10 20:40:20 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 11:10:10 -0400
+Subject: crypto: caam - guard HMAC key hex dumps in hash_digest_key
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260510151010.38344-2-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ Upstream commit 177730a273b18e195263ed953853273e901b5064 ]
+
+Use print_hex_dump_devel() for dumping sensitive HMAC key bytes in
+hash_digest_key() to avoid leaking secrets at runtime when
+CONFIG_DYNAMIC_DEBUG is enabled.
+
+Fixes: 045e36780f11 ("crypto: caam - ahash hmac support")
+Fixes: 3f16f6c9d632 ("crypto: caam/qi2 - add support for ahash algorithms")
+Cc: stable@vger.kernel.org
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/caam/caamalg_qi2.c | 4 ++--
+ drivers/crypto/caam/caamhash.c | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/crypto/caam/caamalg_qi2.c
++++ b/drivers/crypto/caam/caamalg_qi2.c
+@@ -3264,7 +3264,7 @@ static int hash_digest_key(struct caam_h
+ dpaa2_fl_set_addr(out_fle, key_dma);
+ dpaa2_fl_set_len(out_fle, digestsize);
+
+- print_hex_dump_debug("key_in@" __stringify(__LINE__)": ",
++ print_hex_dump_devel("key_in@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1);
+ print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+@@ -3284,7 +3284,7 @@ static int hash_digest_key(struct caam_h
+ /* in progress */
+ wait_for_completion(&result.completion);
+ ret = result.err;
+- print_hex_dump_debug("digested key@" __stringify(__LINE__)": ",
++ print_hex_dump_devel("digested key@" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key,
+ digestsize, 1);
+ }
+--- a/drivers/crypto/caam/caamhash.c
++++ b/drivers/crypto/caam/caamhash.c
+@@ -390,7 +390,7 @@ static int hash_digest_key(struct caam_h
+ append_seq_store(desc, digestsize, LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+
+- print_hex_dump_debug("key_in@"__stringify(__LINE__)": ",
++ print_hex_dump_devel("key_in@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1);
+ print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
+@@ -405,7 +405,7 @@ static int hash_digest_key(struct caam_h
+ wait_for_completion(&result.completion);
+ ret = result.err;
+
+- print_hex_dump_debug("digested key@"__stringify(__LINE__)": ",
++ print_hex_dump_devel("digested key@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key,
+ digestsize, 1);
+ }
--- /dev/null
+From stable+bounces-244907-greg=kroah.com@vger.kernel.org Sat May 9 09:23:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 23:53:31 -0400
+Subject: crypto: nx - Avoid -Wflex-array-member-not-at-end warning
+To: stable@vger.kernel.org
+Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509035333.3119717-1-sashal@kernel.org>
+
+From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
+
+[ Upstream commit 1e6b251ce1759392666856908113dd5d7cea044d ]
+
+-Wflex-array-member-not-at-end is coming in GCC-14, and we are getting
+ready to enable it globally. So, we are deprecating flexible-array
+members in the middle of another structure.
+
+There is currently an object (`header`) in `struct nx842_crypto_ctx`
+that contains a flexible structure (`struct nx842_crypto_header`):
+
+struct nx842_crypto_ctx {
+ ...
+ struct nx842_crypto_header header;
+ struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX];
+ ...
+};
+
+So, in order to avoid ending up with a flexible-array member in the
+middle of another struct, we use the `struct_group_tagged()` helper to
+separate the flexible array from the rest of the members in the flexible
+structure:
+
+struct nx842_crypto_header {
+ struct_group_tagged(nx842_crypto_header_hdr, hdr,
+
+ ... the rest of the members
+
+ );
+ struct nx842_crypto_header_group group[];
+} __packed;
+
+With the change described above, we can now declare an object of the
+type of the tagged struct, without embedding the flexible array in the
+middle of another struct:
+
+struct nx842_crypto_ctx {
+ ...
+ struct nx842_crypto_header_hdr header;
+ struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX];
+ ...
+ } __packed;
+
+We also use `container_of()` whenever we need to retrieve a pointer to
+the flexible structure, through which we can access the flexible
+array if needed.
+
+So, with these changes, fix the following warning:
+
+In file included from drivers/crypto/nx/nx-842.c:55:
+drivers/crypto/nx/nx-842.h:174:36: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
+ 174 | struct nx842_crypto_header header;
+ | ^~~~~~
+
+Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Stable-dep-of: adb3faf2db1a ("crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/nx/nx-842.c | 6 ++++--
+ drivers/crypto/nx/nx-842.h | 10 ++++++----
+ 2 files changed, 10 insertions(+), 6 deletions(-)
+
+--- a/drivers/crypto/nx/nx-842.c
++++ b/drivers/crypto/nx/nx-842.c
+@@ -251,7 +251,9 @@ int nx842_crypto_compress(struct crypto_
+ u8 *dst, unsigned int *dlen)
+ {
+ struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct nx842_crypto_header *hdr = &ctx->header;
++ struct nx842_crypto_header *hdr =
++ container_of(&ctx->header,
++ struct nx842_crypto_header, hdr);
+ struct nx842_crypto_param p;
+ struct nx842_constraints c = *ctx->driver->constraints;
+ unsigned int groups, hdrsize, h;
+@@ -490,7 +492,7 @@ int nx842_crypto_decompress(struct crypt
+ }
+
+ memcpy(&ctx->header, src, hdr_len);
+- hdr = &ctx->header;
++ hdr = container_of(&ctx->header, struct nx842_crypto_header, hdr);
+
+ for (n = 0; n < hdr->groups; n++) {
+ /* ignore applies to last group */
+--- a/drivers/crypto/nx/nx-842.h
++++ b/drivers/crypto/nx/nx-842.h
+@@ -157,9 +157,11 @@ struct nx842_crypto_header_group {
+ } __packed;
+
+ struct nx842_crypto_header {
+- __be16 magic; /* NX842_CRYPTO_MAGIC */
+- __be16 ignore; /* decompressed end bytes to ignore */
+- u8 groups; /* total groups in this header */
++ struct_group_tagged(nx842_crypto_header_hdr, hdr,
++ __be16 magic; /* NX842_CRYPTO_MAGIC */
++ __be16 ignore; /* decompressed end bytes to ignore */
++ u8 groups; /* total groups in this header */
++ );
+ struct nx842_crypto_header_group group[];
+ } __packed;
+
+@@ -171,7 +173,7 @@ struct nx842_crypto_ctx {
+ u8 *wmem;
+ u8 *sbounce, *dbounce;
+
+- struct nx842_crypto_header header;
++ struct nx842_crypto_header_hdr header;
+ struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX];
+
+ struct nx842_driver *driver;
--- /dev/null
+From stable+bounces-244909-greg=kroah.com@vger.kernel.org Sat May 9 09:23:52 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 23:53:33 -0400
+Subject: crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509035333.3119717-3-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ Upstream commit adb3faf2db1a66d0f015b44ac909a32dfc7f2f9c ]
+
+The bounce buffers are allocated with __get_free_pages() using
+BOUNCE_BUFFER_ORDER (order 2 = 4 pages), but both the allocation error
+path and nx842_crypto_free_ctx() release the buffers with free_page().
+Use free_pages() with the matching order instead.
+
+Fixes: ed70b479c2c0 ("crypto: nx - add hardware 842 crypto comp alg")
+Cc: stable@vger.kernel.org
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/nx/nx-842.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/crypto/nx/nx-842.c
++++ b/drivers/crypto/nx/nx-842.c
+@@ -116,8 +116,8 @@ void *nx842_crypto_alloc_ctx(struct nx84
+ ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
+ if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) {
+ kfree(ctx->wmem);
+- free_page((unsigned long)ctx->sbounce);
+- free_page((unsigned long)ctx->dbounce);
++ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER);
++ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER);
+ kfree(ctx);
+ return ERR_PTR(-ENOMEM);
+ }
+@@ -131,8 +131,8 @@ void nx842_crypto_free_ctx(void *p)
+ struct nx842_crypto_ctx *ctx = p;
+
+ kfree(ctx->wmem);
+- free_page((unsigned long)ctx->sbounce);
+- free_page((unsigned long)ctx->dbounce);
++ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER);
++ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER);
+ }
+ EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx);
+
--- /dev/null
+From stable+bounces-244908-greg=kroah.com@vger.kernel.org Sat May 9 09:23:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 23:53:32 -0400
+Subject: crypto: nx - Migrate to scomp API
+To: stable@vger.kernel.org
+Cc: Ard Biesheuvel <ardb@kernel.org>, Herbert Xu <herbert@gondor.apana.org.au>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509035333.3119717-2-sashal@kernel.org>
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+[ Upstream commit 980b5705f4e73f567e405cd18337cc32fd51cf79 ]
+
+The only remaining user of 842 compression has been migrated to the
+acomp compression API, and so the NX hardware driver has to follow suit,
+given that no users of the obsolete 'comp' API remain, and it is going
+to be removed.
+
+So migrate the NX driver code to scomp. These will be wrapped and
+exposed as acomp implementation via the crypto subsystem's
+acomp-to-scomp adaptation layer.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Stable-dep-of: adb3faf2db1a ("crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/nx/nx-842.c | 33 +++++++++++++++++++--------------
+ drivers/crypto/nx/nx-842.h | 14 ++++++++------
+ drivers/crypto/nx/nx-common-powernv.c | 31 +++++++++++++++----------------
+ drivers/crypto/nx/nx-common-pseries.c | 33 ++++++++++++++++-----------------
+ 4 files changed, 58 insertions(+), 53 deletions(-)
+
+--- a/drivers/crypto/nx/nx-842.c
++++ b/drivers/crypto/nx/nx-842.c
+@@ -101,9 +101,13 @@ static int update_param(struct nx842_cry
+ return 0;
+ }
+
+-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver)
++void *nx842_crypto_alloc_ctx(struct nx842_driver *driver)
+ {
+- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct nx842_crypto_ctx *ctx;
++
++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++ if (!ctx)
++ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&ctx->lock);
+ ctx->driver = driver;
+@@ -114,22 +118,23 @@ int nx842_crypto_init(struct crypto_tfm
+ kfree(ctx->wmem);
+ free_page((unsigned long)ctx->sbounce);
+ free_page((unsigned long)ctx->dbounce);
+- return -ENOMEM;
++ kfree(ctx);
++ return ERR_PTR(-ENOMEM);
+ }
+
+- return 0;
++ return ctx;
+ }
+-EXPORT_SYMBOL_GPL(nx842_crypto_init);
++EXPORT_SYMBOL_GPL(nx842_crypto_alloc_ctx);
+
+-void nx842_crypto_exit(struct crypto_tfm *tfm)
++void nx842_crypto_free_ctx(void *p)
+ {
+- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct nx842_crypto_ctx *ctx = p;
+
+ kfree(ctx->wmem);
+ free_page((unsigned long)ctx->sbounce);
+ free_page((unsigned long)ctx->dbounce);
+ }
+-EXPORT_SYMBOL_GPL(nx842_crypto_exit);
++EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx);
+
+ static void check_constraints(struct nx842_constraints *c)
+ {
+@@ -246,11 +251,11 @@ nospc:
+ return update_param(p, slen, dskip + dlen);
+ }
+
+-int nx842_crypto_compress(struct crypto_tfm *tfm,
++int nx842_crypto_compress(struct crypto_scomp *tfm,
+ const u8 *src, unsigned int slen,
+- u8 *dst, unsigned int *dlen)
++ u8 *dst, unsigned int *dlen, void *pctx)
+ {
+- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct nx842_crypto_ctx *ctx = pctx;
+ struct nx842_crypto_header *hdr =
+ container_of(&ctx->header,
+ struct nx842_crypto_header, hdr);
+@@ -431,11 +436,11 @@ usesw:
+ return update_param(p, slen + padding, dlen);
+ }
+
+-int nx842_crypto_decompress(struct crypto_tfm *tfm,
++int nx842_crypto_decompress(struct crypto_scomp *tfm,
+ const u8 *src, unsigned int slen,
+- u8 *dst, unsigned int *dlen)
++ u8 *dst, unsigned int *dlen, void *pctx)
+ {
+- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct nx842_crypto_ctx *ctx = pctx;
+ struct nx842_crypto_header *hdr;
+ struct nx842_crypto_param p;
+ struct nx842_constraints c = *ctx->driver->constraints;
+--- a/drivers/crypto/nx/nx-842.h
++++ b/drivers/crypto/nx/nx-842.h
+@@ -101,6 +101,8 @@
+ #define LEN_ON_SIZE(pa, size) ((size) - ((pa) & ((size) - 1)))
+ #define LEN_ON_PAGE(pa) LEN_ON_SIZE(pa, PAGE_SIZE)
+
++struct crypto_scomp;
++
+ static inline unsigned long nx842_get_pa(void *addr)
+ {
+ if (!is_vmalloc_addr(addr))
+@@ -179,13 +181,13 @@ struct nx842_crypto_ctx {
+ struct nx842_driver *driver;
+ };
+
+-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver);
+-void nx842_crypto_exit(struct crypto_tfm *tfm);
+-int nx842_crypto_compress(struct crypto_tfm *tfm,
++void *nx842_crypto_alloc_ctx(struct nx842_driver *driver);
++void nx842_crypto_free_ctx(void *ctx);
++int nx842_crypto_compress(struct crypto_scomp *tfm,
+ const u8 *src, unsigned int slen,
+- u8 *dst, unsigned int *dlen);
+-int nx842_crypto_decompress(struct crypto_tfm *tfm,
++ u8 *dst, unsigned int *dlen, void *ctx);
++int nx842_crypto_decompress(struct crypto_scomp *tfm,
+ const u8 *src, unsigned int slen,
+- u8 *dst, unsigned int *dlen);
++ u8 *dst, unsigned int *dlen, void *ctx);
+
+ #endif /* __NX_842_H__ */
+--- a/drivers/crypto/nx/nx-common-powernv.c
++++ b/drivers/crypto/nx/nx-common-powernv.c
+@@ -9,6 +9,7 @@
+
+ #include "nx-842.h"
+
++#include <crypto/internal/scompress.h>
+ #include <linux/timer.h>
+
+ #include <asm/prom.h>
+@@ -1034,23 +1035,21 @@ static struct nx842_driver nx842_powernv
+ .decompress = nx842_powernv_decompress,
+ };
+
+-static int nx842_powernv_crypto_init(struct crypto_tfm *tfm)
++static void *nx842_powernv_crypto_alloc_ctx(void)
+ {
+- return nx842_crypto_init(tfm, &nx842_powernv_driver);
++ return nx842_crypto_alloc_ctx(&nx842_powernv_driver);
+ }
+
+-static struct crypto_alg nx842_powernv_alg = {
+- .cra_name = "842",
+- .cra_driver_name = "842-nx",
+- .cra_priority = 300,
+- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
+- .cra_ctxsize = sizeof(struct nx842_crypto_ctx),
+- .cra_module = THIS_MODULE,
+- .cra_init = nx842_powernv_crypto_init,
+- .cra_exit = nx842_crypto_exit,
+- .cra_u = { .compress = {
+- .coa_compress = nx842_crypto_compress,
+- .coa_decompress = nx842_crypto_decompress } }
++static struct scomp_alg nx842_powernv_alg = {
++ .base.cra_name = "842",
++ .base.cra_driver_name = "842-nx",
++ .base.cra_priority = 300,
++ .base.cra_module = THIS_MODULE,
++
++ .alloc_ctx = nx842_powernv_crypto_alloc_ctx,
++ .free_ctx = nx842_crypto_free_ctx,
++ .compress = nx842_crypto_compress,
++ .decompress = nx842_crypto_decompress,
+ };
+
+ static __init int nx_compress_powernv_init(void)
+@@ -1110,7 +1109,7 @@ static __init int nx_compress_powernv_in
+ nx842_powernv_exec = nx842_exec_vas;
+ }
+
+- ret = crypto_register_alg(&nx842_powernv_alg);
++ ret = crypto_register_scomp(&nx842_powernv_alg);
+ if (ret) {
+ nx_delete_coprocs();
+ return ret;
+@@ -1131,7 +1130,7 @@ static void __exit nx_compress_powernv_e
+ if (!nx842_ct)
+ vas_unregister_api_powernv();
+
+- crypto_unregister_alg(&nx842_powernv_alg);
++ crypto_unregister_scomp(&nx842_powernv_alg);
+
+ nx_delete_coprocs();
+ }
+--- a/drivers/crypto/nx/nx-common-pseries.c
++++ b/drivers/crypto/nx/nx-common-pseries.c
+@@ -11,6 +11,7 @@
+ #include <asm/vio.h>
+ #include <asm/hvcall.h>
+ #include <asm/vas.h>
++#include <crypto/internal/scompress.h>
+
+ #include "nx-842.h"
+ #include "nx_csbcpb.h" /* struct nx_csbcpb */
+@@ -1006,23 +1007,21 @@ static struct nx842_driver nx842_pseries
+ .decompress = nx842_pseries_decompress,
+ };
+
+-static int nx842_pseries_crypto_init(struct crypto_tfm *tfm)
++static void *nx842_pseries_crypto_alloc_ctx(void)
+ {
+- return nx842_crypto_init(tfm, &nx842_pseries_driver);
++ return nx842_crypto_alloc_ctx(&nx842_pseries_driver);
+ }
+
+-static struct crypto_alg nx842_pseries_alg = {
+- .cra_name = "842",
+- .cra_driver_name = "842-nx",
+- .cra_priority = 300,
+- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
+- .cra_ctxsize = sizeof(struct nx842_crypto_ctx),
+- .cra_module = THIS_MODULE,
+- .cra_init = nx842_pseries_crypto_init,
+- .cra_exit = nx842_crypto_exit,
+- .cra_u = { .compress = {
+- .coa_compress = nx842_crypto_compress,
+- .coa_decompress = nx842_crypto_decompress } }
++static struct scomp_alg nx842_pseries_alg = {
++ .base.cra_name = "842",
++ .base.cra_driver_name = "842-nx",
++ .base.cra_priority = 300,
++ .base.cra_module = THIS_MODULE,
++
++ .alloc_ctx = nx842_pseries_crypto_alloc_ctx,
++ .free_ctx = nx842_crypto_free_ctx,
++ .compress = nx842_crypto_compress,
++ .decompress = nx842_crypto_decompress,
+ };
+
+ static int nx842_probe(struct vio_dev *viodev,
+@@ -1070,7 +1069,7 @@ static int nx842_probe(struct vio_dev *v
+ if (ret)
+ goto error;
+
+- ret = crypto_register_alg(&nx842_pseries_alg);
++ ret = crypto_register_scomp(&nx842_pseries_alg);
+ if (ret) {
+ dev_err(&viodev->dev, "could not register comp alg: %d\n", ret);
+ goto error;
+@@ -1118,7 +1117,7 @@ static void nx842_remove(struct vio_dev
+ if (caps_feat)
+ sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group);
+
+- crypto_unregister_alg(&nx842_pseries_alg);
++ crypto_unregister_scomp(&nx842_pseries_alg);
+
+ spin_lock_irqsave(&devdata_mutex, flags);
+ old_devdata = rcu_dereference_check(devdata,
+@@ -1247,7 +1246,7 @@ static void __exit nx842_pseries_exit(vo
+
+ vas_unregister_api_pseries();
+
+- crypto_unregister_alg(&nx842_pseries_alg);
++ crypto_unregister_scomp(&nx842_pseries_alg);
+
+ spin_lock_irqsave(&devdata_mutex, flags);
+ old_devdata = rcu_dereference_check(devdata,
--- /dev/null
+From stable+bounces-242493-greg=kroah.com@vger.kernel.org Sat May 2 00:18:56 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 14:48:48 -0400
+Subject: erofs: fix the out-of-bounds nameoff handling for trailing dirents
+To: stable@vger.kernel.org
+Cc: Gao Xiang <hsiangkao@linux.alibaba.com>, Yuhao Jiang <danisjiang@gmail.com>, Junrui Luo <moonafterrain@outlook.com>, Chao Yu <chao@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501184848.3924034-1-sashal@kernel.org>
+
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+
+[ Upstream commit d18a3b5d337fa412a38e776e6b4b857a58836575 ]
+
+Currently we already have boundary-checks for nameoffs, but the trailing
+dirents are special since the namelens are calculated with strnlen()
+with unchecked nameoffs.
+
+If a crafted EROFS has a trailing dirent with nameoff >= maxsize,
+maxsize - nameoff can underflow, causing strnlen() to read past the
+directory block.
+
+nameoff0 should also be verified to be a multiple of
+`sizeof(struct erofs_dirent)` as well [1].
+
+[1] https://sashiko.dev/#/patchset/20260416063511.3173774-1-hsiangkao%40linux.alibaba.com
+
+Fixes: 3aa8ec716e52 ("staging: erofs: add directory operations")
+Fixes: 33bac912840f ("staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()")
+Reported-by: Yuhao Jiang <danisjiang@gmail.com>
+Reported-by: Junrui Luo <moonafterrain@outlook.com>
+Closes: https://lore.kernel.org/r/A0FD7E0F-7558-49B0-8BC8-EB1ECDB2479A@outlook.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+[ replaced upstream `bsz` with `PAGE_SIZE` and `sizeof(*de)` with `sizeof(struct erofs_dirent)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/erofs/dir.c | 30 ++++++++++++++++--------------
+ 1 file changed, 16 insertions(+), 14 deletions(-)
+
+--- a/fs/erofs/dir.c
++++ b/fs/erofs/dir.c
+@@ -37,20 +37,18 @@ static int erofs_fill_dentries(struct in
+ nameoff = le16_to_cpu(de->nameoff);
+ de_name = (char *)dentry_blk + nameoff;
+
+- /* the last dirent in the block? */
+- if (de + 1 >= end)
+- de_namelen = strnlen(de_name, maxsize - nameoff);
+- else
++ /* non-trailing dirent in the directory block? */
++ if (de + 1 < end)
+ de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
++ else if (maxsize <= nameoff)
++ goto err_bogus;
++ else
++ de_namelen = strnlen(de_name, maxsize - nameoff);
+
+- /* a corrupted entry is found */
+- if (nameoff + de_namelen > maxsize ||
+- de_namelen > EROFS_NAME_LEN) {
+- erofs_err(dir->i_sb, "bogus dirent @ nid %llu",
+- EROFS_I(dir)->nid);
+- DBG_BUGON(1);
+- return -EFSCORRUPTED;
+- }
++ /* a corrupted entry is found (including negative namelen) */
++ if (!in_range32(de_namelen, 1, EROFS_NAME_LEN) ||
++ nameoff + de_namelen > maxsize)
++ goto err_bogus;
+
+ debug_one_dentry(d_type, de_name, de_namelen);
+ if (!dir_emit(ctx, de_name, de_namelen,
+@@ -62,6 +60,10 @@ static int erofs_fill_dentries(struct in
+ }
+ *ofs = maxsize;
+ return 0;
++err_bogus:
++ erofs_err(dir->i_sb, "bogus dirent @ nid %llu", EROFS_I(dir)->nid);
++ DBG_BUGON(1);
++ return -EFSCORRUPTED;
+ }
+
+ static int erofs_readdir(struct file *f, struct dir_context *ctx)
+@@ -95,8 +97,8 @@ static int erofs_readdir(struct file *f,
+
+ nameoff = le16_to_cpu(de->nameoff);
+
+- if (nameoff < sizeof(struct erofs_dirent) ||
+- nameoff >= PAGE_SIZE) {
++ if (!nameoff || nameoff >= PAGE_SIZE ||
++ (nameoff % sizeof(struct erofs_dirent))) {
+ erofs_err(dir->i_sb,
+ "invalid de[0].nameoff %u @ nid %llu",
+ nameoff, EROFS_I(dir)->nid);
--- /dev/null
+From stable+bounces-244954-greg=kroah.com@vger.kernel.org Sat May 9 18:22:53 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 May 2026 08:49:57 -0400
+Subject: erofs: fix unsigned underflow in z_erofs_lz4_handle_overlap()
+To: stable@vger.kernel.org
+Cc: Junrui Luo <moonafterrain@outlook.com>, Yuhao Jiang <danisjiang@gmail.com>, Gao Xiang <hsiangkao@linux.alibaba.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509124957.3382270-1-sashal@kernel.org>
+
+From: Junrui Luo <moonafterrain@outlook.com>
+
+[ Upstream commit 21e161de2dc660b1bb70ef5b156ab8e6e1cca3ab ]
+
+Some crafted images can have illegal (!partial_decoding &&
+m_llen < m_plen) extents, and the LZ4 inplace decompression path
+can be wrongly hit, but it cannot handle (outpages < inpages)
+properly: "outpages - inpages" wraps to a large value and
+the subsequent rq->out[] access reads past the decompressed_pages
+array.
+
+However, such crafted cases can correctly result in a corruption
+report in the normal LZ4 non-inplace path.
+
+Let's add an additional check to fix this for backporting.
+
+Reproducible image (base64-encoded gzipped blob):
+
+H4sIAJGR12kCA+3SPUoDQRgG4MkmkkZk8QRbRFIIi9hbpEjrHQI5ghfwCN5BLCzTGtLbBI+g
+dilSJo1CnIm7GEXFxhT6PDDwfrs73/ywIQD/1ePD4r7Ou6ETsrq4mu7XcWfj++Pb58nJU/9i
+PNtbjhan04/9GtX4qVYc814WDqt6FaX5s+ZwXXeq52lndT6IuVvlblytLMvh4Gzwaf90nsvz
+2DF/21+20T/ldgp5s1jXRaN4t/8izsy/OUB6e/Qa79r+JwAAAAAAAL52vQVuGQAAAP6+my1w
+ywAAAAAAAADwu14ATsEYtgBQAAA=
+
+$ mount -t erofs -o cache_strategy=disabled foo.erofs /mnt
+$ dd if=/mnt/data of=/dev/null bs=4096 count=1
+
+Fixes: 598162d05080 ("erofs: support decompress big pcluster for lz4 backend")
+Reported-by: Yuhao Jiang <danisjiang@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Junrui Luo <moonafterrain@outlook.com>
+Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+[ renamed `rq->outpages`/`rq->inpages` to `nrpages_out`/`nrpages_in` and inverted the check to `nrpages_out < nrpages_in` on the existing `goto docopy` chain ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/erofs/decompressor.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/erofs/decompressor.c
++++ b/fs/erofs/decompressor.c
+@@ -140,6 +140,7 @@ static void *z_erofs_handle_inplace_io(s
+
+ if (rq->inplace_io) {
+ if (rq->partial_decoding || !support_0padding ||
++ nrpages_out < nrpages_in ||
+ ofull - oend < LZ4_DECOMPRESS_INPLACE_MARGIN(inputsize))
+ goto docopy;
+
--- /dev/null
+From stable+bounces-240661-greg=kroah.com@vger.kernel.org Fri Apr 24 18:58:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 09:28:31 -0400
+Subject: f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally
+To: stable@vger.kernel.org
+Cc: Chao Yu <chao@kernel.org>, stable@kernel.org, syzbot+62538b67389ee582837a@syzkaller.appspotmail.com, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424132831.1946653-1-sashal@kernel.org>
+
+From: Chao Yu <chao@kernel.org>
+
+[ Upstream commit 6af249c996f7d73a3435f9e577956fa259347d18 ]
+
+Syzbot reported a f2fs bug as below:
+
+------------[ cut here ]------------
+kernel BUG at fs/f2fs/segment.c:1900!
+Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
+CPU: 1 UID: 0 PID: 6527 Comm: syz.5.110 Not tainted syzkaller #0 PREEMPT_{RT,(full)}
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
+RIP: 0010:f2fs_issue_discard_timeout+0x59b/0x5a0 fs/f2fs/segment.c:1900
+Code: d9 80 e1 07 80 c1 03 38 c1 0f 8c d6 fe ff ff 48 89 df e8 a8 5e fa fd e9 c9 fe ff ff e8 4e 46 94 fd 90 0f 0b e8 46 46 94 fd 90 <0f> 0b 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3
+RSP: 0018:ffffc9000494f940 EFLAGS: 00010283
+RAX: ffffffff843009ca RBX: 0000000000000001 RCX: 0000000000080000
+RDX: ffffc9001ca78000 RSI: 00000000000029f3 RDI: 00000000000029f4
+RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
+R10: dffffc0000000000 R11: ffffed100893a431 R12: 1ffff1100893a430
+R13: 1ffff1100c2b702c R14: dffffc0000000000 R15: ffff8880449d2160
+FS: 00007ffa35fed6c0(0000) GS:ffff88812643d000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007f2b68634000 CR3: 0000000039f62000 CR4: 00000000003526f0
+Call Trace:
+ <TASK>
+ __f2fs_remount fs/f2fs/super.c:2960 [inline]
+ f2fs_reconfigure+0x108a/0x1710 fs/f2fs/super.c:5443
+ reconfigure_super+0x227/0x8a0 fs/super.c:1080
+ do_remount fs/namespace.c:3391 [inline]
+ path_mount+0xdc5/0x10e0 fs/namespace.c:4151
+ do_mount fs/namespace.c:4172 [inline]
+ __do_sys_mount fs/namespace.c:4361 [inline]
+ __se_sys_mount+0x31d/0x420 fs/namespace.c:4338
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7ffa37dbda0a
+
+The root cause is there will be race condition in between f2fs_ioc_fitrim()
+and f2fs_remount():
+
+- f2fs_remount - f2fs_ioc_fitrim
+ - f2fs_issue_discard_timeout
+ - __issue_discard_cmd
+ - __drop_discard_cmd
+ - __wait_all_discard_cmd
+ - f2fs_trim_fs
+ - f2fs_write_checkpoint
+ - f2fs_clear_prefree_segments
+ - f2fs_issue_discard
+ - __issue_discard_async
+ - __queue_discard_cmd
+ - __update_discard_tree_range
+ - __insert_discard_cmd
+ - __create_discard_cmd
+ : atomic_inc(&dcc->discard_cmd_cnt);
+ - sanity check on dcc->discard_cmd_cnt (expect discard_cmd_cnt to be zero)
+
+This will only happen when fitrim races w/ remount rw, if we remount to
+readonly filesystem, remount will wait until mnt_pcp.mnt_writers to zero,
+that means fitrim is not in process at that time.
+
+Cc: stable@kernel.org
+Fixes: 2482c4325dfe ("f2fs: detect bug_on in f2fs_wait_discard_bios")
+Reported-by: syzbot+62538b67389ee582837a@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/linux-f2fs-devel/69b07d7c.050a0220.8df7.09a1.GAE@google.com
+Signed-off-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ Different function signatures ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/f2fs.h | 2 +-
+ fs/f2fs/segment.c | 6 +++---
+ fs/f2fs/super.c | 9 +++++++--
+ 3 files changed, 11 insertions(+), 6 deletions(-)
+
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -3467,7 +3467,7 @@ bool f2fs_is_checkpointed_data(struct f2
+ int f2fs_start_discard_thread(struct f2fs_sb_info *sbi);
+ void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi);
+ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi);
+-bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi);
++bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check);
+ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
+ struct cp_control *cpc);
+ void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi);
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -1741,7 +1741,7 @@ void f2fs_stop_discard_thread(struct f2f
+ }
+
+ /* This comes from f2fs_put_super */
+-bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
++bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check)
+ {
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+ struct discard_policy dpolicy;
+@@ -1755,7 +1755,7 @@ bool f2fs_issue_discard_timeout(struct f
+ /* just to make sure there is no pending discard commands */
+ __wait_all_discard_cmd(sbi, NULL);
+
+- f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt));
++ f2fs_bug_on(sbi, need_check && atomic_read(&dcc->discard_cmd_cnt));
+ return dropped;
+ }
+
+@@ -2197,7 +2197,7 @@ static void destroy_discard_cmd_control(
+ * fill_super(), it needs to give a chance to handle them.
+ */
+ if (unlikely(atomic_read(&dcc->discard_cmd_cnt)))
+- f2fs_issue_discard_timeout(sbi);
++ f2fs_issue_discard_timeout(sbi, true);
+
+ kfree(dcc);
+ SM_I(sbi)->dcc_info = NULL;
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1600,7 +1600,7 @@ static void f2fs_put_super(struct super_
+ }
+
+ /* be sure to wait for any on-going discard commands */
+- dropped = f2fs_issue_discard_timeout(sbi);
++ dropped = f2fs_issue_discard_timeout(sbi, true);
+
+ if ((f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) &&
+ !sbi->discard_blks && !dropped) {
+@@ -2409,8 +2409,13 @@ static int f2fs_remount(struct super_blo
+ } else {
+ dcc = SM_I(sbi)->dcc_info;
+ f2fs_stop_discard_thread(sbi);
++ /*
++ * f2fs_ioc_fitrim() won't race w/ "remount ro"
++ * so it's safe to check discard_cmd_cnt in
++ * f2fs_issue_discard_timeout().
++ */
+ if (atomic_read(&dcc->discard_cmd_cnt))
+- f2fs_issue_discard_timeout(sbi);
++ f2fs_issue_discard_timeout(sbi, *flags & SB_RDONLY);
+ need_restart_discard = true;
+ }
+ }
--- /dev/null
+From stable+bounces-240930-greg=kroah.com@vger.kernel.org Fri Apr 24 19:15:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 09:43:22 -0400
+Subject: f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
+To: stable@vger.kernel.org
+Cc: Yongpeng Yang <yangyongpeng@xiaomi.com>, stable@kernel.org, syzbot+6e4cb1cac5efc96ea0ca@syzkaller.appspotmail.com, Chao Yu <chao@kernel.org>, Jaegeuk Kim <jaegeuk@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424134323.2017162-1-sashal@kernel.org>
+
+From: Yongpeng Yang <yangyongpeng@xiaomi.com>
+
+[ Upstream commit 2d9c4a4ed4eef1f82c5b16b037aee8bad819fd53 ]
+
+The xfstests case "generic/107" and syzbot have both reported a NULL
+pointer dereference.
+
+The concurrent scenario that triggers the panic is as follows:
+
+F2FS_WB_CP_DATA write callback umount
+ - f2fs_write_checkpoint
+ - f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA)
+- blk_mq_end_request
+ - bio_endio
+ - f2fs_write_end_io
+ : dec_page_count(sbi, F2FS_WB_CP_DATA)
+ : wake_up(&sbi->cp_wait)
+ - kill_f2fs_super
+ - kill_block_super
+ - f2fs_put_super
+ : iput(sbi->node_inode)
+ : sbi->node_inode = NULL
+ : f2fs_in_warm_node_list
+ - is_node_folio // sbi->node_inode is NULL and panic
+
+The root cause is that f2fs_put_super() calls iput(sbi->node_inode) and
+sets sbi->node_inode to NULL after sbi->nr_pages[F2FS_WB_CP_DATA] is
+decremented to zero. As a result, f2fs_in_warm_node_list() may
+dereference a NULL node_inode when checking whether a folio belongs to
+the node inode, leading to a panic.
+
+This patch fixes the issue by calling f2fs_in_warm_node_list() before
+decrementing sbi->nr_pages[F2FS_WB_CP_DATA], thus preventing the
+use-after-free condition.
+
+Cc: stable@kernel.org
+Fixes: 50fa53eccf9f ("f2fs: fix to avoid broken of dnode block list")
+Reported-by: syzbot+6e4cb1cac5efc96ea0ca@syzkaller.appspotmail.com
+Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
+Reviewed-by: Chao Yu <chao@kernel.org>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[ folio => page ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/data.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -339,6 +339,8 @@ static void f2fs_write_end_io(struct bio
+
+ f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
+ page->index != nid_of_node(page));
++ if (f2fs_in_warm_node_list(sbi, page))
++ f2fs_del_fsync_node_entry(sbi, page);
+
+ dec_page_count(sbi, type);
+
+@@ -350,8 +352,6 @@ static void f2fs_write_end_io(struct bio
+ wq_has_sleeper(&sbi->cp_wait))
+ wake_up(&sbi->cp_wait);
+
+- if (f2fs_in_warm_node_list(sbi, page))
+- f2fs_del_fsync_node_entry(sbi, page);
+ clear_page_private_gcing(page);
+ end_page_writeback(page);
+ }
--- /dev/null
+From stable+bounces-244037-greg=kroah.com@vger.kernel.org Tue May 5 15:19:47 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 May 2026 05:49:37 -0400
+Subject: fbdev: defio: Disconnect deferred I/O from the lifetime of struct fb_info
+To: stable@vger.kernel.org
+Cc: Thomas Zimmermann <tzimmermann@suse.de>, Helge Deller <deller@gmx.de>, linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260505094937.506038-1-sashal@kernel.org>
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit 9ded47ad003f09a94b6a710b5c47f4aa5ceb7429 ]
+
+Hold state of deferred I/O in struct fb_deferred_io_state. Allocate an
+instance as part of initializing deferred I/O and remove it only after
+the final mapping has been closed. If the fb_info and the contained
+deferred I/O meanwhile goes away, clear struct fb_deferred_io_state.info
+to invalidate the mapping. Any access will then result in a SIGBUS
+signal.
+
+Fixes a long-standing problem, where a device hot-unplug happens while
+user space still has an active mapping of the graphics memory. The hot-
+unplug frees the instance of struct fb_info. Accessing the memory will
+operate on undefined state.
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Fixes: 60b59beafba8 ("fbdev: mm: Deferred IO support")
+Cc: Helge Deller <deller@gmx.de>
+Cc: linux-fbdev@vger.kernel.org
+Cc: dri-devel@lists.freedesktop.org
+Cc: stable@vger.kernel.org # v2.6.22+
+Signed-off-by: Helge Deller <deller@gmx.de>
+[ replaced `kzalloc_obj()` with `kzalloc(sizeof(*fbdefio_state), GFP_KERNEL)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/video/fbdev/core/fb_defio.c | 152 +++++++++++++++++++++++++++++++-----
+ include/linux/fb.h | 4
+ 2 files changed, 138 insertions(+), 18 deletions(-)
+
+--- a/drivers/video/fbdev/core/fb_defio.c
++++ b/drivers/video/fbdev/core/fb_defio.c
+@@ -23,6 +23,75 @@
+ #include <linux/rmap.h>
+ #include <linux/pagemap.h>
+
++/*
++ * struct fb_deferred_io_state
++ */
++
++struct fb_deferred_io_state {
++ struct kref ref;
++
++ struct mutex lock; /* mutex that protects the pageref list */
++ /* fields protected by lock */
++ struct fb_info *info;
++};
++
++static struct fb_deferred_io_state *fb_deferred_io_state_alloc(void)
++{
++ struct fb_deferred_io_state *fbdefio_state;
++
++ fbdefio_state = kzalloc(sizeof(*fbdefio_state), GFP_KERNEL);
++ if (!fbdefio_state)
++ return NULL;
++
++ kref_init(&fbdefio_state->ref);
++ mutex_init(&fbdefio_state->lock);
++
++ return fbdefio_state;
++}
++
++static void fb_deferred_io_state_release(struct fb_deferred_io_state *fbdefio_state)
++{
++ mutex_destroy(&fbdefio_state->lock);
++
++ kfree(fbdefio_state);
++}
++
++static void fb_deferred_io_state_get(struct fb_deferred_io_state *fbdefio_state)
++{
++ kref_get(&fbdefio_state->ref);
++}
++
++static void __fb_deferred_io_state_release(struct kref *ref)
++{
++ struct fb_deferred_io_state *fbdefio_state =
++ container_of(ref, struct fb_deferred_io_state, ref);
++
++ fb_deferred_io_state_release(fbdefio_state);
++}
++
++static void fb_deferred_io_state_put(struct fb_deferred_io_state *fbdefio_state)
++{
++ kref_put(&fbdefio_state->ref, __fb_deferred_io_state_release);
++}
++
++/*
++ * struct vm_operations_struct
++ */
++
++static void fb_deferred_io_vm_open(struct vm_area_struct *vma)
++{
++ struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data;
++
++ fb_deferred_io_state_get(fbdefio_state);
++}
++
++static void fb_deferred_io_vm_close(struct vm_area_struct *vma)
++{
++ struct fb_deferred_io_state *fbdefio_state = vma->vm_private_data;
++
++ fb_deferred_io_state_put(fbdefio_state);
++}
++
+ static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
+ {
+ void *screen_base = (void __force *) info->screen_base;
+@@ -93,17 +162,31 @@ static void fb_deferred_io_pageref_put(s
+ /* this is to find and return the vmalloc-ed fb pages */
+ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
+ {
++ struct fb_info *info;
+ unsigned long offset;
+ struct page *page;
+- struct fb_info *info = vmf->vma->vm_private_data;
++ vm_fault_t ret;
++ struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data;
++
++ mutex_lock(&fbdefio_state->lock);
++
++ info = fbdefio_state->info;
++ if (!info) {
++ ret = VM_FAULT_SIGBUS; /* our device is gone */
++ goto err_mutex_unlock;
++ }
+
+ offset = vmf->pgoff << PAGE_SHIFT;
+- if (offset >= info->fix.smem_len)
+- return VM_FAULT_SIGBUS;
++ if (offset >= info->fix.smem_len) {
++ ret = VM_FAULT_SIGBUS;
++ goto err_mutex_unlock;
++ }
+
+ page = fb_deferred_io_page(info, offset);
+- if (!page)
+- return VM_FAULT_SIGBUS;
++ if (!page) {
++ ret = VM_FAULT_SIGBUS;
++ goto err_mutex_unlock;
++ }
+
+ get_page(page);
+
+@@ -115,8 +198,14 @@ static vm_fault_t fb_deferred_io_fault(s
+ BUG_ON(!page->mapping);
+ page->index = vmf->pgoff; /* for page_mkclean() */
+
++ mutex_unlock(&fbdefio_state->lock);
++
+ vmf->page = page;
+ return 0;
++
++err_mutex_unlock:
++ mutex_unlock(&fbdefio_state->lock);
++ return ret;
+ }
+
+ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+@@ -143,8 +232,9 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
+ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf)
+ {
+ struct page *page = vmf->page;
+- struct fb_info *info = vmf->vma->vm_private_data;
+- struct fb_deferred_io *fbdefio = info->fbdefio;
++ struct fb_deferred_io_state *fbdefio_state = vmf->vma->vm_private_data;
++ struct fb_info *info;
++ struct fb_deferred_io *fbdefio;
+ struct fb_deferred_io_pageref *pageref;
+ unsigned long offset;
+ vm_fault_t ret;
+@@ -160,7 +250,15 @@ static vm_fault_t fb_deferred_io_mkwrite
+ file_update_time(vmf->vma->vm_file);
+
+ /* protect against the workqueue changing the page list */
+- mutex_lock(&fbdefio->lock);
++ mutex_lock(&fbdefio_state->lock);
++
++ info = fbdefio_state->info;
++ if (!info) {
++ ret = VM_FAULT_SIGBUS; /* our device is gone */
++ goto err_mutex_unlock;
++ }
++
++ fbdefio = info->fbdefio;
+
+ /* first write in this cycle, notify the driver */
+ if (fbdefio->first_io && list_empty(&fbdefio->pagereflist))
+@@ -182,18 +280,20 @@ static vm_fault_t fb_deferred_io_mkwrite
+ */
+ lock_page(pageref->page);
+
+- mutex_unlock(&fbdefio->lock);
++ mutex_unlock(&fbdefio_state->lock);
+
+ /* come back after delay to process the deferred IO */
+ schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+ return VM_FAULT_LOCKED;
+
+ err_mutex_unlock:
+- mutex_unlock(&fbdefio->lock);
++ mutex_unlock(&fbdefio_state->lock);
+ return ret;
+ }
+
+ static const struct vm_operations_struct fb_deferred_io_vm_ops = {
++ .open = fb_deferred_io_vm_open,
++ .close = fb_deferred_io_vm_close,
+ .fault = fb_deferred_io_fault,
+ .page_mkwrite = fb_deferred_io_mkwrite,
+ };
+@@ -215,7 +315,10 @@ int fb_deferred_io_mmap(struct fb_info *
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ if (!(info->flags & FBINFO_VIRTFB))
+ vma->vm_flags |= VM_IO;
+- vma->vm_private_data = info;
++ vma->vm_private_data = info->fbdefio_state;
++
++ fb_deferred_io_state_get(info->fbdefio_state); /* released in vma->vm_ops->close() */
++
+ return 0;
+ }
+
+@@ -225,9 +328,10 @@ static void fb_deferred_io_work(struct w
+ struct fb_info *info = container_of(work, struct fb_info, deferred_work.work);
+ struct fb_deferred_io_pageref *pageref, *next;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
++ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
+
+ /* here we mkclean the pages, then do all deferred IO */
+- mutex_lock(&fbdefio->lock);
++ mutex_lock(&fbdefio_state->lock);
+ list_for_each_entry(pageref, &fbdefio->pagereflist, list) {
+ struct page *cur = pageref->page;
+ lock_page(cur);
+@@ -242,12 +346,13 @@ static void fb_deferred_io_work(struct w
+ list_for_each_entry_safe(pageref, next, &fbdefio->pagereflist, list)
+ fb_deferred_io_pageref_put(pageref, info);
+
+- mutex_unlock(&fbdefio->lock);
++ mutex_unlock(&fbdefio_state->lock);
+ }
+
+ int fb_deferred_io_init(struct fb_info *info)
+ {
+ struct fb_deferred_io *fbdefio = info->fbdefio;
++ struct fb_deferred_io_state *fbdefio_state;
+ struct fb_deferred_io_pageref *pagerefs;
+ unsigned long npagerefs, i;
+ int ret;
+@@ -257,7 +362,11 @@ int fb_deferred_io_init(struct fb_info *
+ if (WARN_ON(!info->fix.smem_len))
+ return -EINVAL;
+
+- mutex_init(&fbdefio->lock);
++ fbdefio_state = fb_deferred_io_state_alloc();
++ if (!fbdefio_state)
++ return -ENOMEM;
++ fbdefio_state->info = info;
++
+ INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
+ INIT_LIST_HEAD(&fbdefio->pagereflist);
+ if (fbdefio->delay == 0) /* set a default of 1 s */
+@@ -276,10 +385,12 @@ int fb_deferred_io_init(struct fb_info *
+ info->npagerefs = npagerefs;
+ info->pagerefs = pagerefs;
+
++ info->fbdefio_state = fbdefio_state;
++
+ return 0;
+
+ err:
+- mutex_destroy(&fbdefio->lock);
++ fb_deferred_io_state_release(fbdefio_state);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(fb_deferred_io_init);
+@@ -320,11 +431,18 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_release
+
+ void fb_deferred_io_cleanup(struct fb_info *info)
+ {
+- struct fb_deferred_io *fbdefio = info->fbdefio;
++ struct fb_deferred_io_state *fbdefio_state = info->fbdefio_state;
+
+ fb_deferred_io_lastclose(info);
+
++ info->fbdefio_state = NULL;
++
++ mutex_lock(&fbdefio_state->lock);
++ fbdefio_state->info = NULL;
++ mutex_unlock(&fbdefio_state->lock);
++
++ fb_deferred_io_state_put(fbdefio_state);
++
+ kvfree(info->pagerefs);
+- mutex_destroy(&fbdefio->lock);
+ }
+ EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
+--- a/include/linux/fb.h
++++ b/include/linux/fb.h
+@@ -213,12 +213,13 @@ struct fb_deferred_io {
+ unsigned long delay;
+ bool sort_pagereflist; /* sort pagelist by offset */
+ int open_count; /* number of opened files; protected by fb_info lock */
+- struct mutex lock; /* mutex that protects the pageref list */
+ struct list_head pagereflist; /* list of pagerefs for touched pages */
+ /* callback */
+ void (*first_io)(struct fb_info *info);
+ void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
+ };
++
++struct fb_deferred_io_state;
+ #endif
+
+ /*
+@@ -480,6 +481,7 @@ struct fb_info {
+ unsigned long npagerefs;
+ struct fb_deferred_io_pageref *pagerefs;
+ struct fb_deferred_io *fbdefio;
++ struct fb_deferred_io_state *fbdefio_state;
+ #endif
+
+ const struct fb_ops *fbops;
--- /dev/null
+From stable+bounces-244872-greg=kroah.com@vger.kernel.org Sat May 9 06:43:11 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 21:12:59 -0400
+Subject: hfsplus: fix held lock freed on hfsplus_fill_super()
+To: stable@vger.kernel.org
+Cc: Zilin Guan <zilin@seu.edu.cn>, Viacheslav Dubeyko <slava@dubeyko.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509011259.2724832-2-sashal@kernel.org>
+
+From: Zilin Guan <zilin@seu.edu.cn>
+
+[ Upstream commit 90c500e4fd83fa33c09bc7ee23b6d9cc487ac733 ]
+
+hfsplus_fill_super() calls hfs_find_init() to initialize a search
+structure, which acquires tree->tree_lock. If the subsequent call to
+hfsplus_cat_build_key() fails, the function jumps to the out_put_root
+error label without releasing the lock. The later cleanup path then
+frees the tree data structure with the lock still held, triggering a
+held lock freed warning.
+
+Fix this by adding the missing hfs_find_exit(&fd) call before jumping
+to the out_put_root error label. This ensures that tree->tree_lock is
+properly released on the error path.
+
+The bug was originally detected on v6.13-rc1 using an experimental
+static analysis tool we are developing, and we have verified that the
+issue persists in the latest mainline kernel. The tool is specifically
+designed to detect memory management issues. It is currently under active
+development and not yet publicly available.
+
+We confirmed the bug by runtime testing under QEMU with x86_64 defconfig,
+lockdep enabled, and CONFIG_HFSPLUS_FS=y. To trigger the error path, we
+used GDB to dynamically shrink the max_unistr_len parameter to 1 before
+hfsplus_asc2uni() is called. This forces hfsplus_asc2uni() to naturally
+return -ENAMETOOLONG, which propagates to hfsplus_cat_build_key() and
+exercises the faulty error path. The following warning was observed
+during mount:
+
+ =========================
+ WARNING: held lock freed!
+ 7.0.0-rc3-00016-gb4f0dd314b39 #4 Not tainted
+ -------------------------
+ mount/174 is freeing memory ffff888103f92000-ffff888103f92fff, with a lock still held there!
+ ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0
+ 2 locks held by mount/174:
+ #0: ffff888103f960e0 (&type->s_umount_key#42/1){+.+.}-{4:4}, at: alloc_super.constprop.0+0x167/0xa40
+ #1: ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0
+
+ stack backtrace:
+ CPU: 2 UID: 0 PID: 174 Comm: mount Not tainted 7.0.0-rc3-00016-gb4f0dd314b39 #4 PREEMPT(lazy)
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x82/0xd0
+ debug_check_no_locks_freed+0x13a/0x180
+ kfree+0x16b/0x510
+ ? hfsplus_fill_super+0xcb4/0x18a0
+ hfsplus_fill_super+0xcb4/0x18a0
+ ? __pfx_hfsplus_fill_super+0x10/0x10
+ ? srso_return_thunk+0x5/0x5f
+ ? bdev_open+0x65f/0xc30
+ ? srso_return_thunk+0x5/0x5f
+ ? pointer+0x4ce/0xbf0
+ ? trace_contention_end+0x11c/0x150
+ ? __pfx_pointer+0x10/0x10
+ ? srso_return_thunk+0x5/0x5f
+ ? bdev_open+0x79b/0xc30
+ ? srso_return_thunk+0x5/0x5f
+ ? srso_return_thunk+0x5/0x5f
+ ? vsnprintf+0x6da/0x1270
+ ? srso_return_thunk+0x5/0x5f
+ ? __mutex_unlock_slowpath+0x157/0x740
+ ? __pfx_vsnprintf+0x10/0x10
+ ? srso_return_thunk+0x5/0x5f
+ ? srso_return_thunk+0x5/0x5f
+ ? mark_held_locks+0x49/0x80
+ ? srso_return_thunk+0x5/0x5f
+ ? srso_return_thunk+0x5/0x5f
+ ? irqentry_exit+0x17b/0x5e0
+ ? trace_irq_disable.constprop.0+0x116/0x150
+ ? __pfx_hfsplus_fill_super+0x10/0x10
+ ? __pfx_hfsplus_fill_super+0x10/0x10
+ get_tree_bdev_flags+0x302/0x580
+ ? __pfx_get_tree_bdev_flags+0x10/0x10
+ ? vfs_parse_fs_qstr+0x129/0x1a0
+ ? __pfx_vfs_parse_fs_qstr+0x3/0x10
+ vfs_get_tree+0x89/0x320
+ fc_mount+0x10/0x1d0
+ path_mount+0x5c5/0x21c0
+ ? __pfx_path_mount+0x10/0x10
+ ? trace_irq_enable.constprop.0+0x116/0x150
+ ? trace_irq_enable.constprop.0+0x116/0x150
+ ? srso_return_thunk+0x5/0x5f
+ ? srso_return_thunk+0x5/0x5f
+ ? kmem_cache_free+0x307/0x540
+ ? user_path_at+0x51/0x60
+ ? __x64_sys_mount+0x212/0x280
+ ? srso_return_thunk+0x5/0x5f
+ __x64_sys_mount+0x212/0x280
+ ? __pfx___x64_sys_mount+0x10/0x10
+ ? srso_return_thunk+0x5/0x5f
+ ? trace_irq_enable.constprop.0+0x116/0x150
+ ? srso_return_thunk+0x5/0x5f
+ do_syscall_64+0x111/0x680
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+ RIP: 0033:0x7ffacad55eae
+ Code: 48 8b 0d 85 1f 0f 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 00 8
+ RSP: 002b:00007fff1ab55718 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
+ RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ffacad55eae
+ RDX: 000055740c64e5b0 RSI: 000055740c64e630 RDI: 000055740c651ab0
+ RBP: 000055740c64e380 R08: 0000000000000000 R09: 0000000000000001
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 000055740c64e5b0 R14: 000055740c651ab0 R15: 000055740c64e380
+ </TASK>
+
+After applying this patch, the warning no longer appears.
+
+Fixes: 89ac9b4d3d1a ("hfsplus: fix longname handling")
+CC: stable@vger.kernel.org
+Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
+Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Tested-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/hfsplus/super.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/hfsplus/super.c
++++ b/fs/hfsplus/super.c
+@@ -539,8 +539,10 @@ static int hfsplus_fill_super(struct sup
+ if (err)
+ goto out_put_root;
+ err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
+- if (unlikely(err < 0))
++ if (unlikely(err < 0)) {
++ hfs_find_exit(&fd);
+ goto out_put_root;
++ }
+ if (!hfsplus_brec_read_cat(&fd, &entry)) {
+ hfs_find_exit(&fd);
+ if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
--- /dev/null
+From stable+bounces-244871-greg=kroah.com@vger.kernel.org Sat May 9 06:43:07 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 21:12:58 -0400
+Subject: hfsplus: fix uninit-value by validating catalog record size
+To: stable@vger.kernel.org
+Cc: Deepanshu Kartikey <kartikey406@gmail.com>, syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com, Viacheslav Dubeyko <slava@dubeyko.com>, Charalampos Mitrodimas <charmitro@posteo.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509011259.2724832-1-sashal@kernel.org>
+
+From: Deepanshu Kartikey <kartikey406@gmail.com>
+
+[ Upstream commit b6b592275aeff184aa82fcf6abccd833fb71b393 ]
+
+Syzbot reported a KMSAN uninit-value issue in hfsplus_strcasecmp(). The
+root cause is that hfs_brec_read() doesn't validate that the on-disk
+record size matches the expected size for the record type being read.
+
+When mounting a corrupted filesystem, hfs_brec_read() may read less data
+than expected. For example, when reading a catalog thread record, the
+debug output showed:
+
+ HFSPLUS_BREC_READ: rec_len=520, fd->entrylength=26
+ HFSPLUS_BREC_READ: WARNING - entrylength (26) < rec_len (520) - PARTIAL READ!
+
+hfs_brec_read() only validates that entrylength is not greater than the
+buffer size, but doesn't check if it's less than expected. It successfully
+reads 26 bytes into a 520-byte structure and returns success, leaving 494
+bytes uninitialized.
+
+This uninitialized data in tmp.thread.nodeName then gets copied by
+hfsplus_cat_build_key_uni() and used by hfsplus_strcasecmp(), triggering
+the KMSAN warning when the uninitialized bytes are used as array indices
+in case_fold().
+
+Fix by introducing hfsplus_brec_read_cat() wrapper that:
+1. Calls hfs_brec_read() to read the data
+2. Validates the record size based on the type field:
+ - Fixed size for folder and file records
+ - Variable size for thread records (depends on string length)
+3. Returns -EIO if size doesn't match expected
+
+For thread records, check against HFSPLUS_MIN_THREAD_SZ before reading
+nodeName.length to avoid reading uninitialized data at call sites that
+don't zero-initialize the entry structure.
+
+Also initialize the tmp variable in hfsplus_find_cat() as defensive
+programming to ensure no uninitialized data even if validation is
+bypassed.
+
+Reported-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=d80abb5b890d39261e72
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com
+Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Tested-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Suggested-by: Charalampos Mitrodimas <charmitro@posteo.net>
+Link: https://lore.kernel.org/all/20260120051114.1281285-1-kartikey406@gmail.com/ [v1]
+Link: https://lore.kernel.org/all/20260121063109.1830263-1-kartikey406@gmail.com/ [v2]
+Link: https://lore.kernel.org/all/20260212014233.2422046-1-kartikey406@gmail.com/ [v3]
+Link: https://lore.kernel.org/all/20260214002100.436125-1-kartikey406@gmail.com/T/ [v4]
+Link: https://lore.kernel.org/all/20260221061626.15853-1-kartikey406@gmail.com/T/ [v5]
+Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
+Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Link: https://lore.kernel.org/r/20260307010302.41547-1-kartikey406@gmail.com
+Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
+Stable-dep-of: 90c500e4fd83 ("hfsplus: fix held lock freed on hfsplus_fill_super()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/hfsplus/bfind.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/hfsplus/catalog.c | 4 +--
+ fs/hfsplus/dir.c | 2 -
+ fs/hfsplus/hfsplus_fs.h | 9 ++++++++
+ fs/hfsplus/super.c | 2 -
+ 5 files changed, 64 insertions(+), 4 deletions(-)
+
+--- a/fs/hfsplus/bfind.c
++++ b/fs/hfsplus/bfind.c
+@@ -287,3 +287,54 @@ out:
+ fd->bnode = bnode;
+ return res;
+ }
++
++/**
++ * hfsplus_brec_read_cat - read and validate a catalog record
++ * @fd: find data structure
++ * @entry: pointer to catalog entry to read into
++ *
++ * Reads a catalog record and validates its size matches the expected
++ * size based on the record type.
++ *
++ * Returns 0 on success, or negative error code on failure.
++ */
++int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry)
++{
++ int res;
++ u32 expected_size;
++
++ res = hfs_brec_read(fd, entry, sizeof(hfsplus_cat_entry));
++ if (res)
++ return res;
++
++ /* Validate catalog record size based on type */
++ switch (be16_to_cpu(entry->type)) {
++ case HFSPLUS_FOLDER:
++ expected_size = sizeof(struct hfsplus_cat_folder);
++ break;
++ case HFSPLUS_FILE:
++ expected_size = sizeof(struct hfsplus_cat_file);
++ break;
++ case HFSPLUS_FOLDER_THREAD:
++ case HFSPLUS_FILE_THREAD:
++ /* Ensure we have at least the fixed fields before reading nodeName.length */
++ if (fd->entrylength < HFSPLUS_MIN_THREAD_SZ) {
++ pr_err("thread record too short (got %u)\n", fd->entrylength);
++ return -EIO;
++ }
++ expected_size = hfsplus_cat_thread_size(&entry->thread);
++ break;
++ default:
++ pr_err("unknown catalog record type %d\n",
++ be16_to_cpu(entry->type));
++ return -EIO;
++ }
++
++ if (fd->entrylength != expected_size) {
++ pr_err("catalog record size mismatch (type %d, got %u, expected %u)\n",
++ be16_to_cpu(entry->type), fd->entrylength, expected_size);
++ return -EIO;
++ }
++
++ return 0;
++}
+--- a/fs/hfsplus/catalog.c
++++ b/fs/hfsplus/catalog.c
+@@ -194,12 +194,12 @@ static int hfsplus_fill_cat_thread(struc
+ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
+ struct hfs_find_data *fd)
+ {
+- hfsplus_cat_entry tmp;
++ hfsplus_cat_entry tmp = {0};
+ int err;
+ u16 type;
+
+ hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid);
+- err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry));
++ err = hfsplus_brec_read_cat(fd, &tmp);
+ if (err)
+ return err;
+
+--- a/fs/hfsplus/dir.c
++++ b/fs/hfsplus/dir.c
+@@ -49,7 +49,7 @@ static struct dentry *hfsplus_lookup(str
+ if (unlikely(err < 0))
+ goto fail;
+ again:
+- err = hfs_brec_read(&fd, &entry, sizeof(entry));
++ err = hfsplus_brec_read_cat(&fd, &entry);
+ if (err) {
+ if (err == -ENOENT) {
+ hfs_find_exit(&fd);
+--- a/fs/hfsplus/hfsplus_fs.h
++++ b/fs/hfsplus/hfsplus_fs.h
+@@ -533,6 +533,15 @@ int hfsplus_submit_bio(struct super_bloc
+ void **data, int op, int op_flags);
+ int hfsplus_read_wrapper(struct super_block *sb);
+
++static inline u32 hfsplus_cat_thread_size(const struct hfsplus_cat_thread *thread)
++{
++ return offsetof(struct hfsplus_cat_thread, nodeName) +
++ offsetof(struct hfsplus_unistr, unicode) +
++ be16_to_cpu(thread->nodeName.length) * sizeof(hfsplus_unichr);
++}
++
++int hfsplus_brec_read_cat(struct hfs_find_data *fd, hfsplus_cat_entry *entry);
++
+ /*
+ * time helpers: convert between 1904-base and 1970-base timestamps
+ *
+--- a/fs/hfsplus/super.c
++++ b/fs/hfsplus/super.c
+@@ -541,7 +541,7 @@ static int hfsplus_fill_super(struct sup
+ err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
+ if (unlikely(err < 0))
+ goto out_put_root;
+- if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
++ if (!hfsplus_brec_read_cat(&fd, &entry)) {
+ hfs_find_exit(&fd);
+ if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
+ err = -EIO;
--- /dev/null
+From 4f1ddce4042ea4b3d8a3d14d1b4745d408b68090 Mon Sep 17 00:00:00 2001
+From: Longxuan Yu <ylong030@ucr.edu>
+Date: Sun, 12 Apr 2026 16:38:20 +0800
+Subject: io_uring/poll: fix signed comparison in io_poll_get_ownership()
+
+From: Longxuan Yu <ylong030@ucr.edu>
+
+Commit 326941b22806cbf2df1fbfe902b7908b368cce42 usptream.
+
+io_poll_get_ownership() uses a signed comparison to check whether
+poll_refs has reached the threshold for the slowpath:
+
+ if (unlikely(atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
+
+atomic_read() returns int (signed). When IO_POLL_CANCEL_FLAG
+(BIT(31)) is set in poll_refs, the value becomes negative in
+signed arithmetic, so the >= 128 comparison always evaluates to
+false and the slowpath is never taken.
+
+Fix this by casting the atomic_read() result to unsigned int
+before the comparison, so that the cancel flag is treated as a
+large positive value and correctly triggers the slowpath.
+
+Fixes: a26a35e9019f ("io_uring: make poll refs more robust")
+Cc: stable@vger.kernel.org
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Longxuan Yu <ylong030@ucr.edu>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://patch.msgid.link/3a3508b08bcd7f1bc3beff848ae6e1d73d355043.1775965597.git.ylong030@ucr.edu
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/io_uring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -5525,7 +5525,7 @@ static bool io_poll_get_ownership_slowpa
+ */
+ static inline bool io_poll_get_ownership(struct io_kiocb *req)
+ {
+- if (unlikely(atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
++ if (unlikely((unsigned int)atomic_read(&req->poll_refs) >= IO_POLL_REF_BIAS))
+ return io_poll_get_ownership_slowpath(req);
+ return !(atomic_fetch_inc(&req->poll_refs) & IO_POLL_REF_MASK);
+ }
--- /dev/null
+From c5794709bc9105935dbedef8b9cf9c06f2b559fa Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Tue, 17 Feb 2026 20:28:29 -0800
+Subject: ksmbd: Compare MACs in constant time
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit c5794709bc9105935dbedef8b9cf9c06f2b559fa upstream.
+
+To prevent timing attacks, MAC comparisons need to be constant-time.
+Replace the memcmp() with the correct function, crypto_memneq().
+
+Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Rajani Kantha <681739313@139.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ksmbd/Kconfig | 1 +
+ fs/ksmbd/auth.c | 4 +++-
+ fs/ksmbd/smb2pdu.c | 5 +++--
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/fs/ksmbd/Kconfig
++++ b/fs/ksmbd/Kconfig
+@@ -10,6 +10,7 @@ config SMB_SERVER
+ select CRYPTO_HMAC
+ select CRYPTO_ECB
+ select CRYPTO_LIB_DES
++ select CRYPTO_LIB_UTILS
+ select CRYPTO_SHA256
+ select CRYPTO_CMAC
+ select CRYPTO_SHA512
+--- a/fs/ksmbd/auth.c
++++ b/fs/ksmbd/auth.c
+@@ -13,6 +13,7 @@
+ #include <linux/xattr.h>
+ #include <crypto/hash.h>
+ #include <crypto/aead.h>
++#include <crypto/utils.h>
+ #include <linux/random.h>
+ #include <linux/scatterlist.h>
+
+@@ -281,7 +282,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn
+ goto out;
+ }
+
+- if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0)
++ if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
++ CIFS_HMAC_MD5_HASH_SIZE))
+ rc = -EINVAL;
+ out:
+ if (ctx)
+--- a/fs/ksmbd/smb2pdu.c
++++ b/fs/ksmbd/smb2pdu.c
+@@ -4,6 +4,7 @@
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
+ */
+
++#include <crypto/utils.h>
+ #include <linux/inetdevice.h>
+ #include <net/addrconf.h>
+ #include <linux/syscalls.h>
+@@ -8440,7 +8441,7 @@ int smb2_check_sign_req(struct ksmbd_wor
+ signature))
+ return 0;
+
+- if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
++ if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
+ pr_err("bad smb2 signature\n");
+ return 0;
+ }
+@@ -8528,7 +8529,7 @@ int smb3_check_sign_req(struct ksmbd_wor
+ if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature))
+ return 0;
+
+- if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
++ if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
+ pr_err("bad smb2 signature\n");
+ return 0;
+ }
--- /dev/null
+From stable+bounces-241014-greg=kroah.com@vger.kernel.org Fri Apr 24 22:57:03 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 13:25:12 -0400
+Subject: ksmbd: require minimum ACE size in smb_check_perm_dacl()
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424172512.2372287-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit d07b26f39246a82399661936dd0c853983cfade7 ]
+
+Both ACE-walk loops in smb_check_perm_dacl() only guard against an
+under-sized remaining buffer, not against an ACE whose declared
+`ace->size` is smaller than the struct it claims to describe:
+
+ if (offsetof(struct smb_ace, access_req) > aces_size)
+ break;
+ ace_size = le16_to_cpu(ace->size);
+ if (ace_size > aces_size)
+ break;
+
+The first check only requires the 4-byte ACE header to be in bounds;
+it does not require access_req (4 bytes at offset 4) to be readable.
+An attacker who has set a crafted DACL on a file they own can declare
+ace->size == 4 with aces_size == 4, pass both checks, and then
+
+ granted |= le32_to_cpu(ace->access_req); /* upper loop */
+ compare_sids(&sid, &ace->sid); /* lower loop */
+
+reads access_req at offset 4 (OOB by up to 4 bytes) and ace->sid at
+offset 8 (OOB by up to CIFS_SID_BASE_SIZE + SID_MAX_SUB_AUTHORITIES
+* 4 bytes).
+
+Tighten both loops to require
+
+ ace_size >= offsetof(struct smb_ace, sid) + CIFS_SID_BASE_SIZE
+
+which is the smallest valid on-wire ACE layout (4-byte header +
+4-byte access_req + 8-byte sid base with zero sub-auths). Also
+reject ACEs whose sid.num_subauth exceeds SID_MAX_SUB_AUTHORITIES
+before letting compare_sids() dereference sub_auth[] entries.
+
+parse_sec_desc() already enforces an equivalent check (lines 441-448);
+smb_check_perm_dacl() simply grew weaker validation over time.
+
+Reachability: authenticated SMB client with permission to set an ACL
+on a file. On a subsequent CREATE against that file, the kernel
+walks the stored DACL via smb_check_perm_dacl() and triggers the
+OOB read. Not pre-auth, and the OOB read is not reflected to the
+attacker, but KASAN reports and kernel state corruption are
+possible.
+
+Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+[ changed le16_to_cpu to le32_to_cpu for num_aces field which is __le32 ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ksmbd/smbacl.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/fs/ksmbd/smbacl.c
++++ b/fs/ksmbd/smbacl.c
+@@ -1265,10 +1265,13 @@ int smb_check_perm_dacl(struct ksmbd_con
+ ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+ aces_size = acl_size - sizeof(struct smb_acl);
+ for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+- if (offsetof(struct smb_ace, access_req) > aces_size)
++ if (offsetof(struct smb_ace, sid) +
++ aces_size < CIFS_SID_BASE_SIZE)
+ break;
+ ace_size = le16_to_cpu(ace->size);
+- if (ace_size > aces_size)
++ if (ace_size > aces_size ||
++ ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+ aces_size -= ace_size;
+ granted |= le32_to_cpu(ace->access_req);
+@@ -1286,13 +1289,19 @@ int smb_check_perm_dacl(struct ksmbd_con
+ ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+ aces_size = acl_size - sizeof(struct smb_acl);
+ for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+- if (offsetof(struct smb_ace, access_req) > aces_size)
++ if (offsetof(struct smb_ace, sid) +
++ aces_size < CIFS_SID_BASE_SIZE)
+ break;
+ ace_size = le16_to_cpu(ace->size);
+- if (ace_size > aces_size)
++ if (ace_size > aces_size ||
++ ace_size < offsetof(struct smb_ace, sid) +
++ CIFS_SID_BASE_SIZE)
+ break;
+ aces_size -= ace_size;
+
++ if (ace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
++ break;
++
+ if (!compare_sids(&sid, &ace->sid) ||
+ !compare_sids(&sid_unix_NFS_mode, &ace->sid)) {
+ found = 1;
--- /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/mpi/mpicoder.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/lib/mpi/mpicoder.c
++++ b/lib/mpi/mpicoder.c
+@@ -453,7 +453,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 stable+bounces-242572-greg=kroah.com@vger.kernel.org Sat May 2 07:42:26 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 22:12:21 -0400
+Subject: media: rc: igorplugusb: heed coherency rules
+To: stable@vger.kernel.org
+Cc: Oliver Neukum <oneukum@suse.com>, Sean Young <sean@mess.org>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260502021221.4166866-1-sashal@kernel.org>
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit eac69475b01fe1e861dfe3960b57fa95671c132e ]
+
+In a control request, the USB request structure
+can be subject to DMA on some HCs. Hence it must obey
+the rules for DMA coherency. Allocate it separately.
+
+Fixes: b1c97193c6437 ("[media] rc: port IgorPlug-USB to rc-core")
+Cc: stable@vger.kernel.org
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+[ replaced kzalloc_obj() with kzalloc(sizeof(*ir->request), GFP_KERNEL) ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/rc/igorplugusb.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/media/rc/igorplugusb.c
++++ b/drivers/media/rc/igorplugusb.c
+@@ -14,6 +14,7 @@
+ #include <linux/device.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/slab.h>
+ #include <linux/usb.h>
+ #include <linux/usb/input.h>
+ #include <media/rc-core.h>
+@@ -34,7 +35,7 @@ struct igorplugusb {
+ struct device *dev;
+
+ struct urb *urb;
+- struct usb_ctrlrequest request;
++ struct usb_ctrlrequest *request;
+
+ struct timer_list timer;
+
+@@ -123,7 +124,7 @@ static void igorplugusb_cmd(struct igorp
+ {
+ int ret;
+
+- ir->request.bRequest = cmd;
++ ir->request->bRequest = cmd;
+ ir->urb->transfer_flags = 0;
+ ret = usb_submit_urb(ir->urb, GFP_ATOMIC);
+ if (ret)
+@@ -165,13 +166,17 @@ static int igorplugusb_probe(struct usb_
+ if (!ir)
+ return -ENOMEM;
+
++ ir->request = kzalloc(sizeof(*ir->request), GFP_KERNEL);
++ if (!ir->request)
++ goto fail;
++
+ ir->dev = &intf->dev;
+
+ timer_setup(&ir->timer, igorplugusb_timer, 0);
+
+- ir->request.bRequest = GET_INFRACODE;
+- ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
+- ir->request.wLength = cpu_to_le16(sizeof(ir->buf_in));
++ ir->request->bRequest = GET_INFRACODE;
++ ir->request->bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
++ ir->request->wLength = cpu_to_le16(sizeof(ir->buf_in));
+
+ ir->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ir->urb)
+@@ -223,6 +228,7 @@ fail:
+ rc_free_device(ir->rc);
+ usb_free_urb(ir->urb);
+ del_timer(&ir->timer);
++ kfree(ir->request);
+
+ return ret;
+ }
+@@ -236,6 +242,7 @@ static void igorplugusb_disconnect(struc
+ usb_set_intfdata(intf, NULL);
+ usb_kill_urb(ir->urb);
+ usb_free_urb(ir->urb);
++ kfree(ir->request);
+ }
+
+ static const struct usb_device_id igorplugusb_table[] = {
--- /dev/null
+From stable+bounces-242479-greg=kroah.com@vger.kernel.org Fri May 1 22:58:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 13:27:52 -0400
+Subject: media: rc: ttusbir: respect DMA coherency rules
+To: stable@vger.kernel.org
+Cc: Oliver Neukum <oneukum@suse.com>, Sean Young <sean@mess.org>, Hans Verkuil <hverkuil+cisco@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501172752.3765703-1-sashal@kernel.org>
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit 50acaad3d202c064779db8dc3d010007347f59c7 ]
+
+Buffers must not share a cache line with other data structures.
+Allocate separately.
+
+Fixes: 0938069fa0897 ("[media] rc: Add support for the TechnoTrend USB IR Receiver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+[ kept kzalloc(sizeof(*tt), GFP_KERNEL) instead of kzalloc_obj() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/media/rc/ttusbir.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/media/rc/ttusbir.c
++++ b/drivers/media/rc/ttusbir.c
+@@ -32,7 +32,7 @@ struct ttusbir {
+
+ struct led_classdev led;
+ struct urb *bulk_urb;
+- uint8_t bulk_buffer[5];
++ u8 *bulk_buffer;
+ int bulk_out_endp, iso_in_endp;
+ bool led_on, is_led_on;
+ atomic_t led_complete;
+@@ -188,13 +188,16 @@ static int ttusbir_probe(struct usb_inte
+ struct rc_dev *rc;
+ int i, j, ret;
+ int altsetting = -1;
++ u8 *buffer;
+
+ tt = kzalloc(sizeof(*tt), GFP_KERNEL);
++ buffer = kzalloc(5, GFP_KERNEL);
+ rc = rc_allocate_device(RC_DRIVER_IR_RAW);
+- if (!tt || !rc) {
++ if (!tt || !rc || buffer) {
+ ret = -ENOMEM;
+ goto out;
+ }
++ tt->bulk_buffer = buffer;
+
+ /* find the correct alt setting */
+ for (i = 0; i < intf->num_altsetting && altsetting == -1; i++) {
+@@ -283,8 +286,8 @@ static int ttusbir_probe(struct usb_inte
+ tt->bulk_buffer[3] = 0x01;
+
+ usb_fill_bulk_urb(tt->bulk_urb, tt->udev, usb_sndbulkpipe(tt->udev,
+- tt->bulk_out_endp), tt->bulk_buffer, sizeof(tt->bulk_buffer),
+- ttusbir_bulk_complete, tt);
++ tt->bulk_out_endp), tt->bulk_buffer, 5,
++ ttusbir_bulk_complete, tt);
+
+ tt->led.name = "ttusbir:green:power";
+ tt->led.default_trigger = "rc-feedback";
+@@ -353,6 +356,7 @@ out:
+ kfree(tt);
+ }
+ rc_free_device(rc);
++ kfree(buffer);
+
+ return ret;
+ }
+@@ -375,6 +379,7 @@ static void ttusbir_disconnect(struct us
+ }
+ usb_kill_urb(tt->bulk_urb);
+ usb_free_urb(tt->bulk_urb);
++ kfree(tt->bulk_buffer);
+ usb_set_intfdata(intf, NULL);
+ kfree(tt);
+ }
--- /dev/null
+From stable+bounces-244082-greg=kroah.com@vger.kernel.org Tue May 5 16:03:31 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 May 2026 06:18:15 -0400
+Subject: mmc: sdhci-of-dwcmshc: Disable clock before DLL configuration
+To: stable@vger.kernel.org
+Cc: Shawn Lin <shawn.lin@rock-chips.com>, Adrian Hunter <adrian.hunter@intel.com>, Ulf Hansson <ulf.hansson@linaro.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260505101815.586456-1-sashal@kernel.org>
+
+From: Shawn Lin <shawn.lin@rock-chips.com>
+
+[ Upstream commit 6546a49bbe656981d99a389195560999058c89c4 ]
+
+According to the ASIC design recommendations, the clock must be
+disabled before operating the DLL to prevent glitches that could
+affect the internal digital logic. In extreme cases, failing to
+do so may cause the controller to malfunction completely.
+
+Adds a step to disable the clock before DLL configuration and
+re-enables it at the end.
+
+Fixes: 08f3dff799d4 ("mmc: sdhci-of-dwcmshc: add rockchip platform support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+[ dropped HS200/HS400 block and BIT(4) line, converted the single `return` in `if (clock <= 400000)` to `goto enable_clk` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mmc/host/sdhci-of-dwcmshc.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
+@@ -213,10 +213,13 @@ static void dwcmshc_rk3568_set_clock(str
+ extra &= ~BIT(0);
+ sdhci_writel(host, extra, reg);
+
++ /* Disable clock while config DLL */
++ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
++
+ if (clock <= 400000) {
+ /* Disable DLL to reset sample clock */
+ sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
+- return;
++ goto enable_clk;
+ }
+
+ /* Reset DLL */
+@@ -234,7 +237,7 @@ static void dwcmshc_rk3568_set_clock(str
+ 500 * USEC_PER_MSEC);
+ if (err) {
+ dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
+- return;
++ goto enable_clk;
+ }
+
+ extra = 0x1 << 16 | /* tune clock stop en */
+@@ -255,6 +258,16 @@ static void dwcmshc_rk3568_set_clock(str
+ DLL_STRBIN_TAPNUM_DEFAULT |
+ DLL_STRBIN_TAPNUM_FROM_SW;
+ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
++
++enable_clk:
++ /*
++ * The sdclk frequency select bits in SDHCI_CLOCK_CONTROL are not functional
++ * on Rockchip's SDHCI implementation. Instead, the clock frequency is fully
++ * controlled via external clk provider by calling clk_set_rate(). Consequently,
++ * passing 0 to sdhci_enable_clk() only re-enables the already-configured clock,
++ * which matches the hardware's actual behavior.
++ */
++ sdhci_enable_clk(host, 0);
+ }
+
+ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
--- /dev/null
+From stable+bounces-242570-greg=kroah.com@vger.kernel.org Sat May 2 07:42:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 22:11:53 -0400
+Subject: mtd: docg3: Convert to platform remove callback returning void
+To: stable@vger.kernel.org
+Cc: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>, "Miquel Raynal" <miquel.raynal@bootlin.com>, "Tudor Ambarus" <tudor.ambarus@linaro.org>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260502021154.4166366-1-sashal@kernel.org>
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit eb0cec77d534413a800ec20944a2b1e37cfecdcf ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new(), which already returns void. Eventually after all drivers
+are converted, .remove_new() will be renamed to .remove().
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Acked-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Link: https://lore.kernel.org/linux-mtd/20231008200143.196369-5-u.kleine-koenig@pengutronix.de
+Stable-dep-of: ca19808bc6fa ("mtd: docg3: fix use-after-free in docg3_release()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/devices/docg3.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
+index 27c08f22dec8c..25a7df6448028 100644
+--- a/drivers/mtd/devices/docg3.c
++++ b/drivers/mtd/devices/docg3.c
+@@ -2038,7 +2038,7 @@ static int __init docg3_probe(struct platform_device *pdev)
+ *
+ * Returns 0
+ */
+-static int docg3_release(struct platform_device *pdev)
++static void docg3_release(struct platform_device *pdev)
+ {
+ struct docg3_cascade *cascade = platform_get_drvdata(pdev);
+ struct docg3 *docg3 = cascade->floors[0]->priv;
+@@ -2050,7 +2050,6 @@ static int docg3_release(struct platform_device *pdev)
+ doc_release_device(cascade->floors[floor]);
+
+ bch_free(docg3->cascade->bch);
+- return 0;
+ }
+
+ #ifdef CONFIG_OF
+@@ -2068,7 +2067,7 @@ static struct platform_driver g3_driver = {
+ },
+ .suspend = docg3_suspend,
+ .resume = docg3_resume,
+- .remove = docg3_release,
++ .remove_new = docg3_release,
+ };
+
+ module_platform_driver_probe(g3_driver, docg3_probe);
+--
+2.53.0
+
--- /dev/null
+From stable+bounces-242571-greg=kroah.com@vger.kernel.org Sat May 2 07:42:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 22:11:54 -0400
+Subject: mtd: docg3: fix use-after-free in docg3_release()
+To: stable@vger.kernel.org
+Cc: James Kim <james010kim@gmail.com>, Miquel Raynal <miquel.raynal@bootlin.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260502021154.4166366-2-sashal@kernel.org>
+
+From: James Kim <james010kim@gmail.com>
+
+[ Upstream commit ca19808bc6fac7e29420d8508df569b346b3e339 ]
+
+In docg3_release(), the docg3 pointer is obtained from
+cascade->floors[0]->priv before the loop that calls
+doc_release_device() on each floor. doc_release_device() frees the
+docg3 struct via kfree(docg3) at line 1881. After the loop,
+docg3->cascade->bch dereferences the already-freed pointer.
+
+Fix this by accessing cascade->bch directly, which is equivalent
+since docg3->cascade points back to the same cascade struct, and
+is already available as a local variable. This also removes the
+now-unused docg3 local variable.
+
+Fixes: c8ae3f744ddc ("lib/bch: Rework a little bit the exported function names")
+Cc: stable@vger.kernel.org
+Signed-off-by: James Kim <james010kim@gmail.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/devices/docg3.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
+index 25a7df6448028..7de576404b14f 100644
+--- a/drivers/mtd/devices/docg3.c
++++ b/drivers/mtd/devices/docg3.c
+@@ -2041,7 +2041,6 @@ static int __init docg3_probe(struct platform_device *pdev)
+ static void docg3_release(struct platform_device *pdev)
+ {
+ struct docg3_cascade *cascade = platform_get_drvdata(pdev);
+- struct docg3 *docg3 = cascade->floors[0]->priv;
+ int floor;
+
+ doc_unregister_sysfs(pdev, cascade);
+@@ -2049,7 +2048,7 @@ static void docg3_release(struct platform_device *pdev)
+ if (cascade->floors[floor])
+ doc_release_device(cascade->floors[floor]);
+
+- bch_free(docg3->cascade->bch);
++ bch_free(cascade->bch);
+ }
+
+ #ifdef CONFIG_OF
+--
+2.53.0
+
--- /dev/null
+From stable+bounces-244833-greg=kroah.com@vger.kernel.org Sat May 9 02:48:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 17:18:16 -0400
+Subject: mtd: spi-nor: sst: Fix write enable before AAI sequence
+To: stable@vger.kernel.org
+Cc: Sanjaikumar V S <sanjaikumar.vs@dicortech.com>, Hendrik Donner <hd@os-cillation.de>, "Pratyush Yadav (Google)" <pratyush@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260508211816.1960968-1-sashal@kernel.org>
+
+From: Sanjaikumar V S <sanjaikumar.vs@dicortech.com>
+
+[ Upstream commit a0f64241d3566a49c0a9b33ba7ae458ae22003a9 ]
+
+When writing to SST flash starting at an odd address, a single byte is
+first programmed using the byte program (BP) command. After this
+operation completes, the flash hardware automatically clears the Write
+Enable Latch (WEL) bit.
+
+If an AAI (Auto Address Increment) word program sequence follows, it
+requires WEL to be set. Without re-enabling writes, the AAI sequence
+fails.
+
+Add spi_nor_write_enable() after the odd-address byte program when more
+data needs to be written. Use a local boolean for clarity.
+
+Fixes: b199489d37b2 ("mtd: spi-nor: add the framework for SPI NOR")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sanjaikumar V S <sanjaikumar.vs@dicortech.com>
+Tested-by: Hendrik Donner <hd@os-cillation.de>
+Reviewed-by: Hendrik Donner <hd@os-cillation.de>
+Signed-off-by: Pratyush Yadav (Google) <pratyush@kernel.org>
+[ kept inline `nor->program_opcode = SPINOR_OP_BP;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mtd/spi-nor/sst.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/mtd/spi-nor/sst.c
++++ b/drivers/mtd/spi-nor/sst.c
+@@ -112,6 +112,8 @@ static int sst_write(struct mtd_info *mt
+
+ /* Start write from odd address. */
+ if (to % 2) {
++ bool needs_write_enable = (len > 1);
++
+ nor->program_opcode = SPINOR_OP_BP;
+
+ /* write one byte. */
+@@ -125,6 +127,17 @@ static int sst_write(struct mtd_info *mt
+
+ to++;
+ actual++;
++
++ /*
++ * Byte program clears the write enable latch. If more
++ * data needs to be written using the AAI sequence,
++ * re-enable writes.
++ */
++ if (needs_write_enable) {
++ ret = spi_nor_write_enable(nor);
++ if (ret)
++ goto out;
++ }
+ }
+
+ /* Write out most of the data here. */
--- /dev/null
+From stable+bounces-243012-greg=kroah.com@vger.kernel.org Mon May 4 17:47:03 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 08:16:28 -0400
+Subject: net: bridge: use a stable FDB dst snapshot in RCU readers
+To: stable@vger.kernel.org
+Cc: Zhengchuan Liang <zcliangcn@gmail.com>, stable@kernel.org, Yifan Wu <yifanwucs@gmail.com>, Juefei Pu <tomapufckgml@gmail.com>, Yuan Tan <yuantan098@gmail.com>, Xin Liu <bird@lzu.edu.cn>, Ren Wei <enjou1224z@gmail.com>, Ren Wei <n05ec@lzu.edu.cn>, Ido Schimmel <idosch@nvidia.com>, Nikolay Aleksandrov <razor@blackwall.org>, Paolo Abeni <pabeni@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504121628.2165390-1-sashal@kernel.org>
+
+From: Zhengchuan Liang <zcliangcn@gmail.com>
+
+[ Upstream commit df4601653201de21b487c3e7fffd464790cab808 ]
+
+Local FDB entries can be rewritten in place by `fdb_delete_local()`, which
+updates `f->dst` to another port or to `NULL` while keeping the entry
+alive. Several bridge RCU readers inspect `f->dst`, including
+`br_fdb_fillbuf()` through the `brforward_read()` sysfs path.
+
+These readers currently load `f->dst` multiple times and can therefore
+observe inconsistent values across the check and later dereference.
+In `br_fdb_fillbuf()`, this means a concurrent local-FDB update can change
+`f->dst` after the NULL check and before the `port_no` dereference,
+leading to a NULL-ptr-deref.
+
+Fix this by taking a single `READ_ONCE()` snapshot of `f->dst` in each
+affected RCU reader and using that snapshot for the rest of the access
+sequence. Also publish the in-place `f->dst` updates in `fdb_delete_local()`
+with `WRITE_ONCE()` so the readers and writer use matching access patterns.
+
+Fixes: 960b589f86c7 ("bridge: Properly check if local fdb entry can be deleted in br_fdb_change_mac_address")
+Cc: stable@kernel.org
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Co-developed-by: Yuan Tan <yuantan098@gmail.com>
+Signed-off-by: Yuan Tan <yuantan098@gmail.com>
+Suggested-by: Xin Liu <bird@lzu.edu.cn>
+Tested-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Zhengchuan Liang <zcliangcn@gmail.com>
+Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
+Link: https://patch.msgid.link/6570fabb85ecadb8baaf019efe856f407711c7b9.1776043229.git.zcliangcn@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ kept combined-flag check `(dst->flags & (BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS))` and `cb->args[2]` indexing instead of `br_is_neigh_suppress_enabled()` helper and `ctx->fdb_idx` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bridge/br_arp_nd_proxy.c | 8 +++++---
+ net/bridge/br_fdb.c | 28 ++++++++++++++++++----------
+ 2 files changed, 23 insertions(+), 13 deletions(-)
+
+--- a/net/bridge/br_arp_nd_proxy.c
++++ b/net/bridge/br_arp_nd_proxy.c
+@@ -199,11 +199,12 @@ void br_do_proxy_suppress_arp(struct sk_
+
+ f = br_fdb_find_rcu(br, n->ha, vid);
+ if (f) {
++ const struct net_bridge_port *dst = READ_ONCE(f->dst);
+ bool replied = false;
+
+ if ((p && (p->flags & BR_PROXYARP)) ||
+- (f->dst && (f->dst->flags & (BR_PROXYARP_WIFI |
+- BR_NEIGH_SUPPRESS)))) {
++ (dst && (dst->flags & (BR_PROXYARP_WIFI |
++ BR_NEIGH_SUPPRESS)))) {
+ if (!vid)
+ br_arp_send(br, p, skb->dev, sip, tip,
+ sha, n->ha, sha, 0, 0);
+@@ -463,9 +464,10 @@ void br_do_suppress_nd(struct sk_buff *s
+
+ f = br_fdb_find_rcu(br, n->ha, vid);
+ if (f) {
++ const struct net_bridge_port *dst = READ_ONCE(f->dst);
+ bool replied = false;
+
+- if (f->dst && (f->dst->flags & BR_NEIGH_SUPPRESS)) {
++ if (dst && (dst->flags & BR_NEIGH_SUPPRESS)) {
+ if (vid != 0)
+ br_nd_send(br, p, skb, n,
+ skb->vlan_proto,
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -121,6 +121,7 @@ struct net_device *br_fdb_find_port(cons
+ const unsigned char *addr,
+ __u16 vid)
+ {
++ const struct net_bridge_port *dst;
+ struct net_bridge_fdb_entry *f;
+ struct net_device *dev = NULL;
+ struct net_bridge *br;
+@@ -133,8 +134,11 @@ struct net_device *br_fdb_find_port(cons
+ br = netdev_priv(br_dev);
+ rcu_read_lock();
+ f = br_fdb_find_rcu(br, addr, vid);
+- if (f && f->dst)
+- dev = f->dst->dev;
++ if (f) {
++ dst = READ_ONCE(f->dst);
++ if (dst)
++ dev = dst->dev;
++ }
+ rcu_read_unlock();
+
+ return dev;
+@@ -224,7 +228,7 @@ static void fdb_delete_local(struct net_
+ vg = nbp_vlan_group(op);
+ if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
+ (!vid || br_vlan_find(vg, vid))) {
+- f->dst = op;
++ WRITE_ONCE(f->dst, op);
+ clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
+ return;
+ }
+@@ -235,7 +239,7 @@ static void fdb_delete_local(struct net_
+ /* Maybe bridge device has same hw addr? */
+ if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
+ (!vid || (v && br_vlan_should_use(v)))) {
+- f->dst = NULL;
++ WRITE_ONCE(f->dst, NULL);
+ clear_bit(BR_FDB_ADDED_BY_USER, &f->flags);
+ return;
+ }
+@@ -462,6 +466,7 @@ int br_fdb_test_addr(struct net_device *
+ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
+ unsigned long maxnum, unsigned long skip)
+ {
++ const struct net_bridge_port *dst;
+ struct net_bridge_fdb_entry *f;
+ struct __fdb_entry *fe = buf;
+ int num = 0;
+@@ -477,7 +482,8 @@ int br_fdb_fillbuf(struct net_bridge *br
+ continue;
+
+ /* ignore pseudo entry for local MAC address */
+- if (!f->dst)
++ dst = READ_ONCE(f->dst);
++ if (!dst)
+ continue;
+
+ if (skip) {
+@@ -489,8 +495,8 @@ int br_fdb_fillbuf(struct net_bridge *br
+ memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
+
+ /* due to ABI compat need to split into hi/lo */
+- fe->port_no = f->dst->port_no;
+- fe->port_hi = f->dst->port_no >> 8;
++ fe->port_no = dst->port_no;
++ fe->port_hi = dst->port_no >> 8;
+
+ fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
+ if (!test_bit(BR_FDB_STATIC, &f->flags))
+@@ -836,9 +842,11 @@ int br_fdb_dump(struct sk_buff *skb,
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
++ const struct net_bridge_port *dst = READ_ONCE(f->dst);
++
+ if (*idx < cb->args[2])
+ goto skip;
+- if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
++ if (filter_dev && (!dst || dst->dev != filter_dev)) {
+ if (filter_dev != dev)
+ goto skip;
+ /* !f->dst is a special case for bridge
+@@ -846,10 +854,10 @@ int br_fdb_dump(struct sk_buff *skb,
+ * Therefore need a little more filtering
+ * we only want to dump the !f->dst case
+ */
+- if (f->dst)
++ if (dst)
+ goto skip;
+ }
+- if (!filter_dev && f->dst)
++ if (!filter_dev && dst)
+ goto skip;
+
+ err = fdb_fill_info(skb, br, f,
--- /dev/null
+From stable+bounces-242960-greg=kroah.com@vger.kernel.org Mon May 4 14:34:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 04:59:28 -0400
+Subject: net: mctp: fix don't require received header reserved bits to be zero
+To: stable@vger.kernel.org
+Cc: Yuan Zhaoming <yuanzm2@lenovo.com>, Jeremy Kerr <jk@codeconstruct.com.au>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504085928.1894173-1-sashal@kernel.org>
+
+From: Yuan Zhaoming <yuanzm2@lenovo.com>
+
+[ Upstream commit a663bac71a2f0b3ac6c373168ca57b2a6e6381aa ]
+
+>From the MCTP Base specification (DSP0236 v1.2.1), the first byte of
+the MCTP header contains a 4 bit reserved field, and 4 bit version.
+
+On our current receive path, we require those 4 reserved bits to be
+zero, but the 9500-8i card is non-conformant, and may set these
+reserved bits.
+
+DSP0236 states that the reserved bits must be written as zero, and
+ignored when read. While the device might not conform to the former,
+we should accept these message to conform to the latter.
+
+Relax our check on the MCTP version byte to allow non-zero bits in the
+reserved field.
+
+Fixes: 889b7da23abf ("mctp: Add initial routing framework")
+Signed-off-by: Yuan Zhaoming <yuanzm2@lenovo.com>
+Cc: stable@vger.kernel.org
+Acked-by: Jeremy Kerr <jk@codeconstruct.com.au>
+Link: https://patch.msgid.link/20260417141340.5306-1-yuanzhaoming901030@126.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Context ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/mctp.h | 3 +++
+ net/mctp/route.c | 8 ++++++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+--- a/include/net/mctp.h
++++ b/include/net/mctp.h
+@@ -25,6 +25,9 @@ struct mctp_hdr {
+ #define MCTP_VER_MIN 1
+ #define MCTP_VER_MAX 1
+
++/* Definitions for ver field */
++#define MCTP_HDR_VER_MASK GENMASK(3, 0)
++
+ /* Definitions for flags_seq_tag field */
+ #define MCTP_HDR_FLAG_SOM BIT(7)
+ #define MCTP_HDR_FLAG_EOM BIT(6)
+--- a/net/mctp/route.c
++++ b/net/mctp/route.c
+@@ -229,6 +229,7 @@ static int mctp_route_input(struct mctp_
+ unsigned long f;
+ u8 tag, flags;
+ int rc;
++ u8 ver;
+
+ msk = NULL;
+ rc = -EINVAL;
+@@ -246,7 +247,8 @@ static int mctp_route_input(struct mctp_
+ mh = mctp_hdr(skb);
+ skb_pull(skb, sizeof(struct mctp_hdr));
+
+- if (mh->ver != 1)
++ ver = mh->ver & MCTP_HDR_VER_MASK;
++ if (ver < MCTP_VER_MIN || ver > MCTP_VER_MAX)
+ goto out;
+
+ flags = mh->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
+@@ -859,6 +861,7 @@ static int mctp_pkttype_receive(struct s
+ struct mctp_skb_cb *cb;
+ struct mctp_route *rt;
+ struct mctp_hdr *mh;
++ u8 ver;
+
+ /* basic non-data sanity checks */
+ if (dev->type != ARPHRD_MCTP)
+@@ -872,7 +875,8 @@ static int mctp_pkttype_receive(struct s
+
+ /* We have enough for a header; decode and route */
+ mh = mctp_hdr(skb);
+- if (mh->ver < MCTP_VER_MIN || mh->ver > MCTP_VER_MAX)
++ ver = mh->ver & MCTP_HDR_VER_MASK;
++ if (ver < MCTP_VER_MIN || ver > MCTP_VER_MAX)
+ goto err_drop;
+
+ cb = __mctp_cb(skb);
--- /dev/null
+From stable+bounces-241120-greg=kroah.com@vger.kernel.org Sat Apr 25 15:31:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 25 Apr 2026 06:01:33 -0400
+Subject: net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
+To: stable@vger.kernel.org
+Cc: Bingquan Chen <patzilla007@gmail.com>, Willem de Bruijn <willemb@google.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260425100133.3487288-1-sashal@kernel.org>
+
+From: Bingquan Chen <patzilla007@gmail.com>
+
+[ Upstream commit 2c054e17d9d41f1020376806c7f750834ced4dc5 ]
+
+In tpacket_snd(), when PACKET_VNET_HDR is enabled, vnet_hdr points
+directly into the mmap'd TX ring buffer shared with userspace. The
+kernel validates the header via __packet_snd_vnet_parse() but then
+re-reads all fields later in virtio_net_hdr_to_skb(). A concurrent
+userspace thread can modify the vnet_hdr fields between validation
+and use, bypassing all safety checks.
+
+The non-TPACKET path (packet_snd()) already correctly copies vnet_hdr
+to a stack-local variable. All other vnet_hdr consumers in the kernel
+(tun.c, tap.c, virtio_net.c) also use stack copies. The TPACKET TX
+path is the only caller of virtio_net_hdr_to_skb() that reads directly
+from user-controlled shared memory.
+
+Fix this by copying vnet_hdr from the mmap'd ring buffer to a
+stack-local variable before validation and use, consistent with the
+approach used in packet_snd() and all other callers.
+
+Fixes: 1d036d25e560 ("packet: tpacket_snd gso and checksum offload")
+Signed-off-by: Bingquan Chen <patzilla007@gmail.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20260418112006.78823-1-patzilla007@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ replaced `vnet_hdr_sz` with `sizeof(vnet_hdr)` and `if (vnet_hdr_sz)` with `if (po->has_vnet_hdr)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/packet/af_packet.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -2729,7 +2729,8 @@ static int tpacket_snd(struct packet_soc
+ {
+ struct sk_buff *skb = NULL;
+ struct net_device *dev;
+- struct virtio_net_hdr *vnet_hdr = NULL;
++ struct virtio_net_hdr vnet_hdr;
++ bool has_vnet_hdr = false;
+ struct sockcm_cookie sockc;
+ __be16 proto;
+ int err, reserve = 0;
+@@ -2829,16 +2830,20 @@ static int tpacket_snd(struct packet_soc
+ hlen = LL_RESERVED_SPACE(dev);
+ tlen = dev->needed_tailroom;
+ if (po->has_vnet_hdr) {
+- vnet_hdr = data;
+- data += sizeof(*vnet_hdr);
+- tp_len -= sizeof(*vnet_hdr);
+- if (tp_len < 0 ||
+- __packet_snd_vnet_parse(vnet_hdr, tp_len)) {
++ data += sizeof(vnet_hdr);
++ tp_len -= sizeof(vnet_hdr);
++ if (tp_len < 0) {
++ tp_len = -EINVAL;
++ goto tpacket_error;
++ }
++ memcpy(&vnet_hdr, data - sizeof(vnet_hdr), sizeof(vnet_hdr));
++ if (__packet_snd_vnet_parse(&vnet_hdr, tp_len)) {
+ tp_len = -EINVAL;
+ goto tpacket_error;
+ }
+ copylen = __virtio16_to_cpu(vio_le(),
+- vnet_hdr->hdr_len);
++ vnet_hdr.hdr_len);
++ has_vnet_hdr = true;
+ }
+ copylen = max_t(int, copylen, dev->hard_header_len);
+ skb = sock_alloc_send_skb(&po->sk,
+@@ -2875,12 +2880,12 @@ tpacket_error:
+ }
+ }
+
+- if (po->has_vnet_hdr) {
+- if (virtio_net_hdr_to_skb(skb, vnet_hdr, vio_le())) {
++ if (has_vnet_hdr) {
++ if (virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le())) {
+ tp_len = -EINVAL;
+ goto tpacket_error;
+ }
+- virtio_net_hdr_set_proto(skb, vnet_hdr);
++ virtio_net_hdr_set_proto(skb, &vnet_hdr);
+ }
+
+ skb->destructor = tpacket_destruct_skb;
--- /dev/null
+From stable+bounces-242840-greg=kroah.com@vger.kernel.org Mon May 4 11:09:41 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 01:39:31 -0400
+Subject: net: qrtr: ns: Change servers radix tree to xarray
+To: stable@vger.kernel.org
+Cc: Vignesh Viswanathan <quic_viswanat@quicinc.com>, Chris Lew <quic_clew@quicinc.com>, Simon Horman <simon.horman@corigine.com>, "David S. Miller" <davem@davemloft.net>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504053932.1748829-1-sashal@kernel.org>
+
+From: Vignesh Viswanathan <quic_viswanat@quicinc.com>
+
+[ Upstream commit 608a147a88728f84bbd2efdde3d4984339f1d872 ]
+
+There is a use after free scenario while iterating through the servers
+radix tree despite the ns being a single threaded process. This can
+happen when the radix tree APIs are not synchronized with the
+rcu_read_lock() APIs.
+
+Convert the radix tree for servers to xarray to take advantage of the
+built in rcu lock usage provided by xarray.
+
+Signed-off-by: Chris Lew <quic_clew@quicinc.com>
+Signed-off-by: Vignesh Viswanathan <quic_viswanat@quicinc.com>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 68efba36446a ("net: qrtr: ns: Free the node during ctrl_cmd_bye()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c | 133 ++++++++++------------------------------------------------
+ 1 file changed, 24 insertions(+), 109 deletions(-)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -67,7 +67,7 @@ struct qrtr_server {
+
+ struct qrtr_node {
+ unsigned int id;
+- struct radix_tree_root servers;
++ struct xarray servers;
+ };
+
+ /* Max lookup limit is chosen based on the current platform requirements. If the
+@@ -89,6 +89,7 @@ static struct qrtr_node *node_get(unsign
+ return NULL;
+
+ node->id = node_id;
++ xa_init(&node->servers);
+
+ if (radix_tree_insert(&nodes, node_id, node)) {
+ kfree(node);
+@@ -199,40 +200,23 @@ static void lookup_notify(struct sockadd
+
+ static int announce_servers(struct sockaddr_qrtr *sq)
+ {
+- struct radix_tree_iter iter;
+ struct qrtr_server *srv;
+ struct qrtr_node *node;
+- void __rcu **slot;
++ unsigned long index;
+ int ret;
+
+ node = node_get(qrtr_ns.local_node);
+ if (!node)
+ return 0;
+
+- rcu_read_lock();
+ /* Announce the list of servers registered in this node */
+- radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
+- srv = radix_tree_deref_slot(slot);
+- if (!srv)
+- continue;
+- if (radix_tree_deref_retry(srv)) {
+- slot = radix_tree_iter_retry(&iter);
+- continue;
+- }
+- slot = radix_tree_iter_resume(slot, &iter);
+- rcu_read_unlock();
+-
++ xa_for_each(&node->servers, index, srv) {
+ ret = service_announce_new(sq, srv);
+ if (ret < 0) {
+ pr_err("failed to announce new service\n");
+ return ret;
+ }
+-
+- rcu_read_lock();
+ }
+-
+- rcu_read_unlock();
+-
+ return 0;
+ }
+
+@@ -262,14 +246,17 @@ static struct qrtr_server *server_add(un
+ goto err;
+
+ /* Delete the old server on the same port */
+- old = radix_tree_lookup(&node->servers, port);
++ old = xa_store(&node->servers, port, srv, GFP_KERNEL);
+ if (old) {
+- radix_tree_delete(&node->servers, port);
+- kfree(old);
++ if (xa_is_err(old)) {
++ pr_err("failed to add server [0x%x:0x%x] ret:%d\n",
++ srv->service, srv->instance, xa_err(old));
++ goto err;
++ } else {
++ kfree(old);
++ }
+ }
+
+- radix_tree_insert(&node->servers, port, srv);
+-
+ trace_qrtr_ns_server_add(srv->service, srv->instance,
+ srv->node, srv->port);
+
+@@ -286,11 +273,11 @@ static int server_del(struct qrtr_node *
+ struct qrtr_server *srv;
+ struct list_head *li;
+
+- srv = radix_tree_lookup(&node->servers, port);
++ srv = xa_load(&node->servers, port);
+ if (!srv)
+ return -ENOENT;
+
+- radix_tree_delete(&node->servers, port);
++ xa_erase(&node->servers, port);
+
+ /* Broadcast the removal of local servers */
+ if (srv->node == qrtr_ns.local_node && bcast)
+@@ -350,13 +337,12 @@ static int ctrl_cmd_hello(struct sockadd
+ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
+ {
+ struct qrtr_node *local_node;
+- struct radix_tree_iter iter;
+ struct qrtr_ctrl_pkt pkt;
+ struct qrtr_server *srv;
+ struct sockaddr_qrtr sq;
+ struct msghdr msg = { };
+ struct qrtr_node *node;
+- void __rcu **slot;
++ unsigned long index;
+ struct kvec iv;
+ int ret;
+
+@@ -367,22 +353,9 @@ static int ctrl_cmd_bye(struct sockaddr_
+ if (!node)
+ return 0;
+
+- rcu_read_lock();
+ /* Advertise removal of this client to all servers of remote node */
+- radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
+- srv = radix_tree_deref_slot(slot);
+- if (!srv)
+- continue;
+- if (radix_tree_deref_retry(srv)) {
+- slot = radix_tree_iter_retry(&iter);
+- continue;
+- }
+- slot = radix_tree_iter_resume(slot, &iter);
+- rcu_read_unlock();
++ xa_for_each(&node->servers, index, srv)
+ server_del(node, srv->port, true);
+- rcu_read_lock();
+- }
+- rcu_read_unlock();
+
+ /* Advertise the removal of this client to all local servers */
+ local_node = node_get(qrtr_ns.local_node);
+@@ -393,18 +366,7 @@ static int ctrl_cmd_bye(struct sockaddr_
+ pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
+ pkt.client.node = cpu_to_le32(from->sq_node);
+
+- rcu_read_lock();
+- radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
+- srv = radix_tree_deref_slot(slot);
+- if (!srv)
+- continue;
+- if (radix_tree_deref_retry(srv)) {
+- slot = radix_tree_iter_retry(&iter);
+- continue;
+- }
+- slot = radix_tree_iter_resume(slot, &iter);
+- rcu_read_unlock();
+-
++ xa_for_each(&local_node->servers, index, srv) {
+ sq.sq_family = AF_QIPCRTR;
+ sq.sq_node = srv->node;
+ sq.sq_port = srv->port;
+@@ -417,11 +379,7 @@ static int ctrl_cmd_bye(struct sockaddr_
+ pr_err("failed to send bye cmd\n");
+ return ret;
+ }
+- rcu_read_lock();
+ }
+-
+- rcu_read_unlock();
+-
+ return 0;
+ }
+
+@@ -429,7 +387,6 @@ static int ctrl_cmd_del_client(struct so
+ unsigned int node_id, unsigned int port)
+ {
+ struct qrtr_node *local_node;
+- struct radix_tree_iter iter;
+ struct qrtr_lookup *lookup;
+ struct qrtr_ctrl_pkt pkt;
+ struct msghdr msg = { };
+@@ -438,7 +395,7 @@ static int ctrl_cmd_del_client(struct so
+ struct qrtr_node *node;
+ struct list_head *tmp;
+ struct list_head *li;
+- void __rcu **slot;
++ unsigned long index;
+ struct kvec iv;
+ int ret;
+
+@@ -484,18 +441,7 @@ static int ctrl_cmd_del_client(struct so
+ pkt.client.node = cpu_to_le32(node_id);
+ pkt.client.port = cpu_to_le32(port);
+
+- rcu_read_lock();
+- radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
+- srv = radix_tree_deref_slot(slot);
+- if (!srv)
+- continue;
+- if (radix_tree_deref_retry(srv)) {
+- slot = radix_tree_iter_retry(&iter);
+- continue;
+- }
+- slot = radix_tree_iter_resume(slot, &iter);
+- rcu_read_unlock();
+-
++ xa_for_each(&local_node->servers, index, srv) {
+ sq.sq_family = AF_QIPCRTR;
+ sq.sq_node = srv->node;
+ sq.sq_port = srv->port;
+@@ -508,11 +454,7 @@ static int ctrl_cmd_del_client(struct so
+ pr_err("failed to send del client cmd\n");
+ return ret;
+ }
+- rcu_read_lock();
+ }
+-
+- rcu_read_unlock();
+-
+ return 0;
+ }
+
+@@ -585,13 +527,12 @@ static int ctrl_cmd_del_server(struct so
+ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
+ unsigned int service, unsigned int instance)
+ {
+- struct radix_tree_iter node_iter;
+ struct qrtr_server_filter filter;
+- struct radix_tree_iter srv_iter;
+ struct qrtr_lookup *lookup;
++ struct qrtr_server *srv;
+ struct qrtr_node *node;
+- void __rcu **node_slot;
+- void __rcu **srv_slot;
++ unsigned long node_idx;
++ unsigned long srv_idx;
+
+ /* Accept only local observers */
+ if (from->sq_node != qrtr_ns.local_node)
+@@ -616,40 +557,14 @@ static int ctrl_cmd_new_lookup(struct so
+ filter.service = service;
+ filter.instance = instance;
+
+- rcu_read_lock();
+- radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
+- node = radix_tree_deref_slot(node_slot);
+- if (!node)
+- continue;
+- if (radix_tree_deref_retry(node)) {
+- node_slot = radix_tree_iter_retry(&node_iter);
+- continue;
+- }
+- node_slot = radix_tree_iter_resume(node_slot, &node_iter);
+-
+- radix_tree_for_each_slot(srv_slot, &node->servers,
+- &srv_iter, 0) {
+- struct qrtr_server *srv;
+-
+- srv = radix_tree_deref_slot(srv_slot);
+- if (!srv)
+- continue;
+- if (radix_tree_deref_retry(srv)) {
+- srv_slot = radix_tree_iter_retry(&srv_iter);
+- continue;
+- }
+-
++ xa_for_each(&nodes, node_idx, node) {
++ xa_for_each(&node->servers, srv_idx, srv) {
+ if (!server_match(srv, &filter))
+ continue;
+
+- srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter);
+-
+- rcu_read_unlock();
+ lookup_notify(from, srv, true);
+- rcu_read_lock();
+ }
+ }
+- rcu_read_unlock();
+
+ /* Empty notification, to indicate end of listing */
+ lookup_notify(from, NULL, true);
--- /dev/null
+From stable+bounces-242841-greg=kroah.com@vger.kernel.org Mon May 4 11:09:43 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 01:39:32 -0400
+Subject: net: qrtr: ns: Free the node during ctrl_cmd_bye()
+To: stable@vger.kernel.org
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504053932.1748829-2-sashal@kernel.org>
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+[ Upstream commit 68efba36446a7774ea5b971257ade049272a07ac ]
+
+A node sends the BYE packet when it is about to go down. So the nameserver
+should advertise the removal of the node to all remote and local observers
+and free the node finally. But currently, the nameserver doesn't free the
+node memory even after processing the BYE packet. This causes the node
+memory to leak.
+
+Hence, remove the node from Xarray list and free the node memory during
+both success and failure case of ctrl_cmd_bye().
+
+Cc: stable@vger.kernel.org
+Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260409-qrtr-fix-v3-3-00a8a5ff2b51@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -344,7 +344,7 @@ static int ctrl_cmd_bye(struct sockaddr_
+ struct qrtr_node *node;
+ unsigned long index;
+ struct kvec iv;
+- int ret;
++ int ret = 0;
+
+ iv.iov_base = &pkt;
+ iv.iov_len = sizeof(pkt);
+@@ -359,8 +359,10 @@ static int ctrl_cmd_bye(struct sockaddr_
+
+ /* Advertise the removal of this client to all local servers */
+ local_node = node_get(qrtr_ns.local_node);
+- if (!local_node)
+- return 0;
++ if (!local_node) {
++ ret = 0;
++ goto delete_node;
++ }
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
+@@ -377,10 +379,18 @@ static int ctrl_cmd_bye(struct sockaddr_
+ ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
+ if (ret < 0) {
+ pr_err("failed to send bye cmd\n");
+- return ret;
++ goto delete_node;
+ }
+ }
+- return 0;
++
++ /* Ignore -ENODEV */
++ ret = 0;
++
++delete_node:
++ xa_erase(&nodes, from->sq_node);
++ kfree(node);
++
++ return ret;
+ }
+
+ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
--- /dev/null
+From stable+bounces-242836-greg=kroah.com@vger.kernel.org Mon May 4 10:35:29 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 01:05:10 -0400
+Subject: net: qrtr: ns: Limit the maximum number of lookups
+To: stable@vger.kernel.org
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504050510.1612332-1-sashal@kernel.org>
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+[ Upstream commit 5640227d9a21c6a8be249a10677b832e7f40dc55 ]
+
+Current code does no bound checking on the number of lookups a client can
+perform. Though the code restricts the lookups to local clients, there is
+still a possibility of a malicious local client sending a flood of
+NEW_LOOKUP messages over the same socket.
+
+Fix this issue by limiting the maximum number of lookups to 64 globally.
+Since the nameserver allows only atmost one local observer, this global
+lookup count will ensure that the lookups stay within the limit.
+
+Note that, limit of 64 is chosen based on the current platform
+requirements. If requirement changes in the future, this limit can be
+increased.
+
+Cc: stable@vger.kernel.org
+Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260409-qrtr-fix-v3-2-00a8a5ff2b51@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ adapted comment block to only mention QRTR_NS_MAX_LOOKUPS and kept kzalloc() instead of kzalloc_obj() due to missing prerequisite commits ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -21,6 +21,7 @@ static struct {
+ struct socket *sock;
+ struct sockaddr_qrtr bcast_sq;
+ struct list_head lookups;
++ u32 lookup_count;
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+ void (*saved_data_ready)(struct sock *sk);
+@@ -69,6 +70,11 @@ struct qrtr_node {
+ struct radix_tree_root servers;
+ };
+
++/* Max lookup limit is chosen based on the current platform requirements. If the
++ * requirement changes in the future, this value can be increased.
++ */
++#define QRTR_NS_MAX_LOOKUPS 64
++
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+ struct qrtr_node *node;
+@@ -457,6 +463,7 @@ static int ctrl_cmd_del_client(struct so
+
+ list_del(&lookup->li);
+ kfree(lookup);
++ qrtr_ns.lookup_count--;
+ }
+
+ /* Remove the server belonging to this port but don't broadcast
+@@ -590,6 +597,11 @@ static int ctrl_cmd_new_lookup(struct so
+ if (from->sq_node != qrtr_ns.local_node)
+ return -EINVAL;
+
++ if (qrtr_ns.lookup_count >= QRTR_NS_MAX_LOOKUPS) {
++ pr_err_ratelimited("QRTR client node exceeds max lookup limit!\n");
++ return -ENOSPC;
++ }
++
+ lookup = kzalloc(sizeof(*lookup), GFP_KERNEL);
+ if (!lookup)
+ return -ENOMEM;
+@@ -598,6 +610,7 @@ static int ctrl_cmd_new_lookup(struct so
+ lookup->service = service;
+ lookup->instance = instance;
+ list_add_tail(&lookup->li, &qrtr_ns.lookups);
++ qrtr_ns.lookup_count++;
+
+ memset(&filter, 0, sizeof(filter));
+ filter.service = service;
+@@ -664,6 +677,7 @@ static void ctrl_cmd_del_lookup(struct s
+
+ list_del(&lookup->li);
+ kfree(lookup);
++ qrtr_ns.lookup_count--;
+ }
+ }
+
--- /dev/null
+From stable+bounces-242992-greg=kroah.com@vger.kernel.org Mon May 4 16:06:33 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 May 2026 06:32:53 -0400
+Subject: net: qrtr: ns: Limit the total number of nodes
+To: stable@vger.kernel.org
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260504103253.2070381-1-sashal@kernel.org>
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+
+[ Upstream commit 27d5e84e810b0849d08b9aec68e48570461ce313 ]
+
+Currently, the nameserver doesn't limit the number of nodes it handles.
+This can be an attack vector if a malicious client starts registering
+random nodes, leading to memory exhaustion.
+
+Hence, limit the maximum number of nodes to 64. Note that, limit of 64 is
+chosen based on the current platform requirements. If requirement changes
+in the future, this limit can be increased.
+
+Cc: stable@vger.kernel.org
+Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260409-qrtr-fix-v3-4-00a8a5ff2b51@oss.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ dropped node_count-- hunk since ctrl_cmd_bye() has no delete_node ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/qrtr/ns.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -75,6 +75,16 @@ struct qrtr_node {
+ */
+ #define QRTR_NS_MAX_LOOKUPS 64
+
++/* Max nodes, server, lookup limits are chosen based on the current platform
++ * requirements. If the requirement changes in the future, these values can be
++ * increased.
++ */
++#define QRTR_NS_MAX_NODES 64
++#define QRTR_NS_MAX_SERVERS 256
++#define QRTR_NS_MAX_LOOKUPS 64
++
++static u8 node_count;
++
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+ struct qrtr_node *node;
+@@ -83,6 +93,11 @@ static struct qrtr_node *node_get(unsign
+ if (node)
+ return node;
+
++ if (node_count >= QRTR_NS_MAX_NODES) {
++ pr_err_ratelimited("QRTR clients exceed max node limit!\n");
++ return NULL;
++ }
++
+ /* If node didn't exist, allocate and insert it to the tree */
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+@@ -96,6 +111,8 @@ static struct qrtr_node *node_get(unsign
+ return NULL;
+ }
+
++ node_count++;
++
+ return node;
+ }
+
--- /dev/null
+From 46d0d6f50dab706637f4c18a470aac20a21900d3 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@kernel.org>
+Date: Mon, 2 Mar 2026 12:34:09 -0800
+Subject: net/tcp-md5: Fix MAC comparison to be constant-time
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 46d0d6f50dab706637f4c18a470aac20a21900d3 upstream.
+
+To prevent timing attacks, MACs need to be compared in constant
+time. Use the appropriate helper function for this.
+
+Fixes: cfb6eeb4c860 ("[TCP]: MD5 Signature Option (RFC2385) support.")
+Fixes: 658ddaaf6694 ("tcp: md5: RST: getting md5 key from listener")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Link: https://patch.msgid.link/20260302203409.13388-1-ebiggers@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Li hongliang <1468888505@139.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/tcp_ipv4.c | 5 +++--
+ net/ipv6/tcp_ipv6.c | 5 +++--
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/net/ipv4/tcp_ipv4.c
++++ b/net/ipv4/tcp_ipv4.c
+@@ -78,6 +78,7 @@
+ #include <linux/inetdevice.h>
+ #include <linux/btf_ids.h>
+
++#include <crypto/algapi.h>
+ #include <crypto/hash.h>
+ #include <linux/scatterlist.h>
+
+@@ -763,7 +764,7 @@ static void tcp_v4_send_reset(const stru
+
+
+ genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, skb);
+- if (genhash || memcmp(hash_location, newhash, 16) != 0)
++ if (genhash || crypto_memneq(hash_location, newhash, 16))
+ goto out;
+
+ }
+@@ -1467,7 +1468,7 @@ static bool tcp_v4_inbound_md5_hash(cons
+ hash_expected,
+ NULL, skb);
+
+- if (genhash || memcmp(hash_location, newhash, 16) != 0) {
++ if (genhash || crypto_memneq(hash_location, newhash, 16)) {
+ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
+ net_info_ratelimited("MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s L3 index %d\n",
+ &iph->saddr, ntohs(th->source),
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -63,6 +63,7 @@
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+
++#include <crypto/algapi.h>
+ #include <crypto/hash.h>
+ #include <linux/scatterlist.h>
+
+@@ -810,7 +811,7 @@ static bool tcp_v6_inbound_md5_hash(cons
+ hash_expected,
+ NULL, skb);
+
+- if (genhash || memcmp(hash_location, newhash, 16) != 0) {
++ if (genhash || crypto_memneq(hash_location, newhash, 16)) {
+ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
+ net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u L3 index %d\n",
+ genhash ? "failed" : "mismatch",
+@@ -1088,7 +1089,7 @@ static void tcp_v6_send_reset(const stru
+ goto out;
+
+ genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb);
+- if (genhash || memcmp(hash_location, newhash, 16) != 0)
++ if (genhash || crypto_memneq(hash_location, newhash, 16))
+ goto out;
+ }
+ #endif
--- /dev/null
+From stable+bounces-242557-greg=kroah.com@vger.kernel.org Sat May 2 04:58:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 19:27:43 -0400
+Subject: nvme: fix interpretation of DMRSL
+To: stable@vger.kernel.org
+Cc: Tom Yan <tom.ty89@gmail.com>, Christoph Hellwig <hch@lst.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501232744.4102493-1-sashal@kernel.org>
+
+From: Tom Yan <tom.ty89@gmail.com>
+
+[ Upstream commit 1a86924e4f464757546d7f7bdc469be237918395 ]
+
+DMRSLl is in the unit of logical blocks, while max_discard_sectors is
+in the unit of "linux sector".
+
+Signed-off-by: Tom Yan <tom.ty89@gmail.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Stable-dep-of: 40f0496b617b ("nvme: respect NVME_QUIRK_DISABLE_WRITE_ZEROES when wzsl is set")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvme/host/core.c | 6 ++++--
+ drivers/nvme/host/nvme.h | 1 +
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -1736,6 +1736,9 @@ static void nvme_config_discard(struct g
+ if (blk_queue_flag_test_and_set(QUEUE_FLAG_DISCARD, queue))
+ return;
+
++ if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns, UINT_MAX))
++ ctrl->max_discard_sectors = nvme_lba_to_sect(ns, ctrl->dmrsl);
++
+ blk_queue_max_discard_sectors(queue, ctrl->max_discard_sectors);
+ blk_queue_max_discard_segments(queue, ctrl->max_discard_segments);
+
+@@ -2948,8 +2951,7 @@ static int nvme_init_non_mdts_limits(str
+
+ if (id->dmrl)
+ ctrl->max_discard_segments = id->dmrl;
+- if (id->dmrsl)
+- ctrl->max_discard_sectors = le32_to_cpu(id->dmrsl);
++ ctrl->dmrsl = le32_to_cpu(id->dmrsl);
+ if (id->wzsl)
+ ctrl->max_zeroes_sectors = nvme_mps_to_sectors(ctrl, id->wzsl);
+
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -299,6 +299,7 @@ struct nvme_ctrl {
+ #endif
+ u16 crdt[3];
+ u16 oncs;
++ u32 dmrsl;
+ u16 oacs;
+ u16 nssa;
+ u16 nr_streams;
--- /dev/null
+From stable+bounces-242556-greg=kroah.com@vger.kernel.org Sat May 2 04:58:05 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 May 2026 19:27:44 -0400
+Subject: nvme: respect NVME_QUIRK_DISABLE_WRITE_ZEROES when wzsl is set
+To: stable@vger.kernel.org
+Cc: Robert Beckett <bob.beckett@collabora.com>, Keith Busch <kbusch@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260501232744.4102493-2-sashal@kernel.org>
+
+From: Robert Beckett <bob.beckett@collabora.com>
+
+[ Upstream commit 40f0496b617b431f8d2dd94d7f785c1121f8a68a ]
+
+The NVM Command Set Identify Controller data may report a non-zero
+Write Zeroes Size Limit (wzsl). When present, nvme_init_non_mdts_limits()
+unconditionally overrides max_zeroes_sectors from wzsl, even if
+NVME_QUIRK_DISABLE_WRITE_ZEROES previously set it to zero.
+
+This effectively re-enables write zeroes for devices that need it
+disabled, defeating the quirk. Several Kingston OM* drives rely on
+this quirk to avoid firmware issues with write zeroes commands.
+
+Check for the quirk before applying the wzsl override.
+
+Fixes: 5befc7c26e5a ("nvme: implement non-mdts command limits")
+Cc: stable@vger.kernel.org
+Signed-off-by: Robert Beckett <bob.beckett@collabora.com>
+Assisted-by: claude-opus-4-6-v1
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvme/host/core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -2952,7 +2952,7 @@ static int nvme_init_non_mdts_limits(str
+ if (id->dmrl)
+ ctrl->max_discard_segments = id->dmrl;
+ ctrl->dmrsl = le32_to_cpu(id->dmrsl);
+- if (id->wzsl)
++ if (id->wzsl && !(ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES))
+ ctrl->max_zeroes_sectors = nvme_mps_to_sectors(ctrl, id->wzsl);
+
+ free_data:
--- /dev/null
+From stable+bounces-245030-greg=kroah.com@vger.kernel.org Sun May 10 20:40:18 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 May 2026 11:10:09 -0400
+Subject: printk: add print_hex_dump_devel()
+To: stable@vger.kernel.org
+Cc: Thorsten Blum <thorsten.blum@linux.dev>, Herbert Xu <herbert@gondor.apana.org.au>, John Ogness <john.ogness@linutronix.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260510151010.38344-1-sashal@kernel.org>
+
+From: Thorsten Blum <thorsten.blum@linux.dev>
+
+[ Upstream commit d134feeb5df33fbf77f482f52a366a44642dba09 ]
+
+Add print_hex_dump_devel() as the hex dump equivalent of pr_devel(),
+which emits output only when DEBUG is enabled, but keeps call sites
+compiled otherwise.
+
+Suggested-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
+Reviewed-by: John Ogness <john.ogness@linutronix.de>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Stable-dep-of: 177730a273b1 ("crypto: caam - guard HMAC key hex dumps in hash_digest_key")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/printk.h | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/include/linux/printk.h
++++ b/include/linux/printk.h
+@@ -740,6 +740,19 @@ static inline void print_hex_dump_debug(
+ }
+ #endif
+
++#if defined(DEBUG)
++#define print_hex_dump_devel(prefix_str, prefix_type, rowsize, \
++ groupsize, buf, len, ascii) \
++ print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \
++ groupsize, buf, len, ascii)
++#else
++static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type,
++ int rowsize, int groupsize,
++ const void *buf, size_t len, bool ascii)
++{
++}
++#endif
++
+ /**
+ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default
+ * params
--- /dev/null
+From stable+bounces-244038-greg=kroah.com@vger.kernel.org Tue May 5 15:22:40 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 May 2026 05:49:40 -0400
+Subject: randomize_kstack: Maintain kstack_offset per task
+To: stable@vger.kernel.org
+Cc: Ryan Roberts <ryan.roberts@arm.com>, Mark Rutland <mark.rutland@arm.com>, Kees Cook <kees@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260505094940.506135-1-sashal@kernel.org>
+
+From: Ryan Roberts <ryan.roberts@arm.com>
+
+[ Upstream commit 37beb42560165869838e7d91724f3e629db64129 ]
+
+kstack_offset was previously maintained per-cpu, but this caused a
+couple of issues. So let's instead make it per-task.
+
+Issue 1: add_random_kstack_offset() and choose_random_kstack_offset()
+expected and required to be called with interrupts and preemption
+disabled so that it could manipulate per-cpu state. But arm64, loongarch
+and risc-v are calling them with interrupts and preemption enabled. I
+don't _think_ this causes any functional issues, but it's certainly
+unexpected and could lead to manipulating the wrong cpu's state, which
+could cause a minor performance degradation due to bouncing the cache
+lines. By maintaining the state per-task those functions can safely be
+called in preemptible context.
+
+Issue 2: add_random_kstack_offset() is called before executing the
+syscall and expands the stack using a previously chosen random offset.
+choose_random_kstack_offset() is called after executing the syscall and
+chooses and stores a new random offset for the next syscall. With
+per-cpu storage for this offset, an attacker could force cpu migration
+during the execution of the syscall and prevent the offset from being
+updated for the original cpu such that it is predictable for the next
+syscall on that cpu. By maintaining the state per-task, this problem
+goes away because the per-task random offset is updated after the
+syscall regardless of which cpu it is executing on.
+
+Fixes: 39218ff4c625 ("stack: Optionally randomize kernel stack offset each syscall")
+Closes: https://lore.kernel.org/all/dd8c37bc-795f-4c7a-9086-69e584d8ab24@arm.com/
+Cc: stable@vger.kernel.org
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
+Link: https://patch.msgid.link/20260303150840.3789438-2-ryan.roberts@arm.com
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/randomize_kstack.h | 44 +++++++++++++++++++++++++++++++--------
+ include/linux/sched.h | 4 +++
+ init/main.c | 1
+ kernel/fork.c | 2 +
+ 4 files changed, 42 insertions(+), 9 deletions(-)
+
+--- a/include/linux/randomize_kstack.h
++++ b/include/linux/randomize_kstack.h
+@@ -8,7 +8,6 @@
+
+ DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
+ randomize_kstack_offset);
+-DECLARE_PER_CPU(u32, kstack_offset);
+
+ /*
+ * Do not use this anywhere else in the kernel. This is used here because
+@@ -39,28 +38,57 @@ DECLARE_PER_CPU(u32, kstack_offset);
+ */
+ #define KSTACK_OFFSET_MAX(x) ((x) & 0x3FF)
+
+-/*
+- * These macros must be used during syscall entry when interrupts and
+- * preempt are disabled, and after user registers have been stored to
+- * the stack.
++/**
++ * add_random_kstack_offset - Increase stack utilization by previously
++ * chosen random offset
++ *
++ * This should be used in the syscall entry path after user registers have been
++ * stored to the stack. Preemption may be enabled. For testing the resulting
++ * entropy, please see: tools/testing/selftests/lkdtm/stack-entropy.sh
+ */
+ #define add_random_kstack_offset() do { \
+ if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
+ &randomize_kstack_offset)) { \
+- u32 offset = raw_cpu_read(kstack_offset); \
++ u32 offset = current->kstack_offset; \
+ u8 *ptr = __kstack_alloca(KSTACK_OFFSET_MAX(offset)); \
+ /* Keep allocation even after "ptr" loses scope. */ \
+ asm volatile("" :: "r"(ptr) : "memory"); \
+ } \
+ } while (0)
+
++/**
++ * choose_random_kstack_offset - Choose the random offset for the next
++ * add_random_kstack_offset()
++ *
++ * This should only be used during syscall exit. Preemption may be enabled. This
++ * position in the syscall flow is done to frustrate attacks from userspace
++ * attempting to learn the next offset:
++ * - Maximize the timing uncertainty visible from userspace: if the
++ * offset is chosen at syscall entry, userspace has much more control
++ * over the timing between choosing offsets. "How long will we be in
++ * kernel mode?" tends to be more difficult to predict than "how long
++ * will we be in user mode?"
++ * - Reduce the lifetime of the new offset sitting in memory during
++ * kernel mode execution. Exposure of "thread-local" memory content
++ * (e.g. current, percpu, etc) tends to be easier than arbitrary
++ * location memory exposure.
++ */
+ #define choose_random_kstack_offset(rand) do { \
+ if (static_branch_maybe(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT, \
+ &randomize_kstack_offset)) { \
+- u32 offset = raw_cpu_read(kstack_offset); \
++ u32 offset = current->kstack_offset; \
+ offset = ror32(offset, 5) ^ (rand); \
+- raw_cpu_write(kstack_offset, offset); \
++ current->kstack_offset = offset; \
+ } \
+ } while (0)
+
++#ifdef CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
++static inline void random_kstack_task_init(struct task_struct *tsk)
++{
++ tsk->kstack_offset = 0;
++}
++#else
++#define random_kstack_task_init(tsk) do { } while (0)
++#endif
++
+ #endif
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -1461,6 +1461,10 @@ struct task_struct {
+ unsigned long prev_lowest_stack;
+ #endif
+
++#ifdef CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
++ u32 kstack_offset;
++#endif
++
+ #ifdef CONFIG_X86_MCE
+ void __user *mce_vaddr;
+ __u64 mce_kflags;
+--- a/init/main.c
++++ b/init/main.c
+@@ -882,7 +882,6 @@ static void __init mm_init(void)
+ #ifdef CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
+ DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
+ randomize_kstack_offset);
+-DEFINE_PER_CPU(u32, kstack_offset);
+
+ static int __init early_randomize_kstack_offset(char *buf)
+ {
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -94,6 +94,7 @@
+ #include <linux/thread_info.h>
+ #include <linux/stackleak.h>
+ #include <linux/kasan.h>
++#include <linux/randomize_kstack.h>
+ #include <linux/scs.h>
+ #include <linux/io_uring.h>
+ #include <linux/bpf.h>
+@@ -2300,6 +2301,7 @@ static __latent_entropy struct task_stru
+ if (retval)
+ goto bad_fork_cleanup_io;
+
++ random_kstack_task_init(p);
+ stackleak_task_init(p);
+
+ if (pid != &init_struct_pid) {
--- /dev/null
+From stable+bounces-242156-greg=kroah.com@vger.kernel.org Thu Apr 30 21:44:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Apr 2026 12:07:39 -0400
+Subject: rtw88: 8821ce: Disable PCIe ASPM L1 for 8821CE using chip ID
+To: stable@vger.kernel.org
+Cc: Jimmy Hon <honyuenkwun@gmail.com>, Ping-Ke Shih <pkshih@realtek.com>, Kalle Valo <kvalo@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260430160740.1785374-1-sashal@kernel.org>
+
+From: Jimmy Hon <honyuenkwun@gmail.com>
+
+[ Upstream commit b9eb5f0742d107ca9c0f33da58f61ce83e3ce2fc ]
+
+Make workaround work for other 8821CE devices with different PCI ID
+
+Signed-off-by: Jimmy Hon <honyuenkwun@gmail.com>
+Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20220407075123.420696-3-honyuenkwun@gmail.com
+Stable-dep-of: eb101d2abdcc ("wifi: rtw88: check for PCI upstream bridge existence")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/realtek/rtw88/pci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/realtek/rtw88/pci.c
++++ b/drivers/net/wireless/realtek/rtw88/pci.c
+@@ -1766,7 +1766,7 @@ int rtw_pci_probe(struct pci_dev *pdev,
+ }
+
+ /* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
+- if (pdev->device == 0xc821 && bridge->vendor == PCI_VENDOR_ID_INTEL)
++ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
+ rtwpci->rx_no_aspm = true;
+
+ rtw_pci_phy_cfg(rtwdev);
--- /dev/null
+From stable+bounces-242815-greg=kroah.com@vger.kernel.org Mon May 4 00:44:24 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 3 May 2026 15:14:16 -0400
+Subject: rxrpc: Fix conn-level packet handling to unshare RESPONSE packets
+To: stable@vger.kernel.org
+Cc: David Howells <dhowells@redhat.com>, Marc Dionne <marc.dionne@auristor.com>, Jeffrey Altman <jaltman@auristor.com>, Simon Horman <horms@kernel.org>, linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260503191416.1286222-1-sashal@kernel.org>
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit 24481a7f573305706054c59e275371f8d0fe919f ]
+
+The security operations that verify the RESPONSE packets decrypt bits of it
+in place - however, the sk_buff may be shared with a packet sniffer, which
+would lead to the sniffer seeing an apparently corrupt packet (actually
+decrypted).
+
+Fix this by handing a copy of the packet off to the specific security
+handler if the packet was cloned.
+
+Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
+Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Marc Dionne <marc.dionne@auristor.com>
+cc: Jeffrey Altman <jaltman@auristor.com>
+cc: Simon Horman <horms@kernel.org>
+cc: linux-afs@lists.infradead.org
+cc: stable@kernel.org
+Link: https://patch.msgid.link/20260422161438.2593376-5-dhowells@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ adapted callback signature to include `_abort_code` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/rxrpc/conn_event.c | 30 +++++++++++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
+index 5d91ef562ff78..09438850f9a5a 100644
+--- a/net/rxrpc/conn_event.c
++++ b/net/rxrpc/conn_event.c
+@@ -285,6 +285,34 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
+ }
+ }
+
++static int rxrpc_verify_response(struct rxrpc_connection *conn,
++ struct sk_buff *skb,
++ u32 *_abort_code)
++{
++ int ret;
++
++ if (skb_cloned(skb)) {
++ /* Copy the packet if shared so that we can do in-place
++ * decryption.
++ */
++ struct sk_buff *nskb = skb_copy(skb, GFP_NOFS);
++
++ if (nskb) {
++ rxrpc_new_skb(nskb, rxrpc_skb_unshared);
++ ret = conn->security->verify_response(conn, nskb, _abort_code);
++ rxrpc_free_skb(nskb, rxrpc_skb_freed);
++ } else {
++ /* OOM - Drop the packet. */
++ rxrpc_see_skb(skb, rxrpc_skb_unshared_nomem);
++ ret = -ENOMEM;
++ }
++ } else {
++ ret = conn->security->verify_response(conn, skb, _abort_code);
++ }
++
++ return ret;
++}
++
+ /*
+ * connection-level Rx packet processor
+ */
+@@ -337,7 +365,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
+ _abort_code);
+
+ case RXRPC_PACKET_TYPE_RESPONSE:
+- ret = conn->security->verify_response(conn, skb, _abort_code);
++ ret = rxrpc_verify_response(conn, skb, _abort_code);
+ if (ret < 0)
+ return ret;
+
+--
+2.53.0
+
--- /dev/null
+From stable+bounces-242628-greg=kroah.com@vger.kernel.org Sun May 3 05:59:34 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 2 May 2026 20:26:45 -0400
+Subject: sched: Use u64 for bandwidth ratio calculations
+To: stable@vger.kernel.org
+Cc: Joseph Salisbury <joseph.salisbury@oracle.com>, "Peter Zijlstra (Intel)" <peterz@infradead.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260503002645.929471-1-sashal@kernel.org>
+
+From: Joseph Salisbury <joseph.salisbury@oracle.com>
+
+[ Upstream commit c6e80201e057dfb7253385e60bf541121bf5dc33 ]
+
+to_ratio() computes BW_SHIFT-scaled bandwidth ratios from u64 period and
+runtime values, but it returns unsigned long. tg_rt_schedulable() also
+stores the current group limit and the accumulated child sum in unsigned
+long.
+
+On 32-bit builds, large bandwidth ratios can be truncated and the RT
+group sum can wrap when enough siblings are present. That can let an
+overcommitted RT hierarchy pass the schedulability check, and it also
+narrows the helper result for other callers.
+
+Return u64 from to_ratio() and use u64 for the RT group totals so
+bandwidth ratios are preserved and compared at full width on both 32-bit
+and 64-bit builds.
+
+Fixes: b40b2e8eb521 ("sched: rt: multi level group constraints")
+Assisted-by: Codex:GPT-5
+Signed-off-by: Joseph Salisbury <joseph.salisbury@oracle.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260403210014.2713404-1-joseph.salisbury@oracle.com
+[ dropped `extern` keyword from `to_ratio()` declaration ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sched/core.c | 2 +-
+ kernel/sched/rt.c | 2 +-
+ kernel/sched/sched.h | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -4491,7 +4491,7 @@ void sched_post_fork(struct task_struct
+ uclamp_post_fork(p);
+ }
+
+-unsigned long to_ratio(u64 period, u64 runtime)
++u64 to_ratio(u64 period, u64 runtime)
+ {
+ if (runtime == RUNTIME_INF)
+ return BW_UNIT;
+--- a/kernel/sched/rt.c
++++ b/kernel/sched/rt.c
+@@ -2606,7 +2606,7 @@ static int tg_rt_schedulable(struct task
+ {
+ struct rt_schedulable_data *d = data;
+ struct task_group *child;
+- unsigned long total, sum = 0;
++ u64 total, sum = 0;
+ u64 period, runtime;
+
+ period = ktime_to_ns(tg->rt_bandwidth.rt_period);
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -2340,7 +2340,7 @@ extern void init_dl_inactive_task_timer(
+ #define RATIO_SHIFT 8
+ #define MAX_BW_BITS (64 - BW_SHIFT)
+ #define MAX_BW ((1ULL << MAX_BW_BITS) - 1)
+-unsigned long to_ratio(u64 period, u64 runtime);
++u64 to_ratio(u64 period, u64 runtime);
+
+ extern void init_entity_runnable_average(struct sched_entity *se);
+ extern void post_init_entity_util_avg(struct task_struct *p);
--- /dev/null
+From stable+bounces-244970-greg=kroah.com@vger.kernel.org Sat May 9 21:38:57 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 May 2026 12:08:46 -0400
+Subject: scsi: core: pm: Rely on the device driver core for async power management
+To: stable@vger.kernel.org
+Cc: Bart Van Assche <bvanassche@acm.org>, Alan Stern <stern@rowland.harvard.edu>, Dan Williams <dan.j.williams@intel.com>, Hannes Reinecke <hare@suse.com>, Adrian Hunter <adrian.hunter@intel.com>, Martin Kepplinger <martin.kepplinger@puri.sm>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509160849.3584738-1-sashal@kernel.org>
+
+From: Bart Van Assche <bvanassche@acm.org>
+
+[ Upstream commit a19a93e4c6a98c9c0f2f5a6db76846f10d7d1f85 ]
+
+Instead of implementing asynchronous resume support in the SCSI core, rely
+on the device driver core for resuming SCSI devices asynchronously.
+Instead of only supporting asynchronous resumes, also support asynchronous
+suspends.
+
+Link: https://lore.kernel.org/r/20211006215453.3318929-2-bvanassche@acm.org
+Cc: Alan Stern <stern@rowland.harvard.edu>
+Cc: Dan Williams <dan.j.williams@intel.com>
+Cc: Hannes Reinecke <hare@suse.com>
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: Martin Kepplinger <martin.kepplinger@puri.sm>
+Signed-off-by: Bart Van Assche <bvanassche@acm.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 1e111c4b3a72 ("scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/hosts.c | 1 +
+ drivers/scsi/scsi.c | 8 --------
+ drivers/scsi/scsi_pm.c | 44 ++------------------------------------------
+ drivers/scsi/scsi_priv.h | 4 +---
+ drivers/scsi/scsi_scan.c | 17 +++++++++++++++++
+ drivers/scsi/scsi_sysfs.c | 1 +
+ drivers/scsi/sd.c | 1 -
+ 7 files changed, 22 insertions(+), 54 deletions(-)
+
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -487,6 +487,7 @@ struct Scsi_Host *scsi_host_alloc(struct
+ dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
+ shost->shost_gendev.bus = &scsi_bus_type;
+ shost->shost_gendev.type = &scsi_host_type;
++ scsi_enable_async_suspend(&shost->shost_gendev);
+
+ device_initialize(&shost->shost_dev);
+ shost->shost_dev.parent = &shost->shost_gendev;
+--- a/drivers/scsi/scsi.c
++++ b/drivers/scsi/scsi.c
+@@ -86,14 +86,6 @@ unsigned int scsi_logging_level;
+ EXPORT_SYMBOL(scsi_logging_level);
+ #endif
+
+-/*
+- * Domain for asynchronous system resume operations. It is marked 'exclusive'
+- * to avoid being included in the async_synchronize_full() that is invoked by
+- * dpm_resume().
+- */
+-ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
+-EXPORT_SYMBOL(scsi_sd_pm_domain);
+-
+ #ifdef CONFIG_SCSI_LOGGING
+ void scsi_log_send(struct scsi_cmnd *cmd)
+ {
+--- a/drivers/scsi/scsi_pm.c
++++ b/drivers/scsi/scsi_pm.c
+@@ -56,9 +56,6 @@ static int scsi_dev_type_suspend(struct
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int err;
+
+- /* flush pending in-flight resume operations, suspend is synchronous */
+- async_synchronize_full_domain(&scsi_sd_pm_domain);
+-
+ err = scsi_device_quiesce(to_scsi_device(dev));
+ if (err == 0) {
+ err = cb(dev, pm);
+@@ -123,48 +120,11 @@ scsi_bus_suspend_common(struct device *d
+ return err;
+ }
+
+-static void async_sdev_resume(void *dev, async_cookie_t cookie)
+-{
+- scsi_dev_type_resume(dev, do_scsi_resume);
+-}
+-
+-static void async_sdev_thaw(void *dev, async_cookie_t cookie)
+-{
+- scsi_dev_type_resume(dev, do_scsi_thaw);
+-}
+-
+-static void async_sdev_restore(void *dev, async_cookie_t cookie)
+-{
+- scsi_dev_type_resume(dev, do_scsi_restore);
+-}
+-
+ static int scsi_bus_resume_common(struct device *dev,
+ int (*cb)(struct device *, const struct dev_pm_ops *))
+ {
+- async_func_t fn;
+-
+- if (!scsi_is_sdev_device(dev))
+- fn = NULL;
+- else if (cb == do_scsi_resume)
+- fn = async_sdev_resume;
+- else if (cb == do_scsi_thaw)
+- fn = async_sdev_thaw;
+- else if (cb == do_scsi_restore)
+- fn = async_sdev_restore;
+- else
+- fn = NULL;
+-
+- if (fn) {
+- async_schedule_domain(fn, dev, &scsi_sd_pm_domain);
+-
+- /*
+- * If a user has disabled async probing a likely reason
+- * is due to a storage enclosure that does not inject
+- * staggered spin-ups. For safety, make resume
+- * synchronous as well in that case.
+- */
+- if (strncmp(scsi_scan_type, "async", 5) != 0)
+- async_synchronize_full_domain(&scsi_sd_pm_domain);
++ if (scsi_is_sdev_device(dev)) {
++ scsi_dev_type_resume(dev, cb);
+ } else {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+--- a/drivers/scsi/scsi_priv.h
++++ b/drivers/scsi/scsi_priv.h
+@@ -117,7 +117,7 @@ extern void scsi_exit_procfs(void);
+ #endif /* CONFIG_PROC_FS */
+
+ /* scsi_scan.c */
+-extern char scsi_scan_type[];
++void scsi_enable_async_suspend(struct device *dev);
+ extern int scsi_complete_async_scans(void);
+ extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int,
+ unsigned int, u64, enum scsi_scan_mode);
+@@ -171,8 +171,6 @@ static inline int scsi_autopm_get_host(s
+ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
+ #endif /* CONFIG_PM */
+
+-extern struct async_domain scsi_sd_pm_domain;
+-
+ /* scsi_dh.c */
+ #ifdef CONFIG_SCSI_DH
+ void scsi_dh_add_device(struct scsi_device *sdev);
+--- a/drivers/scsi/scsi_scan.c
++++ b/drivers/scsi/scsi_scan.c
+@@ -123,6 +123,22 @@ struct async_scan_data {
+ };
+
+ /**
++ * scsi_enable_async_suspend - Enable async suspend and resume
++ */
++void scsi_enable_async_suspend(struct device *dev)
++{
++ /*
++ * If a user has disabled async probing a likely reason is due to a
++ * storage enclosure that does not inject staggered spin-ups. For
++ * safety, make resume synchronous as well in that case.
++ */
++ if (strncmp(scsi_scan_type, "async", 5) != 0)
++ return;
++ /* Enable asynchronous suspend and resume. */
++ device_enable_async_suspend(dev);
++}
++
++/**
+ * scsi_complete_async_scans - Wait for asynchronous scans to complete
+ *
+ * When this function returns, any host which started scanning before
+@@ -499,6 +515,7 @@ static struct scsi_target *scsi_alloc_ta
+ dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id);
+ dev->bus = &scsi_bus_type;
+ dev->type = &scsi_target_type;
++ scsi_enable_async_suspend(dev);
+ starget->id = id;
+ starget->channel = channel;
+ starget->can_queue = 0;
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -1643,6 +1643,7 @@ void scsi_sysfs_device_initialize(struct
+ device_initialize(&sdev->sdev_gendev);
+ sdev->sdev_gendev.bus = &scsi_bus_type;
+ sdev->sdev_gendev.type = &scsi_dev_type;
++ scsi_enable_async_suspend(&sdev->sdev_gendev);
+ dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%llu",
+ sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
+
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -3505,7 +3505,6 @@ static int sd_remove(struct device *dev)
+ sdkp = dev_get_drvdata(dev);
+ scsi_autopm_get_device(sdkp->device);
+
+- async_synchronize_full_domain(&scsi_sd_pm_domain);
+ device_del(&sdkp->dev);
+ del_gendisk(sdkp->disk);
+ sd_shutdown(dev);
--- /dev/null
+From stable+bounces-244971-greg=kroah.com@vger.kernel.org Sat May 9 21:38:58 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 May 2026 12:08:47 -0400
+Subject: scsi: sd: Add error handling support for add_disk()
+To: stable@vger.kernel.org
+Cc: Luis Chamberlain <mcgrof@kernel.org>, Christoph Hellwig <hch@lst.de>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509160849.3584738-2-sashal@kernel.org>
+
+From: Luis Chamberlain <mcgrof@kernel.org>
+
+[ Upstream commit 2a7a891f4c406822801ecd676b076c64de072c9e ]
+
+We never checked for errors on add_disk() as this function returned
+void. Now that this is fixed, use the shiny new error handling.
+
+As with the error handling for device_add() we follow the same logic and
+just put the device so that cleanup is done via the scsi_disk_release().
+
+Link: https://lore.kernel.org/r/20211015233028.2167651-2-mcgrof@kernel.org
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Acked-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 1e111c4b3a72 ("scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/sd.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -3458,7 +3458,13 @@ static int sd_probe(struct device *dev)
+ pm_runtime_set_autosuspend_delay(dev,
+ sdp->host->hostt->rpm_autosuspend_delay);
+ }
+- device_add_disk(dev, gd, NULL);
++
++ error = device_add_disk(dev, gd, NULL);
++ if (error) {
++ put_device(&sdkp->dev);
++ goto out;
++ }
++
+ if (sdkp->capacity)
+ sd_dif_config_host(sdkp);
+
--- /dev/null
+From stable+bounces-244973-greg=kroah.com@vger.kernel.org Sat May 9 21:39:04 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 May 2026 12:08:49 -0400
+Subject: scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails
+To: stable@vger.kernel.org
+Cc: Yang Xiuwei <yangxiuwei@kylinos.cn>, John Garry <john.g.garry@oracle.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509160849.3584738-4-sashal@kernel.org>
+
+From: Yang Xiuwei <yangxiuwei@kylinos.cn>
+
+[ Upstream commit 1e111c4b3a726df1254670a5cc4868cedb946d37 ]
+
+If device_add(&sdkp->disk_dev) fails, put_device() runs
+scsi_disk_release(), which frees the scsi_disk but leaves the gendisk
+referenced. The device_add_disk() error path in sd_probe() calls
+put_disk(gd); call put_disk(gd) here to mirror that cleanup.
+
+Fixes: 265dfe8ebbab ("scsi: sd: Free scsi_disk device via put_device()")
+Cc: stable@vger.kernel.org
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
+Link: https://patch.msgid.link/20260330014952.152776-1-yangxiuwei@kylinos.cn
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/sd.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -3420,6 +3420,7 @@ static int sd_probe(struct device *dev)
+ error = device_add(&sdkp->disk_dev);
+ if (error) {
+ put_device(&sdkp->disk_dev);
++ put_disk(gd);
+ goto out;
+ }
+
--- /dev/null
+From stable+bounces-244972-greg=kroah.com@vger.kernel.org Sat May 9 21:39:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 May 2026 12:08:48 -0400
+Subject: sd: rename the scsi_disk.dev field
+To: stable@vger.kernel.org
+Cc: Christoph Hellwig <hch@lst.de>, Bart Van Assche <bvanassche@acm.org>, Chaitanya Kulkarni <kch@nvidia.com>, Ming Lei <ming.lei@redhat.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Jens Axboe <axboe@kernel.dk>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260509160849.3584738-3-sashal@kernel.org>
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit fad45c3007a18064da759b4dba35eb722bc64e97 ]
+
+dev is very hard to grep for. Give the field a more descriptive name and
+documents its purpose.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Link: https://lore.kernel.org/r/20220308055200.735835-5-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Stable-dep-of: 1e111c4b3a72 ("scsi: sd: fix missing put_disk() when device_add(&disk_dev) fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/sd.c | 22 +++++++++++-----------
+ drivers/scsi/sd.h | 9 +++++++--
+ 2 files changed, 18 insertions(+), 13 deletions(-)
+
+--- a/drivers/scsi/sd.c
++++ b/drivers/scsi/sd.c
+@@ -674,7 +674,7 @@ static struct scsi_disk *scsi_disk_get(s
+ if (disk->private_data) {
+ sdkp = scsi_disk(disk);
+ if (scsi_device_get(sdkp->device) == 0)
+- get_device(&sdkp->dev);
++ get_device(&sdkp->disk_dev);
+ else
+ sdkp = NULL;
+ }
+@@ -687,7 +687,7 @@ static void scsi_disk_put(struct scsi_di
+ struct scsi_device *sdev = sdkp->device;
+
+ mutex_lock(&sd_ref_mutex);
+- put_device(&sdkp->dev);
++ put_device(&sdkp->disk_dev);
+ scsi_device_put(sdev);
+ mutex_unlock(&sd_ref_mutex);
+ }
+@@ -3412,14 +3412,14 @@ static int sd_probe(struct device *dev)
+ SD_MOD_TIMEOUT);
+ }
+
+- device_initialize(&sdkp->dev);
+- sdkp->dev.parent = get_device(dev);
+- sdkp->dev.class = &sd_disk_class;
+- dev_set_name(&sdkp->dev, "%s", dev_name(dev));
++ device_initialize(&sdkp->disk_dev);
++ sdkp->disk_dev.parent = get_device(dev);
++ sdkp->disk_dev.class = &sd_disk_class;
++ dev_set_name(&sdkp->disk_dev, "%s", dev_name(dev));
+
+- error = device_add(&sdkp->dev);
++ error = device_add(&sdkp->disk_dev);
+ if (error) {
+- put_device(&sdkp->dev);
++ put_device(&sdkp->disk_dev);
+ goto out;
+ }
+
+@@ -3461,7 +3461,7 @@ static int sd_probe(struct device *dev)
+
+ error = device_add_disk(dev, gd, NULL);
+ if (error) {
+- put_device(&sdkp->dev);
++ put_device(&sdkp->disk_dev);
+ goto out;
+ }
+
+@@ -3511,7 +3511,7 @@ static int sd_remove(struct device *dev)
+ sdkp = dev_get_drvdata(dev);
+ scsi_autopm_get_device(sdkp->device);
+
+- device_del(&sdkp->dev);
++ device_del(&sdkp->disk_dev);
+ del_gendisk(sdkp->disk);
+ sd_shutdown(dev);
+
+@@ -3519,7 +3519,7 @@ static int sd_remove(struct device *dev)
+
+ mutex_lock(&sd_ref_mutex);
+ dev_set_drvdata(dev, NULL);
+- put_device(&sdkp->dev);
++ put_device(&sdkp->disk_dev);
+ mutex_unlock(&sd_ref_mutex);
+
+ return 0;
+--- a/drivers/scsi/sd.h
++++ b/drivers/scsi/sd.h
+@@ -70,7 +70,12 @@ enum {
+ struct scsi_disk {
+ struct scsi_driver *driver; /* always &sd_template */
+ struct scsi_device *device;
+- struct device dev;
++
++ /*
++ * disk_dev is used to show attributes in /sys/class/scsi_disk/,
++ * but otherwise not really needed. Do not use for refcounting.
++ */
++ struct device disk_dev;
+ struct gendisk *disk;
+ struct opal_dev *opal_dev;
+ #ifdef CONFIG_BLK_DEV_ZONED
+@@ -126,7 +131,7 @@ struct scsi_disk {
+ unsigned security : 1;
+ unsigned ignore_medium_access_errors : 1;
+ };
+-#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
++#define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
+
+ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
+ {
drm-amd-display-use-krealloc_array-in-dal_vector_reserve.patch
fs-fcntl-fix-softirq-unsafe-lock-order-in-fasync-signaling.patch
mm-damon-ops-common-call-folio_test_lru-after-folio_.patch
+io_uring-poll-fix-signed-comparison-in-io_poll_get_ownership.patch
+net-tcp-md5-fix-mac-comparison-to-be-constant-time.patch
+ksmbd-compare-macs-in-constant-time.patch
+lib-crypto-mpi-fix-integer-underflow-in-mpi_read_raw_from_sgl.patch
+f2fs-fix-to-do-sanity-check-on-dcc-discard_cmd_cnt-conditionally.patch
+f2fs-fix-uaf-caused-by-decrementing-sbi-nr_pages-in-f2fs_write_end_io.patch
+smb-server-fix-active_num_conn-leak-on-transport-allocation-failure.patch
+smb-server-fix-max_connections-off-by-one-in-tcp-accept-path.patch
+smb-client-require-a-full-nfs-mode-sid-before-reading-mode-bits.patch
+smb-client-fix-oob-read-in-smb2_ioctl_query_info-query_info-path.patch
+ksmbd-require-minimum-ace-size-in-smb_check_perm_dacl.patch
+net-packet-fix-toctou-race-on-mmap-d-vnet_hdr-in-tpacket_snd.patch
+arm64-mm-enable-batched-tlb-flush-in-unmap_hotplug_range.patch
+rtw88-8821ce-disable-pcie-aspm-l1-for-8821ce-using-chip-id.patch
+wifi-rtw88-check-for-pci-upstream-bridge-existence.patch
+thermal-core-fix-thermal-zone-governor-cleanup-issues.patch
+wifi-mwifiex-fix-use-after-free-in-mwifiex_adapter_cleanup.patch
+alsa-aoa-use-guard-for-mutex-locks.patch
+alsa-aoa-i2sbus-clear-stale-prepared-state.patch
+media-rc-ttusbir-respect-dma-coherency-rules.patch
+alsa-aoa-skip-devices-with-no-codecs-in-i2sbus_resume.patch
+erofs-fix-the-out-of-bounds-nameoff-handling-for-trailing-dirents.patch
+nvme-fix-interpretation-of-dmrsl.patch
+nvme-respect-nvme_quirk_disable_write_zeroes-when-wzsl-is-set.patch
+media-rc-igorplugusb-heed-coherency-rules.patch
+sched-use-u64-for-bandwidth-ratio-calculations.patch
+alsa-core-fix-potential-data-race-at-fasync-handling.patch
+net-qrtr-ns-limit-the-maximum-number-of-lookups.patch
+net-qrtr-ns-change-servers-radix-tree-to-xarray.patch
+net-qrtr-ns-free-the-node-during-ctrl_cmd_bye.patch
+net-mctp-fix-don-t-require-received-header-reserved-bits-to-be-zero.patch
+net-qrtr-ns-limit-the-total-number-of-nodes.patch
+net-bridge-use-a-stable-fdb-dst-snapshot-in-rcu-readers.patch
+fbdev-defio-disconnect-deferred-i-o-from-the-lifetime-of-struct-fb_info.patch
+randomize_kstack-maintain-kstack_offset-per-task.patch
+mmc-sdhci-of-dwcmshc-disable-clock-before-dll-configuration.patch
+mtd-spi-nor-sst-fix-write-enable-before-aai-sequence.patch
+udf-fix-partition-descriptor-append-bookkeeping.patch
+hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch
+hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch
+bluetooth-hci_event-fix-potential-uaf-in-ssp-passkey-handlers.patch
+can-ucan-fix-typos-in-comments.patch
+can-ucan-fix-devres-lifetime.patch
+crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch
+crypto-nx-migrate-to-scomp-api.patch
+crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch
+erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch
+ceph-only-d_add-negative-dentries-when-they-are-unhashed.patch
+scsi-core-pm-rely-on-the-device-driver-core-for-async-power-management.patch
+scsi-sd-add-error-handling-support-for-add_disk.patch
+sd-rename-the-scsi_disk.dev-field.patch
+scsi-sd-fix-missing-put_disk-when-device_add-disk_dev-fails.patch
+alsa-aloop-fix-peer-runtime-uaf-during-format-change-stop.patch
+printk-add-print_hex_dump_devel.patch
+crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch
+tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch
+rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch
+mtd-docg3-fix-use-after-free-in-docg3_release.patch
+mtd-docg3-convert-to-platform-remove-callback-returning-void.patch
--- /dev/null
+From stable+bounces-240989-greg=kroah.com@vger.kernel.org Fri Apr 24 20:38:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 11:08:27 -0400
+Subject: smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424150827.2204387-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit a58c5af19ff0d6f44f6e9fe31e33a2c92223f77e ]
+
+smb2_ioctl_query_info() has two response-copy branches: PASSTHRU_FSCTL
+and the default QUERY_INFO path. The QUERY_INFO branch clamps
+qi.input_buffer_length to the server-reported OutputBufferLength and then
+copies qi.input_buffer_length bytes from qi_rsp->Buffer to userspace, but
+it never verifies that the flexible-array payload actually fits within
+rsp_iov[1].iov_len.
+
+A malicious server can return OutputBufferLength larger than the actual
+QUERY_INFO response, causing copy_to_user() to walk past the response
+buffer and expose adjacent kernel heap to userspace.
+
+Guard the QUERY_INFO copy with a bounds check on the actual Buffer
+payload. Use struct_size(qi_rsp, Buffer, qi.input_buffer_length)
+rather than an open-coded addition so the guard cannot overflow on
+32-bit builds.
+
+Fixes: f5778c398713 ("SMB3: Allow SMB3 FSCTL queries to be sent to server from tools")
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2ops.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -1826,6 +1826,12 @@ smb2_ioctl_query_info(const unsigned int
+ qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
+ if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length)
+ qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength);
++ if (qi.input_buffer_length > 0 &&
++ struct_size(qi_rsp, Buffer, qi.input_buffer_length) >
++ rsp_iov[1].iov_len) {
++ rc = -EFAULT;
++ goto out;
++ }
+ if (copy_to_user(&pqi->input_buffer_length,
+ &qi.input_buffer_length,
+ sizeof(qi.input_buffer_length))) {
--- /dev/null
+From stable+bounces-240984-greg=kroah.com@vger.kernel.org Fri Apr 24 20:06:22 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 10:33:39 -0400
+Subject: smb: client: require a full NFS mode SID before reading mode bits
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424143339.2171783-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 2757ad3e4b6f9e0fed4c7739594e702abc5cab21 ]
+
+parse_dacl() treats an ACE SID matching sid_unix_NFS_mode as an NFS
+mode SID and reads sid.sub_auth[2] to recover the mode bits.
+
+That assumes the ACE carries three subauthorities, but compare_sids()
+only compares min(a, b) subauthorities. A malicious server can return
+an ACE with num_subauth = 2 and sub_auth[] = {88, 3}, which still
+matches sid_unix_NFS_mode and then drives the sub_auth[2] read four
+bytes past the end of the ACE.
+
+Require num_subauth >= 3 before treating the ACE as an NFS mode SID.
+This keeps the fix local to the special-SID mode path without changing
+compare_sids() semantics for the rest of cifsacl.
+
+Fixes: e2f8fbfb8d09 ("cifs: get mode bits from special sid on stat")
+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: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cifsacl.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -807,6 +807,7 @@ static void parse_dacl(struct cifs_acl *
+ dump_ace(ppace[i], end_of_acl);
+ #endif
+ if (mode_from_special_sid &&
++ ppace[i]->sid.num_subauth >= 3 &&
+ (compare_sids(&(ppace[i]->sid),
+ &sid_unix_NFS_mode) == 0)) {
+ /*
--- /dev/null
+From stable+bounces-240967-greg=kroah.com@vger.kernel.org Fri Apr 24 19:24:02 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 09:51:35 -0400
+Subject: smb: server: fix active_num_conn leak on transport allocation failure
+To: stable@vger.kernel.org
+Cc: Michael Bommarito <michael.bommarito@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424135135.2085884-1-sashal@kernel.org>
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+[ Upstream commit 6551300dc452ac16a855a83dbd1e74899542d3b3 ]
+
+Commit 77ffbcac4e56 ("smb: server: fix leak of active_num_conn in
+ksmbd_tcp_new_connection()") addressed the kthread_run() failure
+path. The earlier alloc_transport() == NULL path in the same
+function has the same leak, is reachable pre-authentication via any
+TCP connect to port 445, and was empirically reproduced on UML
+(ARCH=um, v7.0-rc7): a small number of forced allocation failures
+were sufficient to put ksmbd into a state where every subsequent
+connection attempt was rejected for the remainder of the boot.
+
+ksmbd_kthread_fn() increments active_num_conn before calling
+ksmbd_tcp_new_connection() and discards the return value, so when
+alloc_transport() returns NULL the socket is released and -ENOMEM
+returned without decrementing the counter. Each such failure
+permanently consumes one slot from the max_connections pool; once
+cumulative failures reach the cap, atomic_inc_return() hits the
+threshold on every subsequent accept and every new connection is
+rejected. The counter is only reset by module reload.
+
+An unauthenticated remote attacker can drive the server toward the
+memory pressure that makes alloc_transport() fail by holding open
+connections with large RFC1002 lengths up to MAX_STREAM_PROT_LEN
+(0x00FFFFFF); natural transient allocation failures on a loaded
+host produce the same drift more slowly.
+
+Mirror the existing rollback pattern in ksmbd_kthread_fn(): on the
+alloc_transport() failure path, decrement active_num_conn gated on
+server_conf.max_connections.
+
+Repro details: with the patch reverted, forced alloc_transport()
+NULL returns leaked counter slots and subsequent connection
+attempts -- including legitimate connects issued after the
+forced-fail window had closed -- were all rejected with "Limit the
+maximum number of connections". With this patch applied, the same
+connect sequence produces no rejections and the counter cycles
+cleanly between zero and one on every accept.
+
+Fixes: 0d0d4680db22 ("ksmbd: add max connections parameter")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ksmbd/transport_tcp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/ksmbd/transport_tcp.c
++++ b/fs/ksmbd/transport_tcp.c
+@@ -191,6 +191,8 @@ static int ksmbd_tcp_new_connection(stru
+ t = alloc_transport(client_sk);
+ if (!t) {
+ sock_release(client_sk);
++ if (server_conf.max_connections)
++ atomic_dec(&active_num_conn);
+ return -ENOMEM;
+ }
+
--- /dev/null
+From stable+bounces-240975-greg=kroah.com@vger.kernel.org Fri Apr 24 19:40:06 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Apr 2026 10:08:09 -0400
+Subject: smb: server: fix max_connections off-by-one in tcp accept path
+To: stable@vger.kernel.org
+Cc: DaeMyung Kang <charsyam@gmail.com>, Namjae Jeon <linkinjeon@kernel.org>, Steve French <stfrench@microsoft.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260424140809.2152073-1-sashal@kernel.org>
+
+From: DaeMyung Kang <charsyam@gmail.com>
+
+[ Upstream commit ce23158bfe584bd90d1918f279fdf9de57802012 ]
+
+The global max_connections check in ksmbd's TCP accept path counts
+the newly accepted connection with atomic_inc_return(), but then
+rejects the connection when the result is greater than or equal to
+server_conf.max_connections.
+
+That makes the effective limit one smaller than configured. For
+example:
+
+- max_connections=1 rejects the first connection
+- max_connections=2 allows only one connection
+
+The per-IP limit in the same function uses <= correctly because it
+counts only pre-existing connections. The global limit instead checks
+the post-increment total, so it should reject only when that total
+exceeds the configured maximum.
+
+Fix this by changing the comparison from >= to >, so exactly
+max_connections simultaneous connections are allowed and the next one
+is rejected. This matches the documented meaning of max_connections
+in fs/smb/server/ksmbd_netlink.h as the "Number of maximum simultaneous
+connections".
+
+Fixes: 0d0d4680db22 ("ksmbd: add max connections parameter")
+Cc: stable@vger.kernel.org
+Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ksmbd/transport_tcp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/ksmbd/transport_tcp.c
++++ b/fs/ksmbd/transport_tcp.c
+@@ -248,7 +248,7 @@ static int ksmbd_kthread_fn(void *p)
+ }
+
+ if (server_conf.max_connections &&
+- atomic_inc_return(&active_num_conn) >= server_conf.max_connections) {
++ atomic_inc_return(&active_num_conn) > server_conf.max_connections) {
+ pr_info_ratelimited("Limit the maximum number of connections(%u)\n",
+ atomic_read(&active_num_conn));
+ atomic_dec(&active_num_conn);
--- /dev/null
+From stable+bounces-242194-greg=kroah.com@vger.kernel.org Fri May 1 00:27:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Apr 2026 14:57:32 -0400
+Subject: thermal: core: Fix thermal zone governor cleanup issues
+To: stable@vger.kernel.org
+Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260430185732.1955098-1-sashal@kernel.org>
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 41ff66baf81c6541f4f985dd7eac4494d03d9440 ]
+
+If thermal_zone_device_register_with_trips() fails after adding
+a thermal governor to the thermal zone being registered, the
+governor is not removed from it as appropriate which may lead to
+a memory leak.
+
+In turn, thermal_zone_device_unregister() calls thermal_set_governor()
+without acquiring the thermal zone lock beforehand which may race with
+a governor update via sysfs and may lead to a use-after-free in that
+case.
+
+Address these issues by adding two thermal_set_governor() calls, one to
+thermal_release() to remove the governor from the given thermal zone,
+and one to the thermal zone registration error path to cover failures
+preceding the thermal zone device registration.
+
+Fixes: e33df1d2f3a0 ("thermal: let governors have private data for each thermal zone")
+Cc: All applicable <stable@vger.kernel.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://patch.msgid.link/5092923.31r3eYUQgx@rafael.j.wysocki
+[ adapted context for missing mutex_destroy/complete ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thermal/thermal_core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -778,6 +778,7 @@ static void thermal_release(struct devic
+ sizeof("thermal_zone") - 1)) {
+ tz = to_thermal_zone(dev);
+ thermal_zone_destroy_device_groups(tz);
++ thermal_set_governor(tz, NULL);
+ kfree(tz);
+ } else if (!strncmp(dev_name(dev), "cooling_device",
+ sizeof("cooling_device") - 1)) {
+@@ -1260,8 +1261,10 @@ thermal_zone_device_register(const char
+ /* sys I/F */
+ /* Add nodes that are always present via .groups */
+ result = thermal_zone_create_device_groups(tz, mask);
+- if (result)
++ if (result) {
++ thermal_set_governor(tz, NULL);
+ goto remove_id;
++ }
+
+ /* A new thermal zone needs to be updated anyway. */
+ atomic_set(&tz->need_update, 1);
+@@ -1385,8 +1388,6 @@ void thermal_zone_device_unregister(stru
+
+ cancel_delayed_work_sync(&tz->poll_queue);
+
+- thermal_set_governor(tz, NULL);
+-
+ thermal_remove_hwmon_sysfs(tz);
+ ida_simple_remove(&thermal_tz_ida, tz->id);
+ ida_destroy(&tz->ida);
--- /dev/null
+From stable+bounces-245162-greg=kroah.com@vger.kernel.org Mon May 11 14:37:14 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 11 May 2026 04:57:26 -0400
+Subject: tracepoint: balance regfunc() on func_add() failure in tracepoint_add_func()
+To: stable@vger.kernel.org
+Cc: David Carlier <devnexen@gmail.com>, Masami Hiramatsu <mhiramat@kernel.org>, Mathieu Desnoyers <mathieu.desnoyers@efficios.com>, "Steven Rostedt (Google)" <rostedt@goodmis.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260511085726.1417414-1-sashal@kernel.org>
+
+From: David Carlier <devnexen@gmail.com>
+
+[ Upstream commit fad217e16fded7f3c09f8637b0f6a224d58b5f2e ]
+
+When a tracepoint goes through the 0 -> 1 transition, tracepoint_add_func()
+invokes the subsystem's ext->regfunc() before attempting to install the
+new probe via func_add(). If func_add() then fails (for example, when
+allocate_probes() cannot allocate a new probe array under memory pressure
+and returns -ENOMEM), the function returns the error without calling the
+matching ext->unregfunc(), leaving the side effects of regfunc() behind
+with no installed probe to justify them.
+
+For syscall tracepoints this is particularly unpleasant: syscall_regfunc()
+bumps sys_tracepoint_refcount and sets SYSCALL_TRACEPOINT on every task.
+After a leaked failure, the refcount is stuck at a non-zero value with no
+consumer, and every task continues paying the syscall trace entry/exit
+overhead until reboot. Other subsystems providing regfunc()/unregfunc()
+pairs exhibit similarly scoped persistent state.
+
+Mirror the existing 1 -> 0 cleanup and call ext->unregfunc() in the
+func_add() error path, gated on the same condition used there so the
+unwind is symmetric with the registration.
+
+Fixes: 8cf868affdc4 ("tracing: Have the reg function allow to fail")
+Cc: stable@vger.kernel.org
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Link: https://patch.msgid.link/20260413190601.21993-1-devnexen@gmail.com
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+[ changed `tp->ext->unregfunc` to `tp->unregfunc` to match older struct layout ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/tracepoint.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/kernel/tracepoint.c
++++ b/kernel/tracepoint.c
+@@ -337,6 +337,8 @@ static int tracepoint_add_func(struct tr
+ lockdep_is_held(&tracepoints_mutex));
+ old = func_add(&tp_funcs, func, prio);
+ if (IS_ERR(old)) {
++ if (tp->unregfunc && !static_key_enabled(&tp->key))
++ tp->unregfunc();
+ WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM);
+ return PTR_ERR(old);
+ }
--- /dev/null
+From stable+bounces-244849-greg=kroah.com@vger.kernel.org Sat May 9 05:30:16 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 May 2026 19:59:53 -0400
+Subject: udf: fix partition descriptor append bookkeeping
+To: stable@vger.kernel.org
+Cc: Seohyeon Maeng <bioloidgp@gmail.com>, Jan Kara <jack@suse.cz>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260508235953.2245198-1-sashal@kernel.org>
+
+From: Seohyeon Maeng <bioloidgp@gmail.com>
+
+[ Upstream commit 08841b06fa64d8edbd1a21ca6e613420c90cc4b8 ]
+
+Mounting a crafted UDF image with repeated partition descriptors can
+trigger a heap out-of-bounds write in part_descs_loc[].
+
+handle_partition_descriptor() deduplicates entries by partition number,
+but appended slots never record partnum. As a result duplicate
+Partition Descriptors are appended repeatedly and num_part_descs keeps
+growing.
+
+Once the table is full, the growth path still sizes the allocation from
+partnum even though inserts are indexed by num_part_descs. If partnum is
+already aligned to PART_DESC_ALLOC_STEP, ALIGN(partnum, step) can keep
+the old capacity and the next append writes past the end of the table.
+
+Store partnum in the appended slot and size growth from the next append
+count so deduplication and capacity tracking follow the same model.
+
+Fixes: ee4af50ca94f ("udf: Fix mounting of Win7 created UDF filesystems")
+Cc: stable@vger.kernel.org
+Signed-off-by: Seohyeon Maeng <bioloidgp@gmail.com>
+Link: https://patch.msgid.link/20260310081652.21220-1-bioloidgp@gmail.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+[ replaced kzalloc_objs() helper with equivalent kcalloc() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/super.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/udf/super.c
++++ b/fs/udf/super.c
+@@ -1658,8 +1658,9 @@ static struct udf_vds_record *handle_par
+ return &(data->part_descs_loc[i].rec);
+ if (data->num_part_descs >= data->size_part_descs) {
+ struct part_desc_seq_scan_data *new_loc;
+- unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
++ unsigned int new_size;
+
++ new_size = data->num_part_descs + PART_DESC_ALLOC_STEP;
+ new_loc = kcalloc(new_size, sizeof(*new_loc), GFP_KERNEL);
+ if (!new_loc)
+ return ERR_PTR(-ENOMEM);
+@@ -1669,6 +1670,7 @@ static struct udf_vds_record *handle_par
+ data->part_descs_loc = new_loc;
+ data->size_part_descs = new_size;
+ }
++ data->part_descs_loc[data->num_part_descs].partnum = partnum;
+ return &(data->part_descs_loc[data->num_part_descs++].rec);
+ }
+
--- /dev/null
+From stable+bounces-242195-greg=kroah.com@vger.kernel.org Fri May 1 00:28:01 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Apr 2026 14:57:55 -0400
+Subject: wifi: mwifiex: fix use-after-free in mwifiex_adapter_cleanup()
+To: stable@vger.kernel.org
+Cc: Daniel Hodges <git@danielhodges.dev>, Johannes Berg <johannes.berg@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260430185755.1955735-1-sashal@kernel.org>
+
+From: Daniel Hodges <git@danielhodges.dev>
+
+[ Upstream commit ae5e95d4157481693be2317e3ffcd84e36010cbb ]
+
+The mwifiex_adapter_cleanup() function uses timer_delete()
+(non-synchronous) for the wakeup_timer before the adapter structure is
+freed. This is incorrect because timer_delete() does not wait for any
+running timer callback to complete.
+
+If the wakeup_timer callback (wakeup_timer_fn) is executing when
+mwifiex_adapter_cleanup() is called, the callback will continue to
+access adapter fields (adapter->hw_status, adapter->if_ops.card_reset,
+etc.) which may be freed by mwifiex_free_adapter() called later in the
+mwifiex_remove_card() path.
+
+Use timer_delete_sync() instead to ensure any running timer callback has
+completed before returning.
+
+Fixes: 4636187da60b ("mwifiex: add wakeup timer based recovery mechanism")
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Hodges <git@danielhodges.dev>
+Link: https://patch.msgid.link/20260206194401.2346-1-git@danielhodges.dev
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+[ changed `timer_delete_sync(&adapter->wakeup_timer)` to `del_timer_sync(&adapter->wakeup_timer)` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/marvell/mwifiex/init.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/marvell/mwifiex/init.c
++++ b/drivers/net/wireless/marvell/mwifiex/init.c
+@@ -399,7 +399,7 @@ static void mwifiex_invalidate_lists(str
+ static void
+ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
+ {
+- del_timer(&adapter->wakeup_timer);
++ del_timer_sync(&adapter->wakeup_timer);
+ del_timer_sync(&adapter->devdump_timer);
+ mwifiex_cancel_all_pending_cmd(adapter);
+ wake_up_interruptible(&adapter->cmd_wait_q.wait);
--- /dev/null
+From stable+bounces-242157-greg=kroah.com@vger.kernel.org Thu Apr 30 21:45:19 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Apr 2026 12:07:40 -0400
+Subject: wifi: rtw88: check for PCI upstream bridge existence
+To: stable@vger.kernel.org
+Cc: Fedor Pchelkin <pchelkin@ispras.ru>, Ping-Ke Shih <pkshih@realtek.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260430160740.1785374-2-sashal@kernel.org>
+
+From: Fedor Pchelkin <pchelkin@ispras.ru>
+
+[ Upstream commit eb101d2abdcccb514ca4fccd3b278dd8267374f6 ]
+
+pci_upstream_bridge() returns NULL if the device is on a root bus. If
+8821CE is installed in the system with such a PCI topology, the probing
+routine will crash. This has probably been unnoticed as 8821CE is mostly
+supplied in laptops where there is a PCI-to-PCI bridge located upstream
+from the device. However the card might be installed on a system with
+different configuration.
+
+Check if the bridge does exist for the specific workaround to be applied.
+
+Found by Linux Verification Center (linuxtesting.org) with Svace static
+analysis tool.
+
+Fixes: 24f5e38a13b5 ("rtw88: Disable PCIe ASPM while doing NAPI poll on 8821CE")
+Cc: stable@vger.kernel.org
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Acked-by: Ping-Ke Shih <pkshih@realtek.com>
+Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
+Link: https://patch.msgid.link/20260220094730.49791-1-pchelkin@ispras.ru
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/realtek/rtw88/pci.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/realtek/rtw88/pci.c
++++ b/drivers/net/wireless/realtek/rtw88/pci.c
+@@ -1766,7 +1766,8 @@ int rtw_pci_probe(struct pci_dev *pdev,
+ }
+
+ /* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
+- if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
++ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C &&
++ bridge && bridge->vendor == PCI_VENDOR_ID_INTEL)
+ rtwpci->rx_no_aspm = true;
+
+ rtw_pci_phy_cfg(rtwdev);