From: Greg Kroah-Hartman Date: Wed, 29 Jul 2026 13:12:11 +0000 (+0200) Subject: 7.1-stable patches X-Git-Tag: v6.1.179~33 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=2bea7f9c255be1ef1228f5f2f5e6d7ebabf891aa;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: alsa-hda-codecs-hdmi-disable-keep-alive-before-audio-format-change.patch alsa-hda-realtek-fix-speakers-on-lunnen-ground-14.patch alsa-seq-close-a-re-opened-queue-timer-in-the-destructor.patch alsa-timer-don-t-re-enter-an-instance-callback-that-is-still-running.patch alsa-timer-drain-a-slave-s-callback-before-its-master-detaches-it.patch binfmt_misc-set-have_execfd-only-once-the-interpreter-is-opened.patch bluetooth-hci_sync-protect-uuid-list-traversal.patch bluetooth-rfcomm-fix-session-uaf-in-set_termios.patch exec-fix-unsigned-loop-counter-wrap-in-transfer_args_to_stack.patch media-nxp-imx8-isi-clean-up-already-initialized-pipes-on-probe-failure.patch media-nxp-imx8-isi-fix-missing-v4l2_subdev_cleanup-in-pipe-init-error-path.patch media-nxp-imx8-isi-fix-potential-out-of-bounds-issues.patch media-nxp-imx8-isi-fix-scale-factor-calculation-for-hardware-rounding.patch media-pci-dm1105-free-allocated-workqueue.patch media-pwc-drain-fill_buf-on-start_streaming-failure.patch media-pwc-return-queued-buffers-on-start_streaming-failure.patch media-qcom-camss-fix-rdi-streaming-for-csid-340.patch media-qcom-camss-fix-rdi-streaming-for-csid-680.patch media-qcom-camss-fix-rdi-streaming-for-csid-gen2.patch media-qcom-camss-fix-rdi-streaming-for-csid-gen3.patch media-radio-si476x-unregister-v4l2_device-on-probe-failure.patch media-rtl2832-fix-use-after-free-in-rtl2832_remove.patch media-rtl2832_sdr-return-queued-buffers-on-start_streaming-failure.patch media-rzg2l-cru-skip-icnmc-configuration-when-icnsvc-is-used.patch media-rzv2h-ivc-wait-for-frame-end-in-stop_streaming.patch media-saa7134-fix-a-possible-memory-leak-in-saa7134_video_init1.patch media-stm32-dcmi-unregister-notifier-on-probe-failure.patch media-stm32-dcmipp-return-queued-buffers-on-start_streaming-failure.patch media-sun4i-csi-return-queued-buffers-on-start_streaming-failure.patch media-synopsys-hdmirx-fix-hpd-lane-hold-time.patch media-tegra-video-vi-fix-invalid-u32-return-value-in-format-lookup.patch media-ti-vpe-fix-fwnode_handle-leak-in-vip_probe_complete.patch media-ti-vpe-fix-the-error-code-of-devm_kzalloc-in-vip_probe_slice.patch media-ti-vpe-fix-the-error-code-of-devm_request_irq.patch media-ti-vpe-unwind-v4l2-device-registration-on-probe-error.patch media-uapi-rkisp-correct-name-version-enum.patch media-v4l2-ctrls-request-add-null-check-in-v4l2_ctrl_request_complete.patch media-v4l2-ctrls-validate-hevc-active-reference-counts.patch media-v4l2-fwnode-fix-subdev-owner-overwritten-in-v4l2_async_register_subdev_sensor.patch media-v4l2-subdev-fail-enable-disable-_streams-and-s_streaming-nicely.patch media-vb2-use-ssize_t-for-vb2_read-vb2_write.patch media-verisilicon-export-only-needed-pixels-formats.patch media-vidtv-fix-reference-leak-on-failed-device-registration.patch media-vimc-fix-reference-leak-on-failed-device-registration.patch media-vivid-add-vivid_update_reduced_fps.patch media-vivid-check-for-vb2_is_busy-when-toggling-caps.patch media-vivid-fix-cleanup-bugs-in-vivid_init.patch media-vpif_capture-fix-of-node-reference-imbalance.patch platform-loongarch-laptop-explicitly-reset-bl_powered-state-when-suspend.patch staging-rtl8723bs-fix-inverted-ht40-secondary-channel-offset.patch staging-rtl8723bs-fix-oob-reads-in-rtw_get_wps_ie.patch wifi-ath11k-fix-refcount-leak-in-ath11k_ahb_fw_resources_init.patch wifi-ath12k-fix-null-pointer-dereference-in-rhash-table-destroy.patch wifi-ath6kl-fix-oob-access-from-firmware-addba-window-size.patch wifi-ath6kl-fix-use-after-free-in-aggr_reset_state.patch wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch wifi-brcmfmac-make-release_scratchbuffers-idempotent.patch wifi-brcmfmac-set-f2-blocksize-to-256-for-bcm43752.patch wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch wifi-mt76-mt7921-drop-txrx_notify-on-non-mmio-buses.patch wifi-mt76-mt7925-drop-txrx_notify-on-non-mmio-buses.patch wifi-mt76-restrict-npu-ppe-active-checks-to-mmio-devices.patch wifi-mwifiex-fix-null-dereference-when-the-ap-has-ht-cap-but-no-ht-oper.patch wifi-wilc1000-validate-assoc-response-length-before-subtracting-header.patch --- diff --git a/queue-7.1/alsa-hda-codecs-hdmi-disable-keep-alive-before-audio-format-change.patch b/queue-7.1/alsa-hda-codecs-hdmi-disable-keep-alive-before-audio-format-change.patch new file mode 100644 index 0000000000..2355bbd789 --- /dev/null +++ b/queue-7.1/alsa-hda-codecs-hdmi-disable-keep-alive-before-audio-format-change.patch @@ -0,0 +1,131 @@ +From a3d6d3cedfe87bbd5a677d52b22ac20d28e59cf8 Mon Sep 17 00:00:00 2001 +From: Kai Vehmanen +Date: Wed, 15 Jul 2026 21:06:10 +0300 +Subject: ALSA: hda: codecs: hdmi: disable keep-alive before audio format change + +From: Kai Vehmanen + +commit a3d6d3cedfe87bbd5a677d52b22ac20d28e59cf8 upstream. + +When a keep-alive (KAE) silent stream is active on an Intel HDMI/DP +codec, opening a real PCM stream reprograms the converter format and the +audio infoframe in snd_hda_hdmi_generic_pcm_prepare(). Part of that +reprogramming - the converter channel count and the channel mapping in +snd_hda_hdmi_setup_audio_infoframe() - is not safe to do while a +keep-alive stream is active. This is most visible when switching to a +multichannel PCM configuration, where the active channel count actually +changes. In that case the newly opened PCM stream plays no sound. + +Add an optional hdmi_ops .prepare hook, called at the start of the +PCM prepare sequence (before the format and infoframe are touched), and +implement it for HSW+ to release keep-alive. Keep-alive is then +re-enabled as before once the new stream has been set up, in the +setup_stream op. + +Fixes: 15175a4f2bbb ("ALSA: hda/hdmi: add keep-alive support for ADL-P and DG2") +Reported-by: Alexander Kaplan +Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8412 +Tested-by: Alexander Kaplan +Cc: +Signed-off-by: Kai Vehmanen +Link: https://patch.msgid.link/20260715180610.1371243-1-kai.vehmanen@linux.intel.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/hda/codecs/hdmi/hdmi.c | 3 +++ + sound/hda/codecs/hdmi/hdmi_local.h | 9 +++++++++ + sound/hda/codecs/hdmi/intelhdmi.c | 36 ++++++++++++++++++++++++++++++------ + 3 files changed, 42 insertions(+), 6 deletions(-) + +--- a/sound/hda/codecs/hdmi/hdmi.c ++++ b/sound/hda/codecs/hdmi/hdmi.c +@@ -1688,6 +1688,9 @@ int snd_hda_hdmi_generic_pcm_prepare(str + per_pin->channels = substream->runtime->channels; + per_pin->setup = true; + ++ if (spec->ops.prepare) ++ spec->ops.prepare(codec, per_pin); ++ + if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) { + stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core, + substream); +--- a/sound/hda/codecs/hdmi/hdmi_local.h ++++ b/sound/hda/codecs/hdmi/hdmi_local.h +@@ -74,6 +74,15 @@ struct hdmi_ops { + hda_nid_t pin_nid, int dev_id, u32 stream_tag, + int format); + ++ /* ++ * Optional hook invoked at the beginning of the PCM prepare ++ * sequence, before the audio infoframe and stream format are ++ * (re)programmed. Used to disable keep-alive / silent stream so ++ * that the format change is not done while keep-alive is active. ++ */ ++ void (*prepare)(struct hda_codec *codec, ++ struct hdmi_spec_per_pin *per_pin); ++ + void (*pin_cvt_fixup)(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + hda_nid_t cvt_nid); +--- a/sound/hda/codecs/hdmi/intelhdmi.c ++++ b/sound/hda/codecs/hdmi/intelhdmi.c +@@ -418,6 +418,28 @@ static void intel_not_share_assigned_cvt + intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx); + } + ++/* ++ * prepare ops override for HSW+ ++ * ++ * Disable keep-alive before the converter format and audio infoframe are ++ * reprogrammed by the PCM prepare sequence. Changing the audio format (e.g. ++ * the channel count when switching to multichannel PCM) while a keep-alive ++ * stream is active is not safe, so release keep-alive here, early in the ++ * sequence. It is re-enabled once the new stream has been set up, in ++ * i915_hsw_setup_stream(). ++ */ ++static void i915_hsw_prepare(struct hda_codec *codec, ++ struct hdmi_spec_per_pin *per_pin) ++{ ++ struct hdmi_spec *spec = codec->spec; ++ ++ if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin->silent_stream) { ++ silent_stream_set_kae(codec, per_pin, false); ++ /* wait for pending transfers in codec to clear */ ++ usleep_range(100, 200); ++ } ++} ++ + /* setup_stream ops override for HSW+ */ + static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, int dev_id, u32 stream_tag, +@@ -435,15 +457,16 @@ static int i915_hsw_setup_stream(struct + + haswell_verify_D0(codec, cvt_nid, pin_nid); + +- if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { +- silent_stream_set_kae(codec, per_pin, false); +- /* wait for pending transfers in codec to clear */ +- usleep_range(100, 200); +- } +- + res = snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id, + stream_tag, format); + ++ /* ++ * Keep-alive was disabled in i915_hsw_prepare(), re-enable it now. ++ * The pin lookup above resolves to the same per_pin that prepare ++ * used (pin_nid comes from that per_pin), so this stays balanced; a ++ * NULL per_pin only occurs on a lookup failure that also implies no ++ * active keep-alive stream to restore. ++ */ + if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) { + usleep_range(100, 200); + silent_stream_set_kae(codec, per_pin, true); +@@ -607,6 +630,7 @@ static int intel_hsw_common_init(struct + codec->depop_delay = 0; + codec->auto_runtime_pm = 1; + ++ spec->ops.prepare = i915_hsw_prepare; + spec->ops.setup_stream = i915_hsw_setup_stream; + spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup; + spec->ops.silent_stream = i915_set_silent_stream; diff --git a/queue-7.1/alsa-hda-realtek-fix-speakers-on-lunnen-ground-14.patch b/queue-7.1/alsa-hda-realtek-fix-speakers-on-lunnen-ground-14.patch new file mode 100644 index 0000000000..0764541968 --- /dev/null +++ b/queue-7.1/alsa-hda-realtek-fix-speakers-on-lunnen-ground-14.patch @@ -0,0 +1,61 @@ +From 5c3f8dac531b454bf67b6ee3c2aac89f0aaaef74 Mon Sep 17 00:00:00 2001 +From: Nikita Maksimov +Date: Mon, 20 Jul 2026 21:02:14 +0300 +Subject: ALSA: hda/realtek: Fix speakers on Lunnen Ground 14 + +From: Nikita Maksimov + +commit 5c3f8dac531b454bf67b6ee3c2aac89f0aaaef74 upstream. + +The firmware on the Lunnen Ground 14 marks pin 0x1b as unused even +though the internal speakers are connected to it. As a result, the +speakers are not detected. + +Add a pin configuration quirk for PCI subsystem ID 2782:a212 to configure +pin 0x1b as an internal speaker. + +The pin configuration was tested on a Lunnen Ground 14 (DMI product LL4FA) +with an ALC269VC codec. The internal speakers and microphone work as +expected. + +Cc: stable@vger.kernel.org +Signed-off-by: Nikita Maksimov +Link: https://patch.msgid.link/20260720180214.73770-1-nickstogramm@yandex.ru +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/hda/codecs/realtek/alc269.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -3891,6 +3891,7 @@ enum { + ALC269_FIXUP_DMIC_THINKPAD_ACPI, + ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13, + ALC269VC_FIXUP_INFINIX_Y4_MAX, ++ ALC269VC_FIXUP_LUNNEN_GROUND_14, + ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO, + ALC255_FIXUP_ACER_MIC_NO_PRESENCE, + ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, +@@ -4345,6 +4346,13 @@ static const struct hda_fixup alc269_fix + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, ++ [ALC269VC_FIXUP_LUNNEN_GROUND_14] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x1b, 0x90170150 }, /* internal speaker */ ++ { } ++ }, ++ }, + [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -7875,6 +7883,7 @@ static const struct hda_quirk alc269_fix + SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX), + SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK), ++ SND_PCI_QUIRK(0x2782, 0xa212, "Lunnen Ground 14", ALC269VC_FIXUP_LUNNEN_GROUND_14), + SND_PCI_QUIRK(0x7017, 0x2014, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER), + SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), + SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), diff --git a/queue-7.1/alsa-seq-close-a-re-opened-queue-timer-in-the-destructor.patch b/queue-7.1/alsa-seq-close-a-re-opened-queue-timer-in-the-destructor.patch new file mode 100644 index 0000000000..c8d6a72578 --- /dev/null +++ b/queue-7.1/alsa-seq-close-a-re-opened-queue-timer-in-the-destructor.patch @@ -0,0 +1,74 @@ +From 2c4dc0ed50b05cd847a4b34b8cebf0775f19aeb9 Mon Sep 17 00:00:00 2001 +From: Norbert Szetei +Date: Tue, 14 Jul 2026 10:29:23 +0200 +Subject: ALSA: seq: close a re-opened queue timer in the destructor + +From: Norbert Szetei + +commit 2c4dc0ed50b05cd847a4b34b8cebf0775f19aeb9 upstream. + +queue_delete() closes the queue timer, then frees it. snd_seq_timer_close() +clears q->timer->timeri. snd_use_lock_sync() then drains borrowers, and +snd_seq_timer_delete() frees q->timer. + +A borrower can re-open the timer inside that window. A SET_QUEUE_CLIENT +that took a queueptr() use_lock reference before the queue was unlinked +runs snd_seq_timer_open() after the close. Open refuses re-open only while +timeri is set, and the close just cleared it, so it re-opens timeri. + +snd_seq_timer_delete() does not close that instance. Its snd_seq_timer_stop() +is a no-op, because running was cleared first. So it frees q->timer with the +instance still live. The queue is freed next. + +The instance stays on the global timer with callback_data pointing at the +freed queue. A non-owner START on the unlocked queue arms it. The next tick +derefs the freed queue in snd_seq_timer_interrupt(). + +Reachable by an unprivileged user with access to /dev/snd/seq. No CAP and +no queue ownership required. + +Close any lingering instance in the destructor. There, ->timeri can no +longer change: the queue is unlinked and all use_lock borrowers have +drained, so no snd_seq_queue_use() can re-open it. Close it before clearing +q->timer. snd_timer_close() waits for any in-flight snd_seq_timer_interrupt() +to finish, and that callback still reads q->timer (via snd_seq_check_queue()), +so q->timer must stay valid until it drains. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Norbert Szetei +Link: https://patch.msgid.link/422FDB81-2A68-47C7-A22D-2D3301E2E86D@doyensec.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/seq/seq_timer.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/sound/core/seq/seq_timer.c ++++ b/sound/core/seq/seq_timer.c +@@ -61,12 +61,23 @@ struct snd_seq_timer *snd_seq_timer_new( + void snd_seq_timer_delete(struct snd_seq_timer **tmr) + { + struct snd_seq_timer *t = *tmr; +- *tmr = NULL; ++ struct snd_timer_instance *ti; + + if (t == NULL) { + pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n"); + return; + } ++ ++ scoped_guard(spinlock_irq, &t->lock) { ++ ti = t->timeri; ++ t->timeri = NULL; ++ } ++ if (ti) { ++ snd_timer_close(ti); ++ snd_timer_instance_free(ti); ++ } ++ ++ *tmr = NULL; + t->running = 0; + + /* reset time */ diff --git a/queue-7.1/alsa-timer-don-t-re-enter-an-instance-callback-that-is-still-running.patch b/queue-7.1/alsa-timer-don-t-re-enter-an-instance-callback-that-is-still-running.patch new file mode 100644 index 0000000000..b9eb8cd696 --- /dev/null +++ b/queue-7.1/alsa-timer-don-t-re-enter-an-instance-callback-that-is-still-running.patch @@ -0,0 +1,64 @@ +From 70d28bfcd6224eed75986b3b987b997e59643fa4 Mon Sep 17 00:00:00 2001 +From: Norbert Szetei +Date: Mon, 20 Jul 2026 09:09:55 +0200 +Subject: ALSA: timer: don't re-enter an instance callback that is still running + +From: Norbert Szetei + +commit 70d28bfcd6224eed75986b3b987b997e59643fa4 upstream. + +The userspace-driven timer (utimer) TRIGGER ioctl calls +snd_timer_interrupt() directly with no serialization, so two threads +triggering the same utimer can run snd_timer_interrupt() on one +snd_timer concurrently. + +snd_timer_process_callbacks() drops timer->lock around each instance +callback and marks the in-flight callback with the single +SNDRV_TIMER_IFLG_CALLBACK bit; snd_timer_close_locked() waits on that +bit to drain an in-flight callback before freeing the instance. The bit +cannot represent two concurrent callbacks: when a second interrupt +re-queues an instance whose callback is still running, both run at once, +the first to finish clears the bit, and the close-path drain then frees +the instance (and its callback_data) while the other callback is still +live - a use-after-free reachable by any user able to open +/dev/snd/timer, both via a user timer instance and via a sequencer queue +timer bound to the utimer. + +snd_timer_interrupt() sets IFLG_CALLBACK before dropping timer->lock, so +a concurrent interrupt already observes it under the lock. Skip +re-queuing an instance (and its slaves) to the ack/sack list while its +callback is in flight; the accumulated pticks are delivered on the next +tick, so no event is lost. + +Fixes: 37745918e0e7 ("ALSA: timer: Introduce virtual userspace-driven timers") +Cc: stable@vger.kernel.org +Suggested-by: Takashi Iwai +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Norbert Szetei +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/6F9B6501-8E65-4265-B02C-7EFB240D1664@doyensec.com +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/timer.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -894,12 +894,15 @@ void snd_timer_interrupt(struct snd_time + ack_list_head = &timer->ack_list_head; + else + ack_list_head = &timer->sack_list_head; +- if (list_empty(&ti->ack_list)) ++ /* don't requeue an instance whose callback is still running */ ++ if (list_empty(&ti->ack_list) && ++ !(ti->flags & SNDRV_TIMER_IFLG_CALLBACK)) + list_add_tail(&ti->ack_list, ack_list_head); + list_for_each_entry(ts, &ti->slave_active_head, active_list) { + ts->pticks = ti->pticks; + ts->resolution = resolution; +- if (list_empty(&ts->ack_list)) ++ if (list_empty(&ts->ack_list) && ++ !(ts->flags & SNDRV_TIMER_IFLG_CALLBACK)) + list_add_tail(&ts->ack_list, ack_list_head); + } + } diff --git a/queue-7.1/alsa-timer-drain-a-slave-s-callback-before-its-master-detaches-it.patch b/queue-7.1/alsa-timer-drain-a-slave-s-callback-before-its-master-detaches-it.patch new file mode 100644 index 0000000000..38571a38a2 --- /dev/null +++ b/queue-7.1/alsa-timer-drain-a-slave-s-callback-before-its-master-detaches-it.patch @@ -0,0 +1,60 @@ +From bdefe1346a8e6b8dc8593406dc2617e985fcbcab Mon Sep 17 00:00:00 2001 +From: Norbert Szetei +Date: Mon, 20 Jul 2026 09:14:12 +0200 +Subject: ALSA: timer: drain a slave's callback before its master detaches it + +From: Norbert Szetei + +commit bdefe1346a8e6b8dc8593406dc2617e985fcbcab upstream. + +snd_timer_close_locked() drains the closing instance's own in-flight +callback (IFLG_CALLBACK) before freeing it, but not its slaves'. When a +master instance is closed, remove_slave_links() clears each slave's +->timer; the slave's own close then reads timer == NULL and takes the +branch that skips the drain entirely (snd_timer_stop_slave() also no-ops +on a NULL timer). So a slave whose callback is still running when the +master is closed is freed underneath the live callback, leading to +use-after-free. + +Drain the slaves too before remove_slave_links() severs them. +snd_timer_stop() has already taken this instance off the active list, so +no new slave callback can be queued. Take the slaves off the ack list so +a pending one can't fire either, then wait for any that is already in +flight. + +Fixes: 37745918e0e7 ("ALSA: timer: Introduce virtual userspace-driven timers") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Norbert Szetei +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/D26598EB-DBF7-4D76-9F71-8E4BD59822D4@doyensec.com +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/timer.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -448,10 +448,20 @@ static void snd_timer_close_locked(struc + snd_timer_stop(timeri); + + if (timer) { ++ struct snd_timer_instance *slave; ++ bool busy; ++ + timer->num_instances--; +- /* wait, until the active callback is finished */ ++ /* unqueue then drain the slaves' callbacks before remove_slave_links() severs them */ + spin_lock_irq(&timer->lock); +- while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { ++ list_for_each_entry(slave, &timeri->slave_list_head, open_list) ++ list_del_init(&slave->ack_list); ++ for (;;) { ++ busy = timeri->flags & SNDRV_TIMER_IFLG_CALLBACK; ++ list_for_each_entry(slave, &timeri->slave_list_head, open_list) ++ busy |= slave->flags & SNDRV_TIMER_IFLG_CALLBACK; ++ if (!busy) ++ break; + spin_unlock_irq(&timer->lock); + udelay(10); + spin_lock_irq(&timer->lock); diff --git a/queue-7.1/binfmt_misc-set-have_execfd-only-once-the-interpreter-is-opened.patch b/queue-7.1/binfmt_misc-set-have_execfd-only-once-the-interpreter-is-opened.patch new file mode 100644 index 0000000000..a5f9c5ccbe --- /dev/null +++ b/queue-7.1/binfmt_misc-set-have_execfd-only-once-the-interpreter-is-opened.patch @@ -0,0 +1,72 @@ +From bbf5f639918dc011aaf60aab8480218758ee68c5 Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Mon, 20 Jul 2026 14:36:49 +0200 +Subject: binfmt_misc: set have_execfd only once the interpreter is opened + +From: Christian Brauner + +commit bbf5f639918dc011aaf60aab8480218758ee68c5 upstream. + +load_misc_binary() raises bprm->have_execfd as soon as it sees the 'O' +(or 'C') flag. This happens well before it opens the interpreter. If +that open fails the flag stays set on the bprm. binfmt_misc is at the +head of the format list so an interpreter open failure that returns +-ENOEXEC lets the search fall through to a later format. This means it +runs the matched binary directly having never staged an interpreter. So +bprm->executable is NULL while have_execfd falsely claims a descriptor +is present. + +Consequently, begin_new_exec() dereferences the missing executable: + + would_dump(bprm, bprm->executable); + +and NULL derefs. Had it not, the hand-off later in the same function +would have failed anyway. FD_ADD(0, bprm->executable) rejects a NULL +file with -ENOMEM. Both sites are past the point of no return so the +exec cannot be unwound either way. + +This can be reached by unprivileged users as binfmt_misc can be mounted +in user namespaces. So a user can register an 'O' entry whose +interpreter lives on a FUSE mount, have the FUSE server fail the open +with -ENOEXEC and execute a native ELF file that matches the entry. + +have_execfd only means anything alongside the executable it describes +which is not set until the interpreter has been opened and staged. +So lets raise it there, next to execfd_creds, which is already set at +that point. An open failure now leaves it clear, so the fallback format +derives credentials from the binary and emits no AT_EXECFD, as it would +for any native exec. The argv rewrite load_misc_binary() performs before +the open is still not undone. This means the binary sees the interpreter +path in argv[0] and its own path in argv[1] but that predates this +change and only became observable once the exec stopped faulting. + +Link: https://patch.msgid.link/20260720-beglichen-kognitiv-organismus-5e1e55326c56@brauner +Fixes: bc2bf338d54b ("exec: Remove recursion from search_binary_handler") +Cc: stable@vger.kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -228,9 +228,6 @@ static int load_misc_binary(struct linux + goto ret; + } + +- if (fmt->flags & MISC_FMT_OPEN_BINARY) +- bprm->have_execfd = 1; +- + /* make argv[1] be the path to the binary */ + retval = copy_string_kernel(bprm->interp, bprm); + if (retval < 0) +@@ -260,6 +257,8 @@ static int load_misc_binary(struct linux + goto ret; + + bprm->interpreter = interp_file; ++ if (fmt->flags & MISC_FMT_OPEN_BINARY) ++ bprm->have_execfd = 1; + if (fmt->flags & MISC_FMT_CREDENTIALS) + bprm->execfd_creds = 1; + diff --git a/queue-7.1/bluetooth-hci_sync-protect-uuid-list-traversal.patch b/queue-7.1/bluetooth-hci_sync-protect-uuid-list-traversal.patch new file mode 100644 index 0000000000..3958287382 --- /dev/null +++ b/queue-7.1/bluetooth-hci_sync-protect-uuid-list-traversal.patch @@ -0,0 +1,103 @@ +From e9027ffbf5a0f3c12ca8900822e884eae9f0821b Mon Sep 17 00:00:00 2001 +From: Chengfeng Ye +Date: Mon, 20 Jul 2026 00:24:27 +0800 +Subject: Bluetooth: hci_sync: Protect UUID list traversal + +From: Chengfeng Ye + +commit e9027ffbf5a0f3c12ca8900822e884eae9f0821b upstream. + +The hci_sync conversion moved class-of-device and EIR generation from an +HCI request built under hdev->lock to asynchronous command sync work. +The worker holds hdev->req_lock, but that lock does not serialize access +to hdev->uuids against add_uuid() and remove_uuid(), which update the +list under hdev->lock. + +The following interleaving can therefore occur: + + CPU0 (command sync work) CPU1 (management socket) + fetch uuid from the list + list_del(&uuid->list) + kfree(uuid) + read uuid->size + +KASAN reports the resulting use-after-free: + + BUG: KASAN: slab-use-after-free in eir_create+0xb8f/0xee0 + Read of size 1 at addr ffff88810dbd8620 by task kworker/u17:0/87 + Workqueue: hci0 hci_cmd_sync_work + Call Trace: + eir_create+0xb8f/0xee0 + hci_update_eir_sync+0x1c0/0x330 + hci_cmd_sync_work+0x13c/0x290 + process_one_work+0x63a/0x1070 + worker_thread+0x45b/0xd10 + + Allocated by task 86: + __kasan_kmalloc+0x8f/0xa0 + add_uuid+0x18a/0x4b0 + hci_sock_sendmsg+0x1033/0x1ea0 + + Freed by task 92: + __kasan_slab_free+0x43/0x70 + kfree+0x131/0x3c0 + remove_uuid+0x25e/0x560 + hci_sock_sendmsg+0x1033/0x1ea0 + +Hold hdev->lock while generating and committing the class-of-device and +EIR snapshots. Release it before sending an HCI command, so controller +waits do not happen under the device lock. This protects all UUID list +walks in these paths and restores the serialization lost in the command +sync conversion. + +Fixes: 161510ccf91c ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 1") +Cc: stable@vger.kernel.org +Signed-off-by: Chengfeng Ye +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/hci_sync.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -929,12 +929,16 @@ int hci_update_eir_sync(struct hci_dev * + + memset(&cp, 0, sizeof(cp)); + ++ hci_dev_lock(hdev); + eir_create(hdev, cp.data); + +- if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) ++ if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) { ++ hci_dev_unlock(hdev); + return 0; ++ } + + memcpy(hdev->eir, cp.data, sizeof(cp.data)); ++ hci_dev_unlock(hdev); + + return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp, + HCI_CMD_TIMEOUT); +@@ -966,6 +970,7 @@ int hci_update_class_sync(struct hci_dev + if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE)) + return 0; + ++ hci_dev_lock(hdev); + cod[0] = hdev->minor_class; + cod[1] = hdev->major_class; + cod[2] = get_service_classes(hdev); +@@ -973,8 +978,12 @@ int hci_update_class_sync(struct hci_dev + if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) + cod[1] |= 0x20; + +- if (memcmp(cod, hdev->dev_class, 3) == 0) ++ if (memcmp(cod, hdev->dev_class, 3) == 0) { ++ hci_dev_unlock(hdev); + return 0; ++ } ++ ++ hci_dev_unlock(hdev); + + return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CLASS_OF_DEV, + sizeof(cod), cod, HCI_CMD_TIMEOUT); diff --git a/queue-7.1/bluetooth-rfcomm-fix-session-uaf-in-set_termios.patch b/queue-7.1/bluetooth-rfcomm-fix-session-uaf-in-set_termios.patch new file mode 100644 index 0000000000..6b1f299168 --- /dev/null +++ b/queue-7.1/bluetooth-rfcomm-fix-session-uaf-in-set_termios.patch @@ -0,0 +1,128 @@ +From c783399efc22d035443f1dfbf2a09bf9562aaa5e Mon Sep 17 00:00:00 2001 +From: Chengfeng Ye +Date: Mon, 20 Jul 2026 00:03:11 +0800 +Subject: Bluetooth: RFCOMM: Fix session UAF in set_termios + +From: Chengfeng Ye + +commit c783399efc22d035443f1dfbf2a09bf9562aaa5e upstream. + +rfcomm_tty_set_termios() tests dlc->session without rfcomm_mutex and +later passes the pointer to rfcomm_send_rpn(). The latter dereferences +both session->initiator and session->sock. Meanwhile, krfcommd can +unlink the DLC and free the session while holding rfcomm_mutex. + +The race can proceed as follows: + + TTY ioctl task krfcommd + -------------- -------- + load dlc->session + enter rfcomm_send_rpn() + lock rfcomm_mutex + clear dlc->session + free session + unlock rfcomm_mutex + read session->initiator + +KASAN reported: + + BUG: KASAN: slab-use-after-free in rfcomm_send_rpn+0x297/0x2a0 + Read of size 4 at addr ffff88810012a850 by task poc/92 + + Call Trace: + rfcomm_send_rpn+0x297/0x2a0 + rfcomm_tty_set_termios+0x50d/0x850 + tty_set_termios+0x596/0x950 + set_termios+0x46a/0x6e0 + tty_mode_ioctl+0x152/0xbd0 + tty_ioctl+0x915/0x1240 + __x64_sys_ioctl+0x134/0x1c0 + + Allocated by task 92: + rfcomm_session_add+0x9e/0x2e0 + rfcomm_dlc_open+0x8b1/0xe00 + rfcomm_dev_activate+0x85/0x1a0 + rfcomm_tty_open+0x90/0x280 + + Freed by task 68: + kfree+0x131/0x3c0 + rfcomm_session_del+0x119/0x180 + rfcomm_run+0x737/0x4710 + +Add rfcomm_dlc_send_rpn(), which holds rfcomm_mutex while it verifies +that the DLC is still attached and sends the RPN frame. Have the TTY +path use the helper and drop its unlocked session check. This keeps the +session valid through both the frame construction and socket send. + +Fixes: 3a5e903c09ae ("[Bluetooth]: Implement RFCOMM remote port negotiation") +Cc: stable@vger.kernel.org +Signed-off-by: Chengfeng Ye +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + include/net/bluetooth/rfcomm.h | 3 +++ + net/bluetooth/rfcomm/core.c | 17 +++++++++++++++++ + net/bluetooth/rfcomm/tty.c | 7 +++---- + 3 files changed, 23 insertions(+), 4 deletions(-) + +--- a/include/net/bluetooth/rfcomm.h ++++ b/include/net/bluetooth/rfcomm.h +@@ -229,6 +229,9 @@ int rfcomm_send_rpn(struct rfcomm_sessio + u8 bit_rate, u8 data_bits, u8 stop_bits, + u8 parity, u8 flow_ctrl_settings, + u8 xon_char, u8 xoff_char, u16 param_mask); ++int rfcomm_dlc_send_rpn(struct rfcomm_dlc *d, u8 bit_rate, u8 data_bits, ++ u8 stop_bits, u8 parity, u8 flow_ctrl_settings, ++ u8 xon_char, u8 xoff_char, u16 param_mask); + + /* ---- RFCOMM DLCs (channels) ---- */ + struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio); +--- a/net/bluetooth/rfcomm/core.c ++++ b/net/bluetooth/rfcomm/core.c +@@ -1031,6 +1031,23 @@ int rfcomm_send_rpn(struct rfcomm_sessio + return rfcomm_send_frame(s, buf, ptr - buf); + } + ++int rfcomm_dlc_send_rpn(struct rfcomm_dlc *d, u8 bit_rate, u8 data_bits, ++ u8 stop_bits, u8 parity, u8 flow_ctrl_settings, ++ u8 xon_char, u8 xoff_char, u16 param_mask) ++{ ++ int err = -ENOTCONN; ++ ++ rfcomm_lock(); ++ if (d->session) ++ err = rfcomm_send_rpn(d->session, 1, d->dlci, bit_rate, ++ data_bits, stop_bits, parity, ++ flow_ctrl_settings, xon_char, xoff_char, ++ param_mask); ++ rfcomm_unlock(); ++ ++ return err; ++} ++ + static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) + { + struct rfcomm_hdr *hdr; +--- a/net/bluetooth/rfcomm/tty.c ++++ b/net/bluetooth/rfcomm/tty.c +@@ -861,7 +861,7 @@ static void rfcomm_tty_set_termios(struc + + BT_DBG("tty %p termios %p", tty, old); + +- if (!dev || !dev->dlc || !dev->dlc->session) ++ if (!dev || !dev->dlc) + return; + + /* Handle turning off CRTSCTS */ +@@ -982,9 +982,8 @@ static void rfcomm_tty_set_termios(struc + } + + if (changes) +- rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud, +- data_bits, stop_bits, parity, +- RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes); ++ rfcomm_dlc_send_rpn(dev->dlc, baud, data_bits, stop_bits, parity, ++ RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes); + } + + static void rfcomm_tty_throttle(struct tty_struct *tty) diff --git a/queue-7.1/exec-fix-unsigned-loop-counter-wrap-in-transfer_args_to_stack.patch b/queue-7.1/exec-fix-unsigned-loop-counter-wrap-in-transfer_args_to_stack.patch new file mode 100644 index 0000000000..79f843fdd1 --- /dev/null +++ b/queue-7.1/exec-fix-unsigned-loop-counter-wrap-in-transfer_args_to_stack.patch @@ -0,0 +1,79 @@ +From 16cc4f5c1c4b9e45eca7f7deefa5410a292db599 Mon Sep 17 00:00:00 2001 +From: Christian Brauner +Date: Tue, 21 Jul 2026 12:08:49 +0200 +Subject: exec: fix unsigned loop counter wrap in transfer_args_to_stack() + +From: Christian Brauner + +commit 16cc4f5c1c4b9e45eca7f7deefa5410a292db599 upstream. + +The stop value is derived from bprm->p >> PAGE_SHIFT. The index variable +is an unsigned long. If bprm->p drops below PAGE_SIZE and stop becomes +zero the loop condition index >= stop is always true. + +After the index == 0 iteration the decrement wraps to ULONG_MAX and +bprm->page[ULONG_MAX] reads sizeof(void *) bytes in front of the array. +The pointer has wrapped to -1. That garbage pointer is then passed to +kmap_local_page() and PAGE_SIZE bytes are copied from wherever that +lands into the stack of the process being created. And the loop doesn't +terminate either... + +Getting there only requires bprm->p < PAGE_SIZE. On !MMU +bprm_set_stack_limit() and bprm_hit_stack_limit() are empty. So the only +constraint on how far bprm->p is pushed down is valid_arg_len(), i.e. +that each individual string still fits in what is left. + +bprm->p starts at PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *) so a +single argument or environment string of a little over 31 pages leaves +it in the first page: + + Oops - load access fault [#1] + CPU: 0 UID: 0 PID: 1 Comm: victim Not tainted 7.2.0-rc4 #1 + epc : __memcpy+0xd4/0xf8 + ra : transfer_args_to_stack+0xaa/0xae + s4 : ffffffffffffffff s2 : 0000000000000000 + a1 : ffffffdc98000000 a2 : 0000000000001000 + status: 0000000a00001880 badaddr: ffffffdc98000000 cause: 0000000000000005 + [<801a5324>] __memcpy+0xd4/0xf8 + [<800d5f6a>] load_flat_binary+0x43a/0x65e + [<800a2de4>] bprm_execve+0x1d4/0x316 + [<800a351a>] do_execveat_common+0x12e/0x138 + [<800a3d44>] __riscv_sys_execve+0x38/0x4e + Kernel panic - not syncing: Fatal exception in interrupt + +This is an arcane bug but we should still fix it. + +Count down from MAX_ARG_PAGES so the loop ends when index reaches stop, +stop == 0 included. The iterations performed are unchanged for every +other value of stop. + +Only CONFIG_MMU=n builds are affected, transfer_args_to_stack() is used +by binfmt_flat and binfmt_elf_fdpic on nommu only. + +The loop predates git history. commit 7e7ec6a93434 +("elf_fdpic_transfer_args_to_stack(): make it generic") only moved it +from binfmt_elf_fdpic.c into fs/exec.c and narrowed the copy to the used +part of the first page. The condition and the decrement are unchanged +from 2.6.12-rc2. + +Link: https://patch.msgid.link/20260721-hochachtung-staumauer-pigmente-15d71f7d7d04@brauner +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Reviewed-by: David Hildenbrand (Arm) +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Greg Kroah-Hartman +--- + fs/exec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -736,7 +736,7 @@ int transfer_args_to_stack(struct linux_ + stop = bprm->p >> PAGE_SHIFT; + sp = *sp_location; + +- for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { ++ for (index = MAX_ARG_PAGES; index-- > stop; ) { + unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0; + char *src = kmap_local_page(bprm->page[index]) + offset; + sp -= PAGE_SIZE - offset; diff --git a/queue-7.1/media-nxp-imx8-isi-clean-up-already-initialized-pipes-on-probe-failure.patch b/queue-7.1/media-nxp-imx8-isi-clean-up-already-initialized-pipes-on-probe-failure.patch new file mode 100644 index 0000000000..cdfbc11cdf --- /dev/null +++ b/queue-7.1/media-nxp-imx8-isi-clean-up-already-initialized-pipes-on-probe-failure.patch @@ -0,0 +1,40 @@ +From d970b27cc48ec42f8a72bc3a4a4ad2e5c7a36395 Mon Sep 17 00:00:00 2001 +From: Xiaolei Wang +Date: Thu, 7 May 2026 12:13:18 +0800 +Subject: media: nxp: imx8-isi: Clean up already-initialized pipes on probe failure + +From: Xiaolei Wang + +commit d970b27cc48ec42f8a72bc3a4a4ad2e5c7a36395 upstream. + +When mxc_isi_pipe_init() fails partway through the channel loop or +when mxc_isi_v4l2_init() fails, the already initialized pipes are +not cleaned up. + +Fix this by calling mxc_isi_pipe_cleanup() for each already-initialized +pipe in the err_xbar error path. + +Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver") +Cc: stable@vger.kernel.org +Signed-off-by: Xiaolei Wang +Reviewed-by: Laurent Pinchart +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260507041318.491594-5-xiaolei.wang@windriver.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +@@ -538,6 +538,8 @@ static int mxc_isi_probe(struct platform + return 0; + + err_xbar: ++ while (i--) ++ mxc_isi_pipe_cleanup(&isi->pipes[i]); + mxc_isi_crossbar_cleanup(&isi->crossbar); + + return ret; diff --git a/queue-7.1/media-nxp-imx8-isi-fix-missing-v4l2_subdev_cleanup-in-pipe-init-error-path.patch b/queue-7.1/media-nxp-imx8-isi-fix-missing-v4l2_subdev_cleanup-in-pipe-init-error-path.patch new file mode 100644 index 0000000000..5447a1d7b7 --- /dev/null +++ b/queue-7.1/media-nxp-imx8-isi-fix-missing-v4l2_subdev_cleanup-in-pipe-init-error-path.patch @@ -0,0 +1,55 @@ +From 8262de0663318124824aaafd97ddb5d7bb53bd77 Mon Sep 17 00:00:00 2001 +From: Xiaolei Wang +Date: Thu, 7 May 2026 12:13:17 +0800 +Subject: media: nxp: imx8-isi: Fix missing v4l2_subdev_cleanup() in pipe init error path + +From: Xiaolei Wang + +commit 8262de0663318124824aaafd97ddb5d7bb53bd77 upstream. + +After v4l2_subdev_init_finalize() succeeds in mxc_isi_pipe_init(), if +platform_get_irq() or devm_request_irq() fails, the error path jumps to +a label that only calls media_entity_cleanup() and mutex_destroy(), +missing the v4l2_subdev_cleanup() call needed to free the subdev active +state allocated by v4l2_subdev_init_finalize(). + +Add an error_subdev label that calls v4l2_subdev_cleanup() before +falling through to the existing error cleanup. + +Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver") +Cc: stable@vger.kernel.org +Signed-off-by: Xiaolei Wang +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260507041318.491594-4-xiaolei.wang@windriver.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +@@ -796,18 +796,20 @@ int mxc_isi_pipe_init(struct mxc_isi_dev + irq = platform_get_irq(to_platform_device(isi->dev), id); + if (irq < 0) { + ret = irq; +- goto error; ++ goto error_subdev; + } + + ret = devm_request_irq(isi->dev, irq, mxc_isi_pipe_irq_handler, + 0, dev_name(isi->dev), pipe); + if (ret < 0) { + dev_err(isi->dev, "failed to request IRQ (%d)\n", ret); +- goto error; ++ goto error_subdev; + } + + return 0; + ++error_subdev: ++ v4l2_subdev_cleanup(sd); + error: + media_entity_cleanup(&sd->entity); + mutex_destroy(&pipe->lock); diff --git a/queue-7.1/media-nxp-imx8-isi-fix-potential-out-of-bounds-issues.patch b/queue-7.1/media-nxp-imx8-isi-fix-potential-out-of-bounds-issues.patch new file mode 100644 index 0000000000..93b5a83abb --- /dev/null +++ b/queue-7.1/media-nxp-imx8-isi-fix-potential-out-of-bounds-issues.patch @@ -0,0 +1,105 @@ +From 57a7ec5c9f38ce6c4d6209c4b75c8e57e1fea6cf Mon Sep 17 00:00:00 2001 +From: Guoniu Zhou +Date: Mon, 23 Mar 2026 16:33:30 +0800 +Subject: media: nxp: imx8-isi: Fix potential out-of-bounds issues + +From: Guoniu Zhou + +commit 57a7ec5c9f38ce6c4d6209c4b75c8e57e1fea6cf upstream. + +The maximum downscaling factor supported by ISI can be up to 16. Add +minimum value constraint before applying the setting to hardware. +Otherwise, the process will not respond even when Ctrl+C is executed. + +Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver") +Cc: stable@vger.kernel.org +Reviewed-by: Frank Li +Signed-off-by: Guoniu Zhou +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260323-isi-v3-1-8df53b24e622@oss.nxp.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h | 16 ++++++++++++++++ + drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c | 11 ++++++++--- + drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c | 13 ++++++++----- + 3 files changed, 32 insertions(+), 8 deletions(-) + +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +@@ -11,6 +11,7 @@ + #define __MXC_ISI_CORE_H__ + + #include ++#include + #include + #include + #include +@@ -414,4 +415,19 @@ static inline void mxc_isi_debug_cleanup + } + #endif + ++/* ++ * ISI scaling engine works in two parts: it performs pre-decimation of ++ * the image followed by bilinear filtering to achieve the desired ++ * downscaling factor. ++ * ++ * The decimation filter provides a maximum downscaling factor of 8, and ++ * the subsequent bilinear filter provides a maximum downscaling factor ++ * of 2. Combined, the maximum scaling factor can be up to 16. ++ */ ++static inline unsigned int ++mxc_isi_clamp_downscale_16(unsigned int val, unsigned int max_val) ++{ ++ return clamp(val, max(1U, DIV_ROUND_UP(max_val, 16)), max_val); ++} ++ + #endif /* __MXC_ISI_CORE_H__ */ +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +@@ -509,9 +509,14 @@ __mxc_isi_m2m_try_fmt_vid(struct mxc_isi + const enum mxc_isi_video_type type) + { + if (type == MXC_ISI_VIDEO_M2M_CAP) { +- /* Downscaling only */ +- pix->width = min(pix->width, ctx->queues.out.format.width); +- pix->height = min(pix->height, ctx->queues.out.format.height); ++ const struct v4l2_pix_format_mplane *format = ++ &ctx->queues.out.format; ++ ++ /* Downscaling only, by up to 16. */ ++ pix->width = mxc_isi_clamp_downscale_16(pix->width, ++ format->width); ++ pix->height = mxc_isi_clamp_downscale_16(pix->height, ++ format->height); + } + + return mxc_isi_format_try(ctx->m2m->pipe, pix, type); +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +@@ -641,16 +641,19 @@ static int mxc_isi_pipe_set_selection(st + /* Composing is supported on the sink only. */ + return -EINVAL; + +- /* The sink crop is bound by the sink format downscaling only). */ ++ /* ++ * The ISI supports downscaling only, with a factor up to 16. ++ * Clamp the compose rectangle size accordingly. ++ */ + format = mxc_isi_pipe_get_pad_format(pipe, state, + MXC_ISI_PIPE_PAD_SINK); + + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH, +- format->width); +- sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT, +- format->height); ++ sel->r.width = mxc_isi_clamp_downscale_16(sel->r.width, ++ format->width); ++ sel->r.height = mxc_isi_clamp_downscale_16(sel->r.height, ++ format->height); + + rect = mxc_isi_pipe_get_pad_compose(pipe, state, + MXC_ISI_PIPE_PAD_SINK); diff --git a/queue-7.1/media-nxp-imx8-isi-fix-scale-factor-calculation-for-hardware-rounding.patch b/queue-7.1/media-nxp-imx8-isi-fix-scale-factor-calculation-for-hardware-rounding.patch new file mode 100644 index 0000000000..fb1aa1c948 --- /dev/null +++ b/queue-7.1/media-nxp-imx8-isi-fix-scale-factor-calculation-for-hardware-rounding.patch @@ -0,0 +1,44 @@ +From 5eb54da3f874b44149556542d949909898865e29 Mon Sep 17 00:00:00 2001 +From: Guoniu Zhou +Date: Mon, 23 Mar 2026 16:33:31 +0800 +Subject: media: nxp: imx8-isi: Fix scale factor calculation for hardware rounding + +From: Guoniu Zhou + +commit 5eb54da3f874b44149556542d949909898865e29 upstream. + +The ISI hardware rounds the actual output size up to an integer, as +described in i.MX93 Reference Manual section 57.7.8 (Channel 0 Scale +Factor). The scale factor must be calculated to ensure the theoretical +output value rounds up to exactly the desired size. + +Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver") +Cc: stable@vger.kernel.org +Signed-off-by: Guoniu Zhou +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260323-isi-v3-2-8df53b24e622@oss.nxp.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +@@ -112,7 +112,14 @@ static u32 mxc_isi_channel_scaling_ratio + else + *dec = 8; + +- return min_t(u32, from * 0x1000 / (to * *dec), ISI_DOWNSCALE_THRESHOLD); ++ /* ++ * The ISI rounds output dimensions up to the next integer (i.MX93 RM ++ * section 57.7.8). Calculate the scale factor such that the theoretical ++ * output (input / scale_factor) rounds up to exactly the desired ++ * output. ++ */ ++ return min_t(u32, DIV_ROUND_UP(from * 0x1000, to * *dec), ++ ISI_DOWNSCALE_THRESHOLD); + } + + static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe, diff --git a/queue-7.1/media-pci-dm1105-free-allocated-workqueue.patch b/queue-7.1/media-pci-dm1105-free-allocated-workqueue.patch new file mode 100644 index 0000000000..a783d9b829 --- /dev/null +++ b/queue-7.1/media-pci-dm1105-free-allocated-workqueue.patch @@ -0,0 +1,31 @@ +From 1a65db225b25bb8c8febf16974c060e0cc242eb9 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Tue, 28 Apr 2026 16:50:08 +0200 +Subject: media: pci: dm1105: Free allocated workqueue + +From: Krzysztof Kozlowski + +commit 1a65db225b25bb8c8febf16974c060e0cc242eb9 upstream. + +Destroy allocated workqueue in remove() callback to free its resources, +thus fixing memory leak. + +Fixes: 519a4bdcf822 ("V4L/DVB (11984): Add support for yet another SDMC DM1105 based DVB-S card.") +Cc: +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/pci/dm1105/dm1105.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/pci/dm1105/dm1105.c ++++ b/drivers/media/pci/dm1105/dm1105.c +@@ -1194,6 +1194,7 @@ static void dm1105_remove(struct pci_dev + + dm1105_hw_exit(dev); + free_irq(pdev->irq, dev); ++ destroy_workqueue(dev->wq); + pci_iounmap(pdev, dev->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); diff --git a/queue-7.1/media-pwc-drain-fill_buf-on-start_streaming-failure.patch b/queue-7.1/media-pwc-drain-fill_buf-on-start_streaming-failure.patch new file mode 100644 index 0000000000..32cd9a47b4 --- /dev/null +++ b/queue-7.1/media-pwc-drain-fill_buf-on-start_streaming-failure.patch @@ -0,0 +1,63 @@ +From 906e410dcffbbd99fb4081abab817a830033aa28 Mon Sep 17 00:00:00 2001 +From: Valery Borovsky +Date: Wed, 13 May 2026 08:42:44 +0300 +Subject: media: pwc: Drain fill_buf on start_streaming() failure + +From: Valery Borovsky + +commit 906e410dcffbbd99fb4081abab817a830033aa28 upstream. + +pwc_isoc_init() submits its isochronous URBs with +usb_submit_urb(.., GFP_KERNEL) in a loop. After the first URB is +submitted, its completion handler pwc_isoc_handler() can run on another +CPU before the loop finishes: + + start_streaming() + pwc_isoc_init() + usb_submit_urb(urbs[0], GFP_KERNEL) + pwc_isoc_handler(urbs[0]) + pdev->fill_buf = + pwc_get_next_fill_buf(pdev) + usb_submit_urb(urbs[i>0], ..) -> fails + pwc_isoc_cleanup(pdev) /* kills URBs */ + return ret; + pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED) + +pwc_get_next_fill_buf() detaches a buffer from pdev->queued_bufs and +stores it in pdev->fill_buf. The error path in start_streaming() only +drains pdev->queued_bufs, so the buffer parked in pdev->fill_buf is +leaked. vb2_start_streaming() then triggers +WARN_ON(owned_by_drv_count). + +stop_streaming() already handles this since commit 80b0963e1698 +("[media] pwc: fix WARN_ON"), which added the fill_buf drain in the +teardown path but not in the start_streaming() error path. Mirror that +handling on failure so start_streaming() returns with no buffer owned +by the driver. + +Issue identified by automated review of the INV-003 series at +https://sashiko.dev/ + +Fixes: 885fe18f5542 ("[media] pwc: Replace private buffer management code with videobuf2") +Cc: stable@vger.kernel.org +Signed-off-by: Valery Borovsky +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/usb/pwc/pwc-if.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/media/usb/pwc/pwc-if.c ++++ b/drivers/media/usb/pwc/pwc-if.c +@@ -726,6 +726,11 @@ static int start_streaming(struct vb2_qu + pwc_camera_power(pdev, 0); + /* And cleanup any queued bufs!! */ + pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); ++ if (pdev->fill_buf) { ++ vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf, ++ VB2_BUF_STATE_QUEUED); ++ pdev->fill_buf = NULL; ++ } + } + mutex_unlock(&pdev->v4l2_lock); + diff --git a/queue-7.1/media-pwc-return-queued-buffers-on-start_streaming-failure.patch b/queue-7.1/media-pwc-return-queued-buffers-on-start_streaming-failure.patch new file mode 100644 index 0000000000..0397f42efc --- /dev/null +++ b/queue-7.1/media-pwc-return-queued-buffers-on-start_streaming-failure.patch @@ -0,0 +1,54 @@ +From 975b2ee20e569d47821e4f6c9761b4664d48a6a4 Mon Sep 17 00:00:00 2001 +From: Valery Borovsky +Date: Mon, 11 May 2026 20:12:08 +0300 +Subject: media: pwc: Return queued buffers on start_streaming() failure + +From: Valery Borovsky + +commit 975b2ee20e569d47821e4f6c9761b4664d48a6a4 upstream. + +The vb2 framework hands buffers to the driver via buf_queue() before +calling start_streaming(). If start_streaming() returns an error +without first returning those buffers via vb2_buffer_done(), +vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued +buffers leak. + +pwc's start_streaming() had two early returns that hit this trap: +-ENODEV when the USB device was already disconnected, and -ERESTARTSYS +when mutex_lock_interruptible() was interrupted by a signal. Call the +existing pwc_cleanup_queued_bufs() helper with VB2_BUF_STATE_QUEUED +before returning (matching the state already used by the +pwc_isoc_init() error path in the same function). + +This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo: +Return queued buffers on start_streaming() failure"). + +Fixes: ceede9fa8939 ("[media] pwc: Fix locking") +Cc: stable@vger.kernel.org +Signed-off-by: Valery Borovsky +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/usb/pwc/pwc-if.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/media/usb/pwc/pwc-if.c ++++ b/drivers/media/usb/pwc/pwc-if.c +@@ -710,11 +710,15 @@ static int start_streaming(struct vb2_qu + struct pwc_device *pdev = vb2_get_drv_priv(vq); + int r; + +- if (!pdev->udev) ++ if (!pdev->udev) { ++ pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); + return -ENODEV; ++ } + +- if (mutex_lock_interruptible(&pdev->v4l2_lock)) ++ if (mutex_lock_interruptible(&pdev->v4l2_lock)) { ++ pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); + return -ERESTARTSYS; ++ } + /* Turn on camera and set LEDS on */ + pwc_camera_power(pdev, 1); + pwc_set_leds(pdev, leds[0], leds[1]); diff --git a/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-340.patch b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-340.patch new file mode 100644 index 0000000000..9c00690007 --- /dev/null +++ b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-340.patch @@ -0,0 +1,87 @@ +From cc1c35619c9895f918f9e388e3caa6ab2ff2fbe7 Mon Sep 17 00:00:00 2001 +From: Bryan O'Donoghue +Date: Tue, 7 Apr 2026 11:34:52 +0100 +Subject: media: qcom: camss: Fix RDI streaming for CSID 340 + +From: Bryan O'Donoghue + +commit cc1c35619c9895f918f9e388e3caa6ab2ff2fbe7 upstream. + +Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we +have replicated throughout CAMSS where we use the VC number to populate +both the VC fields and port fields of the CSID means that in practice only +VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works. + +Fix that for CSID 340 by separating VC and port. Fix to VC zero as a bugfix +we will look to properly populate the VC field with follow on patches +later. + +Fixes: f0fc808a466a ("media: qcom: camss: Add CSID 340 support") +Cc: stable@vger.kernel.org +Signed-off-by: Bryan O'Donoghue +Reviewed-by: Vladimir Zapolskiy +Reviewed-by: Loic Poulain +Signed-off-by: Bryan O'Donoghue +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/qcom/camss/camss-csid-340.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/media/platform/qcom/camss/camss-csid-340.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-340.c +@@ -74,9 +74,9 @@ static void __csid_ctrl_rdi(struct csid_ + writel_relaxed(!!enable, csid->base + CSID_RDI_CTRL(rdi)); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -88,14 +88,14 @@ static void __csid_configure_rdi_stream( + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- dt_id = vc & 0x03; ++ dt_id = port & 0x03; + + val = CSID_RDI_CFG0_DECODE_FORMAT_NOP; /* only for RDI path */ + val |= FIELD_PREP(CSID_RDI_CFG0_DT_MASK, format->data_type); +@@ -105,10 +105,11 @@ static void __csid_configure_rdi_stream( + if (enable) + val |= CSID_RDI_CFG0_ENABLE; + +- dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x vc=%u)\n", +- csid->id, enable ? "enable" : "disable", format->data_type, vc); ++ dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x port=%u vc=%u)\n", ++ csid->id, enable ? "enable" : "disable", format->data_type, ++ port, vc); + +- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) +@@ -117,9 +118,10 @@ static void csid_configure_stream(struct + + __csid_configure_rx(csid, &csid->phy); + ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + if (csid->phy.en_vc & BIT(i)) { +- __csid_configure_rdi_stream(csid, enable, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } diff --git a/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-680.patch b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-680.patch new file mode 100644 index 0000000000..fca37a506a --- /dev/null +++ b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-680.patch @@ -0,0 +1,143 @@ +From 93ea81d16570442dbca04d2e2563ae8c3e65fa1b Mon Sep 17 00:00:00 2001 +From: Bryan O'Donoghue +Date: Tue, 7 Apr 2026 11:34:51 +0100 +Subject: media: qcom: camss: Fix RDI streaming for CSID 680 + +From: Bryan O'Donoghue + +commit 93ea81d16570442dbca04d2e2563ae8c3e65fa1b upstream. + +Fix streaming to RDI1 and RDI2. csid->phy.en_vc contains a bitmask of +enabled CSID ports not virtual channels. + +We cycle through the number of available CSID ports and test this value +against the vc_en bitmask. + +We then use the passed value both as an index to the port configuration +macros and as a virtual channel index. + +This is a very broken pattern. Reviewing the initial introduction of VC +support it states that you can only map one CSID to one VFE. This is true +however each CSID has multiple sources which can sink inside of the VFE - +for example there is a "pixel" path for bayer stats which sources @ +CSID(x):3 and sinks on VFE(x):pix. + +That is CSID port # 3 should drive VFE port #3. With our current setup only +a sensor which drives virtual channel number #3 could possibly enable that +setup. + +This is deeply wrong the virtual channel has no relevance to hooking CSID +to VFE, a fact that is proven after this patch is applied allowing +RDI0,RDI1 and RDI2 to function with VC0 whereas before only RDI1 worked. + +Another way the current model breaks is the DT field. A sensor driving +different data-types on the same VC would not be able to separate the VC:DT +pair to separate RDI outputs, thus breaking another feature of VCs in the +MIPI data-stream. + +Default the VC back to zero. A follow on series will implement subdev +streams to actually enable VCs without breaking CSID source to VFE sink. + +Fixes: 253314b20408 ("media: qcom: camss: Add CSID 680 support") +Cc: stable@vger.kernel.org +Signed-off-by: Bryan O'Donoghue +Reviewed-by: Vladimir Zapolskiy +Reviewed-by: Loic Poulain +Signed-off-by: Bryan O'Donoghue +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/qcom/camss/camss-csid-680.c | 30 ++++++++++----------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +--- a/drivers/media/platform/qcom/camss/camss-csid-680.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-680.c +@@ -219,9 +219,9 @@ static void __csid_configure_top(struct + CSID_TOP_IO_PATH_CFG0(csid->id)); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -233,28 +233,28 @@ static void __csid_configure_rdi_stream( + lane_cnt = 4; + + val = 0; +- writel(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); ++ writel(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(port)); + + /* + * DT_ID is a two bit bitfield that is concatenated with + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- dt_id = vc & 0x03; ++ dt_id = port & 0x03; + + /* note: for non-RDI path, this should be format->decode_format */ + val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; + val |= format->data_type << RDI_CFG0_DATA_TYPE; + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; + val |= dt_id << RDI_CFG0_DT_ID; +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + + val = RDI_CFG1_TIMESTAMP_STB_FRAME; + val |= RDI_CFG1_BYTE_CNTR_EN; +@@ -265,23 +265,23 @@ static void __csid_configure_rdi_stream( + val |= RDI_CFG1_CROP_V_EN; + val |= RDI_CFG1_PACKING_MIPI; + +- writel(val, csid->base + CSID_RDI_CFG1(vc)); ++ writel(val, csid->base + CSID_RDI_CFG1(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(port)); + + val = 1; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_CTRL(vc)); ++ writel(val, csid->base + CSID_RDI_CTRL(port)); + +- val = readl(csid->base + CSID_RDI_CFG0(vc)); ++ val = readl(csid->base + CSID_RDI_CFG0(port)); + if (enable) + val |= RDI_CFG0_ENABLE; + else + val &= ~RDI_CFG0_ENABLE; +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) +@@ -290,11 +290,11 @@ static void csid_configure_stream(struct + + __csid_configure_top(csid); + +- /* Loop through all enabled VCs and configure stream for each */ ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + if (csid->phy.en_vc & BIT(i)) { +- __csid_configure_rdi_stream(csid, enable, i); +- __csid_configure_rx(csid, &csid->phy, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); ++ __csid_configure_rx(csid, &csid->phy, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } diff --git a/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-gen2.patch b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-gen2.patch new file mode 100644 index 0000000000..3f571e5229 --- /dev/null +++ b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-gen2.patch @@ -0,0 +1,149 @@ +From 618765634cefbdddafa84f07f82e9dd05b86cb9c Mon Sep 17 00:00:00 2001 +From: Bryan O'Donoghue +Date: Tue, 7 Apr 2026 11:34:53 +0100 +Subject: media: qcom: camss: Fix RDI streaming for CSID GEN2 + +From: Bryan O'Donoghue + +commit 618765634cefbdddafa84f07f82e9dd05b86cb9c upstream. + +Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we +have replicated throughout CAMSS where we use the VC number to populate +both the VC fields and port fields of the CSID means that in practice only +VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works. + +Fix that for CSID gen2 by separating VC and port. Fix to VC zero as a +bugfix we will look to properly populate the VC field with follow on +patches later. + +Fixes: 729fc005c8e2 ("media: qcom: camss: Split testgen, RDI and RX for CSID 170") +Cc: stable@vger.kernel.org +Signed-off-by: Bryan O'Donoghue +Reviewed-by: Vladimir Zapolskiy +Reviewed-by: Loic Poulain +Signed-off-by: Bryan O'Donoghue +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/qcom/camss/camss-csid-gen2.c | 47 ++++++++++---------- + 1 file changed, 24 insertions(+), 23 deletions(-) + +--- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c +@@ -203,10 +203,10 @@ static void __csid_ctrl_rdi(struct csid_ + writel_relaxed(val, csid->base + CSID_RDI_CTRL(rdi)); + } + +-static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { + struct csid_testgen_config *tg = &csid->testgen; +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -253,10 +253,10 @@ static void __csid_configure_testgen(str + writel_relaxed(val, csid->base + CSID_TPG_CTRL); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { + /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -267,14 +267,14 @@ static void __csid_configure_rdi_stream( + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- u8 dt_id = vc & 0x03; ++ u8 dt_id = port & 0x03; + + val = 1 << RDI_CFG0_BYTE_CNTR_EN; + val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN; +@@ -284,56 +284,57 @@ static void __csid_configure_rdi_stream( + val |= format->data_type << RDI_CFG0_DATA_TYPE; + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; + val |= dt_id << RDI_CFG0_DT_ID; +- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG0(port)); + + /* CSID_TIMESTAMP_STB_POST_IRQ */ + val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL; +- writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG1(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CTRL(port)); + +- val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc)); ++ val = readl_relaxed(csid->base + CSID_RDI_CFG0(port)); + val |= enable << RDI_CFG0_ENABLE; +- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) + { + struct csid_testgen_config *tg = &csid->testgen; + u8 i; +- /* Loop through all enabled VCs and configure stream for each */ ++ ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) + if (csid->phy.en_vc & BIT(i)) { + if (tg->enabled) +- __csid_configure_testgen(csid, enable, i); ++ __csid_configure_testgen(csid, enable, i, 0); + +- __csid_configure_rdi_stream(csid, enable, i); +- __csid_configure_rx(csid, &csid->phy, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); ++ __csid_configure_rx(csid, &csid->phy, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } diff --git a/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-gen3.patch b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-gen3.patch new file mode 100644 index 0000000000..885ff8e0ac --- /dev/null +++ b/queue-7.1/media-qcom-camss-fix-rdi-streaming-for-csid-gen3.patch @@ -0,0 +1,116 @@ +From ad136e52634d5a393a9dc93383f8ea1e898faf37 Mon Sep 17 00:00:00 2001 +From: Bryan O'Donoghue +Date: Tue, 7 Apr 2026 11:34:54 +0100 +Subject: media: qcom: camss: Fix RDI streaming for CSID GEN3 + +From: Bryan O'Donoghue + +commit ad136e52634d5a393a9dc93383f8ea1e898faf37 upstream. + +Fix streaming from CSIDn RDI1 and RDI2 to VFEn RDI1 and RDI2. A pattern we +have replicated throughout CAMSS where we use the VC number to populate +both the VC fields and port fields of the CSID means that in practice only +VC = 0 on CSIDn:RDI0 to VFEn:RDI0 works. + +Fix that for CSID gen3 by separating VC and port. Fix to VC zero as a +bugfix we will look to properly populate the VC field with follow on +patches later. + +Fixes: d96fe1808dcc ("media: qcom: camss: Add CSID 780 support") +Cc: stable@vger.kernel.org +Signed-off-by: Bryan O'Donoghue +Reviewed-by: Vladimir Zapolskiy +Reviewed-by: Loic Poulain +Signed-off-by: Bryan O'Donoghue +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/qcom/camss/camss-csid-gen3.c | 28 ++++++++++---------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c +@@ -145,12 +145,12 @@ static void __csid_configure_wrapper(str + writel(val, csid->camss->csid_wrapper_base + CSID_IO_PATH_CFG0(csid->id)); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { + u32 val; + u8 lane_cnt = csid->phy.lane_cnt; + /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -163,14 +163,14 @@ static void __csid_configure_rdi_stream( + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- u8 dt_id = vc & 0x03; ++ u8 dt_id = port & 0x03; + + val = RDI_CFG0_TIMESTAMP_EN; + val |= RDI_CFG0_TIMESTAMP_STB_SEL; +@@ -180,7 +180,7 @@ static void __csid_configure_rdi_stream( + val |= format->data_type << RDI_CFG0_DT; + val |= dt_id << RDI_CFG0_DT_ID; + +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + + val = RDI_CFG1_PACKING_FORMAT_MIPI; + val |= RDI_CFG1_PIX_STORE; +@@ -189,22 +189,22 @@ static void __csid_configure_rdi_stream( + val |= RDI_CFG1_CROP_H_EN; + val |= RDI_CFG1_CROP_V_EN; + +- writel(val, csid->base + CSID_RDI_CFG1(vc)); ++ writel(val, csid->base + CSID_RDI_CFG1(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(port)); + + val = 1; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_CTRL(vc)); ++ writel(val, csid->base + CSID_RDI_CTRL(port)); + +- val = readl(csid->base + CSID_RDI_CFG0(vc)); ++ val = readl(csid->base + CSID_RDI_CFG0(port)); + + if (enable) + val |= RDI_CFG0_EN; +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) +@@ -213,11 +213,11 @@ static void csid_configure_stream(struct + + __csid_configure_wrapper(csid); + +- /* Loop through all enabled VCs and configure stream for each */ ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) + if (csid->phy.en_vc & BIT(i)) { +- __csid_configure_rdi_stream(csid, enable, i); +- __csid_configure_rx(csid, &csid->phy, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); ++ __csid_configure_rx(csid, &csid->phy, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } diff --git a/queue-7.1/media-radio-si476x-unregister-v4l2_device-on-probe-failure.patch b/queue-7.1/media-radio-si476x-unregister-v4l2_device-on-probe-failure.patch new file mode 100644 index 0000000000..41a77c18de --- /dev/null +++ b/queue-7.1/media-radio-si476x-unregister-v4l2_device-on-probe-failure.patch @@ -0,0 +1,42 @@ +From 436a693af04ffb889aaf87cb69ec1f2b21d3569c Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Wed, 13 May 2026 16:02:37 +0900 +Subject: media: radio-si476x: Unregister v4l2_device on probe failure + +From: Myeonghun Pak + +commit 436a693af04ffb889aaf87cb69ec1f2b21d3569c upstream. + +si476x_radio_probe() registers radio->v4l2dev before allocating the V4L2 +controls and before registering the video device. If any of those later +steps fails, probe returns through the exit label after freeing only the +control handler. + +A failed probe does not call si476x_radio_remove(), so the +v4l2_device_unregister() there is not reached. This leaves the parent +device reference taken by v4l2_device_register() behind on the error path. + +Unregister the V4L2 device in the probe error path after freeing the +controls. + +Fixes: b879a9c2a755 ("[media] v4l2: Add a V4L2 driver for SI476X MFD") +Cc: stable@vger.kernel.org +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/radio/radio-si476x.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/radio/radio-si476x.c ++++ b/drivers/media/radio/radio-si476x.c +@@ -1493,6 +1493,7 @@ static int si476x_radio_probe(struct pla + return 0; + exit: + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); ++ v4l2_device_unregister(&radio->v4l2dev); + return rval; + } + diff --git a/queue-7.1/media-rtl2832-fix-use-after-free-in-rtl2832_remove.patch b/queue-7.1/media-rtl2832-fix-use-after-free-in-rtl2832_remove.patch new file mode 100644 index 0000000000..701716c6ef --- /dev/null +++ b/queue-7.1/media-rtl2832-fix-use-after-free-in-rtl2832_remove.patch @@ -0,0 +1,54 @@ +From 680daf40a82d483949f87f0d8f98639dc47e610c Mon Sep 17 00:00:00 2001 +From: Deepanshu Kartikey +Date: Wed, 22 Apr 2026 20:17:34 +0530 +Subject: media: rtl2832: fix use-after-free in rtl2832_remove() + +From: Deepanshu Kartikey + +commit 680daf40a82d483949f87f0d8f98639dc47e610c upstream. + +cancel_delayed_work_sync() is called before i2c_mux_del_adapters() +in rtl2832_remove(). While the cancel waits for any running instance +of i2c_gate_work to finish, it does not prevent the timer from being +rescheduled by a concurrent thread. + +During probe, the r820t_attach() call attempts I2C transfers through +the mux adapter. These transfers go through i2c_mux_master_xfer(), +which calls rtl2832_deselect() after the transfer completes, +rescheduling i2c_gate_work via schedule_delayed_work(). If this +transfer is still in flight when rtl2832_remove() runs, +rtl2832_deselect() can reschedule i2c_gate_work after it has been +cancelled, causing a use-after-free when kfree(dev) is called. + +Fix this by calling i2c_mux_del_adapters() before +cancel_delayed_work_sync(). Once the mux adapter is unregistered, no +new I2C transfers can go through it, so rtl2832_deselect() can no +longer reschedule i2c_gate_work. The subsequent +cancel_delayed_work_sync() is then guaranteed to be final. + +Fixes: cddcc40b1b15 ("[media] rtl2832: convert to use an explicit i2c mux core") +Cc: stable@vger.kernel.org +Reported-by: syzbot+019ced393ab913002b75@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=019ced393ab913002b75 +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/dvb-frontends/rtl2832.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/dvb-frontends/rtl2832.c ++++ b/drivers/media/dvb-frontends/rtl2832.c +@@ -1115,10 +1115,10 @@ static void rtl2832_remove(struct i2c_cl + + dev_dbg(&client->dev, "\n"); + +- cancel_delayed_work_sync(&dev->i2c_gate_work); +- + i2c_mux_del_adapters(dev->muxc); + ++ cancel_delayed_work_sync(&dev->i2c_gate_work); ++ + regmap_exit(dev->regmap); + + kfree(dev); diff --git a/queue-7.1/media-rtl2832_sdr-return-queued-buffers-on-start_streaming-failure.patch b/queue-7.1/media-rtl2832_sdr-return-queued-buffers-on-start_streaming-failure.patch new file mode 100644 index 0000000000..a9ec8b1e4a --- /dev/null +++ b/queue-7.1/media-rtl2832_sdr-return-queued-buffers-on-start_streaming-failure.patch @@ -0,0 +1,111 @@ +From 33ca0aab6f4bd90921fc1395478f38f72c4d19af Mon Sep 17 00:00:00 2001 +From: Valery Borovsky +Date: Mon, 11 May 2026 20:12:09 +0300 +Subject: media: rtl2832_sdr: Return queued buffers on start_streaming() failure + +From: Valery Borovsky + +commit 33ca0aab6f4bd90921fc1395478f38f72c4d19af upstream. + +The vb2 framework hands buffers to the driver via buf_queue() before +calling start_streaming(). If start_streaming() returns an error +without first returning those buffers via vb2_buffer_done(), +vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued +buffers leak. + +rtl2832_sdr_start_streaming() had multiple error paths that hit this +trap: two direct early returns (-ENODEV, -ERESTARTSYS), plus six +`goto err` paths covering subdev s_power, tuner setup, ADC setup, +stream-buffer allocation, urb allocation, and urb submission failures. +None of them returned the queued buffers. + +The original function had no distinct success exit and fell straight +through into the err label, which previously only did mutex_unlock and +"return ret". Adding queued-buffer cleanup at err must therefore be +paired with an explicit success return; otherwise every successful +start would also drain the buffer queue and kill streaming. Add that +success return, then add rtl2832_sdr_cleanup_queued_bufs() at the err +label and before each early return. + +The cleanup helper takes a vb2_buffer_state argument so that the +start_streaming error paths can pass VB2_BUF_STATE_QUEUED (as +expected by userspace on start_streaming failure) while stop_streaming +keeps its existing VB2_BUF_STATE_ERROR semantics. + +This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo: +Return queued buffers on start_streaming() failure"). + +The err label still does not roll back power_ctrl(), frontend_ctrl(), +the POWER_ON flag, or stream/URB allocations that may have happened +before the failing step. Those are pre-existing leaks of a different +class and are not addressed here. + +Fixes: 771138920eaf ("[media] rtl2832_sdr: Realtek RTL2832 SDR driver module") +Cc: stable@vger.kernel.org +Signed-off-by: Valery Borovsky +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/dvb-frontends/rtl2832_sdr.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +--- a/drivers/media/dvb-frontends/rtl2832_sdr.c ++++ b/drivers/media/dvb-frontends/rtl2832_sdr.c +@@ -399,7 +399,8 @@ static int rtl2832_sdr_alloc_urbs(struct + } + + /* Must be called with vb_queue_lock hold */ +-static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev) ++static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev, ++ enum vb2_buffer_state state) + { + struct platform_device *pdev = dev->pdev; + unsigned long flags; +@@ -413,7 +414,7 @@ static void rtl2832_sdr_cleanup_queued_b + buf = list_entry(dev->queued_bufs.next, + struct rtl2832_sdr_frame_buf, list); + list_del(&buf->list); +- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); + } +@@ -855,11 +856,15 @@ static int rtl2832_sdr_start_streaming(s + + dev_dbg(&pdev->dev, "\n"); + +- if (!dev->udev) ++ if (!dev->udev) { ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + return -ENODEV; ++ } + +- if (mutex_lock_interruptible(&dev->v4l2_lock)) ++ if (mutex_lock_interruptible(&dev->v4l2_lock)) { ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + return -ERESTARTSYS; ++ } + + if (d->props->power_ctrl) + d->props->power_ctrl(d, 1); +@@ -900,7 +905,11 @@ static int rtl2832_sdr_start_streaming(s + if (ret) + goto err; + ++ mutex_unlock(&dev->v4l2_lock); ++ return 0; ++ + err: ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + mutex_unlock(&dev->v4l2_lock); + + return ret; +@@ -920,7 +929,7 @@ static void rtl2832_sdr_stop_streaming(s + rtl2832_sdr_kill_urbs(dev); + rtl2832_sdr_free_urbs(dev); + rtl2832_sdr_free_stream_bufs(dev); +- rtl2832_sdr_cleanup_queued_bufs(dev); ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_ERROR); + rtl2832_sdr_unset_adc(dev); + + /* sleep tuner */ diff --git a/queue-7.1/media-rzg2l-cru-skip-icnmc-configuration-when-icnsvc-is-used.patch b/queue-7.1/media-rzg2l-cru-skip-icnmc-configuration-when-icnsvc-is-used.patch new file mode 100644 index 0000000000..b498910ca3 --- /dev/null +++ b/queue-7.1/media-rzg2l-cru-skip-icnmc-configuration-when-icnsvc-is-used.patch @@ -0,0 +1,74 @@ +From cd4ce68875f406b0cf3f5a94c0fd22989689222f Mon Sep 17 00:00:00 2001 +From: Tommaso Merciai +Date: Tue, 30 Dec 2025 18:09:15 +0100 +Subject: media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used + +From: Tommaso Merciai + +commit cd4ce68875f406b0cf3f5a94c0fd22989689222f upstream. + +When the CRU is configured to use ICnSVC for virtual channel mapping, +as on the RZ/{G3E, V2H/P} SoC, the ICnMC register must not be +programmed. + +Return early after setting up ICnSVC to avoid overriding the ICnMC +register, which is not applicable in this mode. + +This prevents unintended register programming when ICnSVC is enabled. + +Cc: stable@vger.kernel.org +Fixes: 3c5ca0a48bb0 ("media: rzg2l-cru: Drop function pointer to configure CSI") +Signed-off-by: Tommaso Merciai +[Rework to not break image format programming] +Signed-off-by: Jacopo Mondi +Reviewed-by: Lad Prabhakar +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 1 + drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 17 +++++++++----- + 2 files changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h ++++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h +@@ -60,6 +60,7 @@ + #define ICnMC_CSCTHR BIT(5) + #define ICnMC_INF(x) ((x) << 16) + #define ICnMC_VCSEL(x) ((x) << 22) ++#define ICnMC_VCSEL_MASK GENMASK(23, 22) + #define ICnMC_INF_MASK GENMASK(21, 16) + + #define ICnMS_IA BIT(2) +--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c ++++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +@@ -262,19 +262,24 @@ static void rzg2l_cru_csi2_setup(struct + u8 csi_vc) + { + const struct rzg2l_cru_info *info = cru->info; +- u32 icnmc = ICnMC_INF(ip_fmt->datatype); ++ u32 icnmc = rzg2l_cru_read(cru, info->image_conv) & ~(ICnMC_INF_MASK | ++ ICnMC_VCSEL_MASK); ++ icnmc |= ICnMC_INF(ip_fmt->datatype); + ++ /* ++ * VC filtering goes through SVC register on G3E/V2H. ++ * ++ * FIXME: virtual channel filtering is likely broken and only VC=0 ++ * works. ++ */ + if (cru->info->regs[ICnSVC]) { + rzg2l_cru_write(cru, ICnSVCNUM, csi_vc); + rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) | + ICnSVC_SVC2(2) | ICnSVC_SVC3(3)); ++ } else { ++ icnmc |= ICnMC_VCSEL(csi_vc); + } + +- icnmc |= rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK; +- +- /* Set virtual channel CSI2 */ +- icnmc |= ICnMC_VCSEL(csi_vc); +- + rzg2l_cru_write(cru, info->image_conv, icnmc); + } + diff --git a/queue-7.1/media-rzv2h-ivc-wait-for-frame-end-in-stop_streaming.patch b/queue-7.1/media-rzv2h-ivc-wait-for-frame-end-in-stop_streaming.patch new file mode 100644 index 0000000000..b8ac969f37 --- /dev/null +++ b/queue-7.1/media-rzv2h-ivc-wait-for-frame-end-in-stop_streaming.patch @@ -0,0 +1,99 @@ +From b4e6ddce16b8ae0ddbec7c96c675779260ad4697 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Sat, 28 Mar 2026 17:34:51 +0100 +Subject: media: rzv2h-ivc: Wait for frame end in stop_streaming + +From: Jacopo Mondi + +commit b4e6ddce16b8ae0ddbec7c96c675779260ad4697 upstream. + +The rzv2h-ivc driver fails to handle back-2-back streaming sessions that +do not go through a peripheral reset. As the driver uses an autosuspend +delay of 2 seconds, it is quite possible that two consecutive streaming +sessions won't go through a suspend/resume sequence. + +If the peripheral is not reset the second streaming session hangs and no +frames are delivered to the ISP. + +This is because the stop_streaming() procedure implemented in the driver +doesn't match what's prescribed by the chip datasheet: + +1) The chip manual suggests to poll the RZV2H_IVC_FM_INT_STAT_STPEND bit + of RZV2H_IVC_REG_FM_INT_STA instead of polling on RZV2H_IVC_REG_FM_STOP + and prescribes to clear the bit after polling has completed + +2) More importantly: the RZV2H_IVC_REG_FM_STOP_FSTOP bit has to be set + on RZV2H_IVC_REG_FM_STOP -only- if a frame transfer to the ISP is in + progress. Setting the RZV2H_IVC_REG_FM_STOP_FSTOP bit when no frame is + being transferred causes the polling routine to timeout and the next + streaming session fails to start + +As a frame transfer of an image in 1920x1080@10bi takes 5 milliseconds +at most, it is quite possible that the frame transfer completion interrupt +races with the stop procedure. + +Instead of forcing a frame transfer abort, simply wait for the +in-progress transfer to complete by polling the ivc->vvalid_ifp status +variable in an hand-rolled loop that allows to inspect the variable +while holding the spinlock, to allow the irq handler to complete the +current buffer. + +With this change, streaming back-2-back without suspending the +peripheral works successfully. + +Cc: stable@vger.kernel.org +Fixes: f0b3984d821b ("media: platform: Add Renesas Input Video Control block driver") +Signed-off-by: Jacopo Mondi +Reviewed-by: Daniel Scally +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + .../renesas/rzv2h-ivc/rzv2h-ivc-video.c | 31 ++++++++++++++++--- + 1 file changed, 26 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c +index b167f1bab7ef..932fed38cf3f 100644 +--- a/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c ++++ b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c +@@ -297,12 +297,33 @@ static int rzv2h_ivc_start_streaming(struct vb2_queue *q, unsigned int count) + static void rzv2h_ivc_stop_streaming(struct vb2_queue *q) + { + struct rzv2h_ivc *ivc = vb2_get_drv_priv(q); +- u32 val = 0; ++ unsigned int loop = 5; + +- rzv2h_ivc_write(ivc, RZV2H_IVC_REG_FM_STOP, RZV2H_IVC_REG_FM_STOP_FSTOP); +- readl_poll_timeout(ivc->base + RZV2H_IVC_REG_FM_STOP, +- val, !(val & RZV2H_IVC_REG_FM_STOP_FSTOP), +- 10 * USEC_PER_MSEC, 250 * USEC_PER_MSEC); ++ /* ++ * If no frame transfer is in progress, we're done, otherwise, wait for ++ * the transfer to complete. ++ * ++ * Transferring a 1920x1080@10bit frame to the ISP takes less than 5 ++ * msec so sleep for 2.5 msec (+- 25%) and give up after 5 attempts. ++ */ ++ for (; loop > 0; loop--) { ++ unsigned int vvalid_ifp; ++ ++ /* ++ * Inspect the ivc->vvalid_ifp variable holding the spinlock not ++ * to the race with the rzv2h_ivc_buffer_done() call in the irq ++ * handler. ++ */ ++ scoped_guard(spinlock_irq, &ivc->spinlock) { ++ vvalid_ifp = ivc->vvalid_ifp; ++ } ++ if (vvalid_ifp < 2) ++ break; ++ ++ fsleep(2500); ++ } ++ if (!loop) ++ dev_err(ivc->dev, "Failed to stop streaming\n"); + + rzv2h_ivc_return_buffers(ivc, VB2_BUF_STATE_ERROR); + video_device_pipeline_stop(&ivc->vdev.dev); +-- +2.55.0 + diff --git a/queue-7.1/media-saa7134-fix-a-possible-memory-leak-in-saa7134_video_init1.patch b/queue-7.1/media-saa7134-fix-a-possible-memory-leak-in-saa7134_video_init1.patch new file mode 100644 index 0000000000..a9b446c734 --- /dev/null +++ b/queue-7.1/media-saa7134-fix-a-possible-memory-leak-in-saa7134_video_init1.patch @@ -0,0 +1,79 @@ +From f86ed548386e3050e5f8f25b450d09dc009d9a88 Mon Sep 17 00:00:00 2001 +From: Ma Ke +Date: Thu, 2 Apr 2026 15:35:29 +0800 +Subject: media: saa7134: Fix a possible memory leak in saa7134_video_init1 + +From: Ma Ke + +commit f86ed548386e3050e5f8f25b450d09dc009d9a88 upstream. + +In saa7134_video_init1(), the return value of the first +saa7134_pgtable_alloc() is not checked. If it fails, the function +continues as if successful, leaving the driver with an invalid page +table. Additionally, if vb2_queue_init() for the VBI queue fails after +the video queue page table has been allocated, the allocated memory is +not freed before returning. The second saa7134_pgtable_alloc() also +lacks a return value check. Errors occur during device probing before +the device is fully registered, the normal cleanup path in +saa7134_finidev() is not executed, leading to memory leaks and +potential use of uninitialized DMA resources. + +Check the return value of both saa7134_pgtable_alloc() calls and +propagate errors. On failure of any later step, free allocated page +tables to avoid memory leaks. Ensure control handlers are also +released on error to prevent further resource leakage. + +Found by code review. + +Signed-off-by: Ma Ke +Cc: stable@vger.kernel.org +Fixes: a00e68888d5d ("[media] saa7134: move saa7134_pgtable to saa7134_dmaqueue") +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/pci/saa7134/saa7134-video.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +--- a/drivers/media/pci/saa7134/saa7134-video.c ++++ b/drivers/media/pci/saa7134/saa7134-video.c +@@ -1714,8 +1714,10 @@ int saa7134_video_init1(struct saa7134_d + q->dev = &dev->pci->dev; + ret = vb2_queue_init(q); + if (ret) +- return ret; +- saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt); ++ goto err_free_ctrl; ++ ret = saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt); ++ if (ret) ++ goto err_free_ctrl; + + q = &dev->vbi_vbq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; +@@ -1732,11 +1734,24 @@ int saa7134_video_init1(struct saa7134_d + q->lock = &dev->lock; + q->dev = &dev->pci->dev; + ret = vb2_queue_init(q); +- if (ret) +- return ret; +- saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt); ++ if (ret) { ++ saa7134_pgtable_free(dev->pci, &dev->video_q.pt); ++ goto err_free_ctrl; ++ } ++ ++ ret = saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt); ++ if (ret) { ++ saa7134_pgtable_free(dev->pci, &dev->video_q.pt); ++ goto err_free_ctrl; ++ } + + return 0; ++ ++err_free_ctrl: ++ v4l2_ctrl_handler_free(&dev->ctrl_handler); ++ if (card_has_radio(dev)) ++ v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); ++ return ret; + } + + void saa7134_video_fini(struct saa7134_dev *dev) diff --git a/queue-7.1/media-stm32-dcmi-unregister-notifier-on-probe-failure.patch b/queue-7.1/media-stm32-dcmi-unregister-notifier-on-probe-failure.patch new file mode 100644 index 0000000000..ffe3bbbaa4 --- /dev/null +++ b/queue-7.1/media-stm32-dcmi-unregister-notifier-on-probe-failure.patch @@ -0,0 +1,38 @@ +From 084973ebd67b28f0945c5d45408f86c58b540110 Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Sun, 26 Apr 2026 21:43:49 +0900 +Subject: media: stm32: dcmi: unregister notifier on probe failure + +From: Myeonghun Pak + +commit 084973ebd67b28f0945c5d45408f86c58b540110 upstream. + +dcmi_graph_init() registers the async notifier before dcmi_probe() toggles +the reset line. If reset_control_assert() or reset_control_deassert() +fails afterwards, probe returns through err_cleanup and the driver core +will not call dcmi_remove(). + +Unregister the notifier before cleaning it up on that error path, +matching the successful remove path and the V4L2 async notifier lifetime +rules. + +Signed-off-by: Myeonghun Pak +Signed-off-by: Hans Verkuil +Fixes: d079f94c9046 ("media: platform: Switch to v4l2_async_notifier_add_subdev") +Cc: stable@vger.kernel.org +[hverkuil: added Fixes tag] +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/st/stm32/stm32-dcmi.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -2195,6 +2195,7 @@ static int dcmi_probe(struct platform_de + return 0; + + err_cleanup: ++ v4l2_async_nf_unregister(&dcmi->notifier); + v4l2_async_nf_cleanup(&dcmi->notifier); + err_media_entity_cleanup: + media_entity_cleanup(&dcmi->vdev->entity); diff --git a/queue-7.1/media-stm32-dcmipp-return-queued-buffers-on-start_streaming-failure.patch b/queue-7.1/media-stm32-dcmipp-return-queued-buffers-on-start_streaming-failure.patch new file mode 100644 index 0000000000..ae55b9cf2d --- /dev/null +++ b/queue-7.1/media-stm32-dcmipp-return-queued-buffers-on-start_streaming-failure.patch @@ -0,0 +1,51 @@ +From ffc8eec06378a340d708c889184ab3e14b57d540 Mon Sep 17 00:00:00 2001 +From: Valery Borovsky +Date: Mon, 11 May 2026 20:12:10 +0300 +Subject: media: stm32-dcmipp: Return queued buffers on start_streaming() failure + +From: Valery Borovsky + +commit ffc8eec06378a340d708c889184ab3e14b57d540 upstream. + +The vb2 framework hands buffers to the driver via buf_queue() before +calling start_streaming(). If start_streaming() returns an error +without first returning those buffers via vb2_buffer_done(), +vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued +buffers leak. + +dcmipp_bytecap_start_streaming() returned -EINVAL when the source +subdevice could not be resolved from the media graph, before +pm_runtime_resume_and_get() and media_pipeline_start() had been called. +The remaining error paths already converge on the err_buffer_done +label, which calls dcmipp_bytecap_all_buffers_done(..., +VB2_BUF_STATE_QUEUED). Jump to that label directly: the intermediate +err_pm_put / err_media_pipeline_stop labels are skipped, which is +correct because nothing they would undo has happened yet. + +This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo: +Return queued buffers on start_streaming() failure"). + +Fixes: 28e0f3772296 ("media: stm32-dcmipp: STM32 DCMIPP camera interface driver") +Cc: stable@vger.kernel.org +Signed-off-by: Valery Borovsky +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c +@@ -401,8 +401,10 @@ static int dcmipp_bytecap_start_streamin + */ + if (!vcap->s_subdev) { + pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]); +- if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) +- return -EINVAL; ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) { ++ ret = -EINVAL; ++ goto err_buffer_done; ++ } + vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity); + vcap->s_subdev_pad_nb = pad->index; + } diff --git a/queue-7.1/media-sun4i-csi-return-queued-buffers-on-start_streaming-failure.patch b/queue-7.1/media-sun4i-csi-return-queued-buffers-on-start_streaming-failure.patch new file mode 100644 index 0000000000..efd73ddae9 --- /dev/null +++ b/queue-7.1/media-sun4i-csi-return-queued-buffers-on-start_streaming-failure.patch @@ -0,0 +1,51 @@ +From bbba3e260a62810a717b4442a3bb96d0ec0f6309 Mon Sep 17 00:00:00 2001 +From: Valery Borovsky +Date: Mon, 11 May 2026 20:12:11 +0300 +Subject: media: sun4i-csi: Return queued buffers on start_streaming() failure + +From: Valery Borovsky + +commit bbba3e260a62810a717b4442a3bb96d0ec0f6309 upstream. + +The vb2 framework hands buffers to the driver via buf_queue() before +calling start_streaming(). If start_streaming() returns an error +without first returning those buffers via vb2_buffer_done(), +vb2_start_streaming() fires WARN_ON(owned_by_drv_count) and the queued +buffers leak. + +sun4i_csi_start_streaming() returned -EINVAL when no matching CSI +format could be found, before any setup (scratch buffer allocation, +pipeline start) had been performed. The remaining error paths already +converge on the err_clear_dma_queue label, which calls +return_all_buffers(..., VB2_BUF_STATE_QUEUED) under csi->qlock. Jump +to that label directly: the intermediate err_disable_device / +err_disable_pipeline / err_free_scratch_buffer labels are skipped, +which is correct because nothing they would undo has happened yet. + +This mirrors the uvcvideo fix in commit 4cf3b6fd54eb ("media: uvcvideo: +Return queued buffers on start_streaming() failure"). + +Fixes: 577bbf23b758 ("media: sunxi: Add A10 CSI driver") +Cc: stable@vger.kernel.org +Signed-off-by: Valery Borovsky +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c ++++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +@@ -234,8 +234,10 @@ static int sun4i_csi_start_streaming(str + int ret; + + csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL); +- if (!csi_fmt) +- return -EINVAL; ++ if (!csi_fmt) { ++ ret = -EINVAL; ++ goto err_clear_dma_queue; ++ } + + dev_dbg(csi->dev, "Starting capture\n"); + diff --git a/queue-7.1/media-synopsys-hdmirx-fix-hpd-lane-hold-time.patch b/queue-7.1/media-synopsys-hdmirx-fix-hpd-lane-hold-time.patch new file mode 100644 index 0000000000..aa3bf0f3d0 --- /dev/null +++ b/queue-7.1/media-synopsys-hdmirx-fix-hpd-lane-hold-time.patch @@ -0,0 +1,37 @@ +From d1162a5adbb5e95953d460b5bde3a04cd4473fe9 Mon Sep 17 00:00:00 2001 +From: Dmitry Osipenko +Date: Wed, 25 Mar 2026 13:57:42 +0300 +Subject: media: synopsys: hdmirx: Fix HPD lane hold time + +From: Dmitry Osipenko + +commit d1162a5adbb5e95953d460b5bde3a04cd4473fe9 upstream. + +Increase time of holding HPD lane low by 50ms. This fixes EDID change not +detected by source/display side. + +Fixes: 7b59b132ad43 ("media: platform: synopsys: Add support for HDMI input driver") +Cc: stable@vger.kernel.org +Reported-by: Ross Cawston +Closes: https://lore.kernel.org/linux-rockchip/20260209061654.54757-1-ross@r-sc.ca/ +Signed-off-by: Dmitry Osipenko +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c ++++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +@@ -506,9 +506,9 @@ static void hdmirx_hpd_ctrl(struct snps_ + hdmirx_writel(hdmirx_dev, CORE_CONFIG, + hdmirx_dev->hpd_trigger_level_high ? en : !en); + +- /* 100ms delay as per HDMI spec */ ++ /* 100ms delay as per HDMI spec + extra 50ms to cover internal delay */ + if (!en) +- msleep(100); ++ msleep(100 + 50); + } + + static void hdmirx_write_edid_data(struct snps_hdmirx_dev *hdmirx_dev, diff --git a/queue-7.1/media-tegra-video-vi-fix-invalid-u32-return-value-in-format-lookup.patch b/queue-7.1/media-tegra-video-vi-fix-invalid-u32-return-value-in-format-lookup.patch new file mode 100644 index 0000000000..78cfedabe3 --- /dev/null +++ b/queue-7.1/media-tegra-video-vi-fix-invalid-u32-return-value-in-format-lookup.patch @@ -0,0 +1,41 @@ +From d5b50055338e131a1a99f923ebb0361974a00f36 Mon Sep 17 00:00:00 2001 +From: Hungyu Lin +Date: Thu, 7 May 2026 02:22:13 +0000 +Subject: media: tegra-video: vi: fix invalid u32 return value in format lookup + +From: Hungyu Lin + +commit d5b50055338e131a1a99f923ebb0361974a00f36 upstream. + +tegra_get_format_fourcc_by_idx() returns a u32 but uses -EINVAL to +signal an out-of-bounds index. This results in a large unsigned +value being returned, which may be interpreted as a valid fourcc. + +Returning 0 is not a valid fourcc either. This condition should +never happen, so use WARN_ON_ONCE() to catch unexpected out-of-bounds +access and return a valid fallback format instead. + +Suggested-by: Hans Verkuil +Fixes: 3d8a97eabef0 ("media: tegra-video: Add Tegra210 Video input driver") +Cc: stable@vger.kernel.org +Reviewed-by: Luca Ceresoli +Signed-off-by: Hungyu Lin +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/media/tegra-video/vi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/media/tegra-video/vi.c ++++ b/drivers/staging/media/tegra-video/vi.c +@@ -80,8 +80,8 @@ static int tegra_get_format_idx_by_code( + static u32 tegra_get_format_fourcc_by_idx(struct tegra_vi *vi, + unsigned int index) + { +- if (index >= vi->soc->nformats) +- return -EINVAL; ++ if (WARN_ON_ONCE(index >= vi->soc->nformats)) ++ return vi->soc->video_formats[0].fourcc; + + return vi->soc->video_formats[index].fourcc; + } diff --git a/queue-7.1/media-ti-vpe-fix-fwnode_handle-leak-in-vip_probe_complete.patch b/queue-7.1/media-ti-vpe-fix-fwnode_handle-leak-in-vip_probe_complete.patch new file mode 100644 index 0000000000..bf244e7081 --- /dev/null +++ b/queue-7.1/media-ti-vpe-fix-fwnode_handle-leak-in-vip_probe_complete.patch @@ -0,0 +1,69 @@ +From 34ca1065a4b2cf776c28d7cece6f6c9d90f7e3a3 Mon Sep 17 00:00:00 2001 +From: Felix Gu +Date: Wed, 18 Mar 2026 01:21:53 +0800 +Subject: media: ti: vpe: Fix fwnode_handle leak in vip_probe_complete() + +From: Felix Gu + +commit 34ca1065a4b2cf776c28d7cece6f6c9d90f7e3a3 upstream. + +In vip_probe_complete(), the fwnode_handle reference is not released +if the loop continues via the default switch case or if alloc_port() +fails. This results in a reference count leak. + +Switch to using the __free(fwnode_handle) cleanup attribute to ensure +the reference is automatically released when the handle goes out of +scope. + +Fixes: fc2873aa4a21 ("media: ti: vpe: Add the VIP driver") +Cc: stable@vger.kernel.org +Signed-off-by: Felix Gu +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/ti/vpe/vip.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/ti/vpe/vip.c b/drivers/media/platform/ti/vpe/vip.c +index 0e91e87bda9b..a3c5e966f64c 100644 +--- a/drivers/media/platform/ti/vpe/vip.c ++++ b/drivers/media/platform/ti/vpe/vip.c +@@ -9,6 +9,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -3389,7 +3390,6 @@ static int vip_probe_complete(struct platform_device *pdev) + struct vip_port *port; + struct vip_dev *dev; + struct device_node *parent = pdev->dev.of_node; +- struct fwnode_handle *ep = NULL; + unsigned int syscon_args[5]; + int ret, i, slice_id, port_id, p; + +@@ -3411,8 +3411,9 @@ static int vip_probe_complete(struct platform_device *pdev) + ctrl->syscon_bit_field[i] = syscon_args[i + 1]; + + for (p = 0; p < (VIP_NUM_PORTS * VIP_NUM_SLICES); p++) { +- ep = fwnode_graph_get_next_endpoint_by_regs(of_fwnode_handle(parent), +- p, 0); ++ struct fwnode_handle *ep __free(fwnode_handle) = ++ fwnode_graph_get_next_endpoint_by_regs( ++ of_fwnode_handle(parent), p, 0); + if (!ep) + continue; + +@@ -3447,7 +3448,6 @@ static int vip_probe_complete(struct platform_device *pdev) + port = dev->ports[port_id]; + + vip_register_subdev_notify(port, ep); +- fwnode_handle_put(ep); + } + return 0; + } +-- +2.55.0 + diff --git a/queue-7.1/media-ti-vpe-fix-the-error-code-of-devm_kzalloc-in-vip_probe_slice.patch b/queue-7.1/media-ti-vpe-fix-the-error-code-of-devm_kzalloc-in-vip_probe_slice.patch new file mode 100644 index 0000000000..ca606bea10 --- /dev/null +++ b/queue-7.1/media-ti-vpe-fix-the-error-code-of-devm_kzalloc-in-vip_probe_slice.patch @@ -0,0 +1,57 @@ +From e8f319eae96a3d718e810d52432020a2b77f5f60 Mon Sep 17 00:00:00 2001 +From: Felix Gu +Date: Wed, 18 Mar 2026 01:21:55 +0800 +Subject: media: ti: vpe: Fix the error code of devm_kzalloc() in vip_probe_slice() + +From: Felix Gu + +commit e8f319eae96a3d718e810d52432020a2b77f5f60 upstream. + +In vip_probe_slice(), the error check for devm_kzalloc() incorrectly +uses PTR_ERR_OR_ZERO() which returns 0 for NULL pointer. + +Return -ENOMEM for devm_kzalloc() failure. + +Fixes: fc2873aa4a21 ("media: ti: vpe: Add the VIP driver") +Cc: stable@vger.kernel.org +Signed-off-by: Felix Gu +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/ti/vpe/vip.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/platform/ti/vpe/vip.c b/drivers/media/platform/ti/vpe/vip.c +index bd34c982b427..cb0a5a07a3d4 100644 +--- a/drivers/media/platform/ti/vpe/vip.c ++++ b/drivers/media/platform/ti/vpe/vip.c +@@ -3490,7 +3490,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) + + parser = devm_kzalloc(&pdev->dev, sizeof(*dev->parser), GFP_KERNEL); + if (!parser) +- return PTR_ERR_OR_ZERO(parser); ++ return -ENOMEM; + + parser->base = dev->base + (slice ? VIP_SLICE1_PARSER : VIP_SLICE0_PARSER); + if (IS_ERR(parser->base)) +@@ -3502,7 +3502,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) + dev->sc_assigned = VIP_NOT_ASSIGNED; + sc = devm_kzalloc(&pdev->dev, sizeof(*dev->sc), GFP_KERNEL); + if (!sc) +- return PTR_ERR_OR_ZERO(sc); ++ return -ENOMEM; + + sc->base = dev->base + (slice ? VIP_SLICE1_SC : VIP_SLICE0_SC); + if (IS_ERR(sc->base)) +@@ -3514,7 +3514,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) + dev->csc_assigned = VIP_NOT_ASSIGNED; + csc = devm_kzalloc(&pdev->dev, sizeof(*dev->csc), GFP_KERNEL); + if (!csc) +- return PTR_ERR_OR_ZERO(csc); ++ return -ENOMEM; + + csc->base = dev->base + (slice ? VIP_SLICE1_CSC : VIP_SLICE0_CSC); + if (IS_ERR(csc->base)) +-- +2.55.0 + diff --git a/queue-7.1/media-ti-vpe-fix-the-error-code-of-devm_request_irq.patch b/queue-7.1/media-ti-vpe-fix-the-error-code-of-devm_request_irq.patch new file mode 100644 index 0000000000..b8f8223b71 --- /dev/null +++ b/queue-7.1/media-ti-vpe-fix-the-error-code-of-devm_request_irq.patch @@ -0,0 +1,37 @@ +From 5e78a431a3f74c632351791d7902c60199d1ce83 Mon Sep 17 00:00:00 2001 +From: Felix Gu +Date: Wed, 18 Mar 2026 01:21:54 +0800 +Subject: media: ti: vpe: Fix the error code of devm_request_irq() + +From: Felix Gu + +commit 5e78a431a3f74c632351791d7902c60199d1ce83 upstream. + +Return the actual error code from devm_request_irq() instead of +incorrectly returning -ENOMEM. + +Fixes: fc2873aa4a21 ("media: ti: vpe: Add the VIP driver") +Cc: stable@vger.kernel.org +Signed-off-by: Felix Gu +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/ti/vpe/vip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/platform/ti/vpe/vip.c b/drivers/media/platform/ti/vpe/vip.c +index a3c5e966f64c..bd34c982b427 100644 +--- a/drivers/media/platform/ti/vpe/vip.c ++++ b/drivers/media/platform/ti/vpe/vip.c +@@ -3472,7 +3472,7 @@ static int vip_probe_slice(struct platform_device *pdev, int slice) + ret = devm_request_irq(&pdev->dev, dev->irq, vip_irq, + 0, VIP_MODULE_NAME, dev); + if (ret < 0) +- return -ENOMEM; ++ return ret; + + spin_lock_init(&dev->slock); + mutex_init(&dev->mutex); +-- +2.55.0 + diff --git a/queue-7.1/media-ti-vpe-unwind-v4l2-device-registration-on-probe-error.patch b/queue-7.1/media-ti-vpe-unwind-v4l2-device-registration-on-probe-error.patch new file mode 100644 index 0000000000..b04edddc3c --- /dev/null +++ b/queue-7.1/media-ti-vpe-unwind-v4l2-device-registration-on-probe-error.patch @@ -0,0 +1,41 @@ +From e0f1c9a90ef665f2587c274a8fed59f2dfc575a6 Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Sun, 26 Apr 2026 22:16:31 +0900 +Subject: media: ti: vpe: unwind v4l2 device registration on probe error + +From: Myeonghun Pak + +commit e0f1c9a90ef665f2587c274a8fed59f2dfc575a6 upstream. + +If the vpe_top resource is missing, vpe_probe() returns -ENODEV after +v4l2_device_register() has succeeded. Probe failures do not call the +driver's remove callback, so the v4l2 device remains registered on that +error path. + +Route that failure through the existing v4l2_device_unregister() unwind +label, matching the other errors after v4l2_device_register(). + +Fixes: 4d59c7d45585 ("media: ti-vpe: vpe: Add missing null pointer checks") +Cc: stable@vger.kernel.org +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Reviewed-by: Yemike Abhilash Chandra +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/ti/vpe/vpe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/ti/vpe/vpe.c ++++ b/drivers/media/platform/ti/vpe/vpe.c +@@ -2539,7 +2539,8 @@ static int vpe_probe(struct platform_dev + "vpe_top"); + if (!dev->res) { + dev_err(&pdev->dev, "missing 'vpe_top' resources data\n"); +- return -ENODEV; ++ ret = -ENODEV; ++ goto v4l2_dev_unreg; + } + + /* diff --git a/queue-7.1/media-uapi-rkisp-correct-name-version-enum.patch b/queue-7.1/media-uapi-rkisp-correct-name-version-enum.patch new file mode 100644 index 0000000000..a83aaf3a2f --- /dev/null +++ b/queue-7.1/media-uapi-rkisp-correct-name-version-enum.patch @@ -0,0 +1,55 @@ +From c4c01c4fd4a3916ffdfb35ad9f511c48e289f51c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= + +Date: Fri, 1 May 2026 21:03:39 +0200 +Subject: media: uapi: rkisp: Correct name version enum +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Niklas Söderlund + +commit c4c01c4fd4a3916ffdfb35ad9f511c48e289f51c upstream. + +The name of the enum to hold the mapping of parameter buffer versions +have a typo in the name, correct it. While this is a uAPI header the +impact should be minimal as the enum is only used as a collection for +the one version number supported. + +Fixes: e9d05e9d5db1 ("media: uapi: rkisp1-config: Add extensible params format") +Cc: stable@vger.kernel.org +Signed-off-by: Niklas Söderlund +Reviewed-by: Laurent Pinchart +Link: https://patch.msgid.link/20260501190339.3449193-1-niklas.soderlund+renesas@ragnatech.se +Signed-off-by: Laurent Pinchart +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + include/uapi/linux/rkisp1-config.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/include/uapi/linux/rkisp1-config.h ++++ b/include/uapi/linux/rkisp1-config.h +@@ -1535,11 +1535,11 @@ struct rkisp1_ext_params_wdr_config { + sizeof(struct rkisp1_ext_params_wdr_config)) + + /** +- * enum rksip1_ext_param_buffer_version - RkISP1 extensible parameters version ++ * enum rkisp1_ext_param_buffer_version - RkISP1 extensible parameters version + * + * @RKISP1_EXT_PARAM_BUFFER_V1: First version of RkISP1 extensible parameters + */ +-enum rksip1_ext_param_buffer_version { ++enum rkisp1_ext_param_buffer_version { + RKISP1_EXT_PARAM_BUFFER_V1 = V4L2_ISP_PARAMS_VERSION_V1, + }; + +@@ -1601,7 +1601,7 @@ enum rksip1_ext_param_buffer_version { + * +---------------------------------------------------------------------+ + * + * @version: The RkISP1 extensible parameters buffer version, see +- * :c:type:`rksip1_ext_param_buffer_version` ++ * :c:type:`rkisp1_ext_param_buffer_version` + * @data_size: The RkISP1 configuration data effective size, excluding this + * header + * @data: The RkISP1 extensible configuration data blocks diff --git a/queue-7.1/media-v4l2-ctrls-request-add-null-check-in-v4l2_ctrl_request_complete.patch b/queue-7.1/media-v4l2-ctrls-request-add-null-check-in-v4l2_ctrl_request_complete.patch new file mode 100644 index 0000000000..9d1c70c791 --- /dev/null +++ b/queue-7.1/media-v4l2-ctrls-request-add-null-check-in-v4l2_ctrl_request_complete.patch @@ -0,0 +1,60 @@ +From caced3578bf9f104a4aaad8f46c4c719e705d9a6 Mon Sep 17 00:00:00 2001 +From: Sergey Shtylyov +Date: Fri, 1 May 2026 23:28:31 +0300 +Subject: media: v4l2-ctrls-request: add NULL check in v4l2_ctrl_request_complete() + +From: Sergey Shtylyov + +commit caced3578bf9f104a4aaad8f46c4c719e705d9a6 upstream. + +If CONFIG_MEDIA_CONTROLLER is undefined, media_request_object_find() will +always return NULL, so its 2nd call in v4l2_ctrl_request_complete() would +fail as well as the 1st one and thus cause hdl to have a wrong value (at +the top of memory) and list_for_each_entry() to iterate over the garbage +data located there. Add NULL check for the 2nd call and place the error +cleanup at the end of v4l2_ctrl_request_complete()... + +Found by Linux Verification Center (linuxtesting.org) with the Svace static +analysis tool. + +Fixes: c3bf5129f339 ("media: v4l2-ctrls: always copy the controls on completion") +Cc: stable@vger.kernel.org +Signed-off-by: Sergey Shtylyov +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-ctrls-request.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-ctrls-request.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c +@@ -348,13 +348,12 @@ void v4l2_ctrl_request_complete(struct m + ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8); + if (!ret) + ret = v4l2_ctrl_request_bind(req, hdl, main_hdl); +- if (ret) { +- v4l2_ctrl_handler_free(hdl); +- kfree(hdl); +- return; +- } ++ if (ret) ++ goto error; + hdl->request_is_queued = true; + obj = media_request_object_find(req, &req_ops, main_hdl); ++ if (!obj) ++ goto error; + } + hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); + +@@ -389,6 +388,11 @@ void v4l2_ctrl_request_complete(struct m + mutex_unlock(main_hdl->lock); + media_request_object_complete(obj); + media_request_object_put(obj); ++ return; ++ ++error: ++ v4l2_ctrl_handler_free(hdl); ++ kfree(hdl); + } + EXPORT_SYMBOL(v4l2_ctrl_request_complete); + diff --git a/queue-7.1/media-v4l2-ctrls-validate-hevc-active-reference-counts.patch b/queue-7.1/media-v4l2-ctrls-validate-hevc-active-reference-counts.patch new file mode 100644 index 0000000000..f0613a6b31 --- /dev/null +++ b/queue-7.1/media-v4l2-ctrls-validate-hevc-active-reference-counts.patch @@ -0,0 +1,63 @@ +From afbe4bc252d90a6f8fad869b06d5430f615f22f9 Mon Sep 17 00:00:00 2001 +From: Pengpeng Hou +Date: Tue, 24 Mar 2026 11:13:26 +0800 +Subject: media: v4l2-ctrls: validate HEVC active reference counts + +From: Pengpeng Hou + +commit afbe4bc252d90a6f8fad869b06d5430f615f22f9 upstream. + +HEVC slice parameters are shared stateless V4L2 controls, but the common +validation path does not verify the active L0/L1 reference counts before +driver-specific code consumes them. + +The original report came from Cedrus, but the active count bounds are +not Cedrus-specific. Validate them in the common HEVC slice control path +so stateless HEVC drivers get the same basic guarantees as soon as the +control is queued. + +Do not reject ref_idx_l0/ref_idx_l1 entries here. Existing userspace may +use out-of-range sentinel values such as 0xff for missing references, and +some hardware can use that information for concealment. Keep this common +check limited to the active reference counts. + +Fixes: d395a78db9eab ("media: hevc: Add decode params control") +Cc: stable@vger.kernel.org +Signed-off-by: Pengpeng Hou +Reviewed-by: Nicolas Dufresne +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-ctrls-core.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c +@@ -971,6 +971,7 @@ static int std_validate_compound(const s + struct v4l2_ctrl_hevc_ext_sps_st_rps *p_hevc_st_rps; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; ++ struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; + struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; + struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params; + struct v4l2_area *area; +@@ -1260,6 +1261,18 @@ static int std_validate_compound(const s + break; + + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: ++ p_hevc_slice_params = p; ++ ++ if (p_hevc_slice_params->num_ref_idx_l0_active_minus1 >= ++ V4L2_HEVC_DPB_ENTRIES_NUM_MAX) ++ return -EINVAL; ++ ++ if (p_hevc_slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_B) ++ break; ++ ++ if (p_hevc_slice_params->num_ref_idx_l1_active_minus1 >= ++ V4L2_HEVC_DPB_ENTRIES_NUM_MAX) ++ return -EINVAL; + break; + + case V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS: diff --git a/queue-7.1/media-v4l2-fwnode-fix-subdev-owner-overwritten-in-v4l2_async_register_subdev_sensor.patch b/queue-7.1/media-v4l2-fwnode-fix-subdev-owner-overwritten-in-v4l2_async_register_subdev_sensor.patch new file mode 100644 index 0000000000..b8caa1d6c0 --- /dev/null +++ b/queue-7.1/media-v4l2-fwnode-fix-subdev-owner-overwritten-in-v4l2_async_register_subdev_sensor.patch @@ -0,0 +1,89 @@ +From 06cb687a5132fcffe624c0070576ab852ac6b568 Mon Sep 17 00:00:00 2001 +From: Mirela Rabulea +Date: Fri, 22 May 2026 17:31:20 +0300 +Subject: media: v4l2-fwnode: Fix subdev owner overwritten in v4l2_async_register_subdev_sensor() + +From: Mirela Rabulea + +commit 06cb687a5132fcffe624c0070576ab852ac6b568 upstream. + +The v4l2 helper v4l2_async_register_subdev_sensor() calls +v4l2_async_register_subdev(), which is a macro that expands to +__v4l2_async_register_subdev(sd,THIS_MODULE). Since the macro is expanded +inside v4l2-fwnode.c, THIS_MODULE resolves to the v4l2-fwnode module +rather than the sensor driver module that originally set sd->owner. When +v4l2-fwnode is built-in, THIS_MODULE evaluates to NULL, which then +overwrites the sensor driver's owner with NULL. + +This causes the problem that the sensor module's reference count is never +incremented during async registration, so the module can be removed while +the subdevice is still in use by a notifier (e.g., a CSI-2 receiver +bridge driver). + +Fix this by renaming v4l2_async_register_subdev_sensor() to +__v4l2_async_register_subdev_sensor() with an added explicit module +argument and introducing a wrapper macro: + #define v4l2_async_register_subdev_sensor(sd) \ + __v4l2_async_register_subdev_sensor(sd, THIS_MODULE) + +This ensures the sensor driver module is properly referenced even when +the sensor driver does not init the owner field before calling +v4l2_async_register_subdev_sensor() and prevents premature module removal. + +Fixes: aef69d54755d ("media: v4l: fwnode: Add a convenience function for registering sensors") +Cc: stable@vger.kernel.org +Suggested-by: Frank Li +Link: https://lore.kernel.org/linux-media/20240315073125.275501-2-sakari.ailus@linux.intel.com/ +Signed-off-by: Mirela Rabulea +Reviewed-by: Laurent Pinchart +Reviewed-by: Frank Li +Signed-off-by: Sakari Ailus +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-fwnode.c | 6 +++--- + include/media/v4l2-async.h | 4 +++- + 2 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1256,7 +1256,7 @@ v4l2_async_nf_parse_fwnode_sensor(struct + return 0; + } + +-int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) ++int __v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *module) + { + struct v4l2_async_notifier *notifier; + int ret; +@@ -1282,7 +1282,7 @@ int v4l2_async_register_subdev_sensor(st + if (ret < 0) + goto out_cleanup; + +- ret = v4l2_async_register_subdev(sd); ++ ret = __v4l2_async_register_subdev(sd, module); + if (ret < 0) + goto out_unregister; + +@@ -1300,7 +1300,7 @@ out_cleanup: + + return ret; + } +-EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor); ++EXPORT_SYMBOL_GPL(__v4l2_async_register_subdev_sensor); + + MODULE_DESCRIPTION("V4L2 fwnode binding parsing library"); + MODULE_LICENSE("GPL"); +--- a/include/media/v4l2-async.h ++++ b/include/media/v4l2-async.h +@@ -333,8 +333,10 @@ int __v4l2_async_register_subdev(struct + * An error is returned if the module is no longer loaded on any attempts + * to register it. + */ ++#define v4l2_async_register_subdev_sensor(sd) \ ++ __v4l2_async_register_subdev_sensor(sd, THIS_MODULE) + int __must_check +-v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd); ++__v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *module); + + /** + * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous diff --git a/queue-7.1/media-v4l2-subdev-fail-enable-disable-_streams-and-s_streaming-nicely.patch b/queue-7.1/media-v4l2-subdev-fail-enable-disable-_streams-and-s_streaming-nicely.patch new file mode 100644 index 0000000000..af528987b8 --- /dev/null +++ b/queue-7.1/media-v4l2-subdev-fail-enable-disable-_streams-and-s_streaming-nicely.patch @@ -0,0 +1,38 @@ +From 0bcbfd1c1142d85faef8df5cb679d37f71394c5f Mon Sep 17 00:00:00 2001 +From: Sakari Ailus +Date: Sat, 21 Mar 2026 23:41:50 +0200 +Subject: media: v4l2-subdev: Fail {enable,disable}_streams and s_streaming nicely + +From: Sakari Ailus + +commit 0bcbfd1c1142d85faef8df5cb679d37f71394c5f upstream. + +If a sub-device does not set enable_streams() and disable_streams() pad +ops while it sets the s_stream() video op to +v4l2_subdev_s_stream_helper(), enabling or disabling streaming either way +on the sub-device will result calling v4l2_subdev_s_stream_helper() and +v4l2_subdev_{enable,disable}_streams() recursively, exhausting the stack. +Return -ENOIOCTLCMD in this case to handle the situation gracefully. + +Fixes: b62949ddaa52 ("media: subdev: Support single-stream case in v4l2_subdev_enable/disable_streams()") +Cc: stable@vger.kernel.org +Signed-off-by: Sakari Ailus +Reviewed-by: Laurent Pinchart +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/v4l2-core/v4l2-subdev.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -2504,6 +2504,10 @@ int v4l2_subdev_s_stream_helper(struct v + u64 source_mask = 0; + int pad_index = -1; + ++ if (WARN_ON(!v4l2_subdev_has_op(sd, pad, enable_streams) || ++ !v4l2_subdev_has_op(sd, pad, disable_streams))) ++ return -ENOIOCTLCMD; ++ + /* + * Find the source pad. This helper is meant for subdevs that have a + * single source pad, so failures shouldn't happen, but catch them diff --git a/queue-7.1/media-vb2-use-ssize_t-for-vb2_read-vb2_write.patch b/queue-7.1/media-vb2-use-ssize_t-for-vb2_read-vb2_write.patch new file mode 100644 index 0000000000..13d90e7f9f --- /dev/null +++ b/queue-7.1/media-vb2-use-ssize_t-for-vb2_read-vb2_write.patch @@ -0,0 +1,99 @@ +From a562d6dc86bdfdd299e1b4734977a8d63e803583 Mon Sep 17 00:00:00 2001 +From: Zile Xiong +Date: Fri, 20 Mar 2026 14:54:45 +0800 +Subject: media: vb2: use ssize_t for vb2_read/vb2_write + +From: Zile Xiong + +commit a562d6dc86bdfdd299e1b4734977a8d63e803583 upstream. + +vb2_read() and vb2_write() return size_t, but propagate +negative errno values from __vb2_perform_fileio(). + +This relies on implicit signed/unsigned conversions in callers +(e.g. vb2_fop_read()) to recover error codes: + + __vb2_perform_fileio() -> -EINVAL + vb2_read() -> (size_t)-EINVAL + vb2_fop_read() -> -EINVAL + +This relies on implicit conversions that are not obvious. + +These helpers are exported (EXPORT_SYMBOL_GPL) and part of the +vb2 API, so changing their return type may affect existing users. + +However, they conceptually follow read/write semantics, where +ssize_t is typically used to return either a byte count or a +negative error code. + +Switch vb2_read() and vb2_write() to ssize_t, and update +__vb2_perform_fileio() accordingly. + +Signed-off-by: Zile Xiong +Acked-by: Marek Szyprowski +Fixes: b25748fe6126 ("[media] v4l: videobuf2: add read() and write() emulator") +Cc: stable@vger.kernel.org +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/common/videobuf2/videobuf2-core.c | 12 ++++++------ + include/media/videobuf2-core.h | 8 ++++---- + 2 files changed, 10 insertions(+), 10 deletions(-) + +--- a/drivers/media/common/videobuf2/videobuf2-core.c ++++ b/drivers/media/common/videobuf2/videobuf2-core.c +@@ -2990,8 +2990,8 @@ static int __vb2_cleanup_fileio(struct v + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + * @read: access mode selector (1 means read, 0 means write) + */ +-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, +- loff_t *ppos, int nonblock, int read) ++static ssize_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, ++ loff_t *ppos, int nonblock, int read) + { + struct vb2_fileio_data *fileio; + struct vb2_fileio_buf *buf; +@@ -3154,15 +3154,15 @@ static size_t __vb2_perform_fileio(struc + return ret; + } + +-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, +- loff_t *ppos, int nonblocking) ++ssize_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, ++ loff_t *ppos, int nonblocking) + { + return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); + } + EXPORT_SYMBOL_GPL(vb2_read); + +-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, +- loff_t *ppos, int nonblocking) ++ssize_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, ++ loff_t *ppos, int nonblocking) + { + return __vb2_perform_fileio(q, (char __user *) data, count, + ppos, nonblocking, 0); +--- a/include/media/videobuf2-core.h ++++ b/include/media/videobuf2-core.h +@@ -1093,8 +1093,8 @@ __poll_t vb2_core_poll(struct vb2_queue + * @ppos: file handle position tracking pointer + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + */ +-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, +- loff_t *ppos, int nonblock); ++ssize_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, ++ loff_t *ppos, int nonblock); + /** + * vb2_write() - implements write() syscall logic. + * @q: pointer to &struct vb2_queue with videobuf2 queue. +@@ -1103,8 +1103,8 @@ size_t vb2_read(struct vb2_queue *q, cha + * @ppos: file handle position tracking pointer + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + */ +-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, +- loff_t *ppos, int nonblock); ++ssize_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, ++ loff_t *ppos, int nonblock); + + /** + * typedef vb2_thread_fnc - callback function for use with vb2_thread. diff --git a/queue-7.1/media-verisilicon-export-only-needed-pixels-formats.patch b/queue-7.1/media-verisilicon-export-only-needed-pixels-formats.patch new file mode 100644 index 0000000000..524cf29519 --- /dev/null +++ b/queue-7.1/media-verisilicon-export-only-needed-pixels-formats.patch @@ -0,0 +1,56 @@ +From e0f5d6ae76423ec5b6f97c7c3e1f02187b988afd Mon Sep 17 00:00:00 2001 +From: Benjamin Gaignard +Date: Tue, 24 Jun 2025 14:29:38 +0200 +Subject: media: verisilicon: Export only needed pixels formats + +From: Benjamin Gaignard + +commit e0f5d6ae76423ec5b6f97c7c3e1f02187b988afd upstream. + +Some pixel formats can only be produced if the decoder outputs +reference pictures directly. In some cases, such as AV1 film-grain, +the use of the post-processor is strictly required. In this case, +only enumerate the post-processor supported formats. The exception is +when V4L2_FMTDESC_FLAG_ENUM_ALL is set, in this case, we enumerate +everything regardless of the state. + +Signed-off-by: Benjamin Gaignard +Fixes: bcd4f091cf1e ("media: verisilicon: Use V4L2_FMTDESC_FLAG_ENUM_ALL flag") +Cc: stable@vger.kernel.org +Reviewed-by: Nicolas Dufresne +Signed-off-by: Nicolas Dufresne +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/verisilicon/hantro_v4l2.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/media/platform/verisilicon/hantro_v4l2.c ++++ b/drivers/media/platform/verisilicon/hantro_v4l2.c +@@ -222,6 +222,7 @@ static int vidioc_enum_fmt(struct file * + unsigned int num_fmts, i, j = 0; + bool skip_mode_none, enum_all_formats; + u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL; ++ bool need_postproc = ctx->need_postproc; + + /* + * If the V4L2_FMTDESC_FLAG_ENUM_ALL flag is set, we want to enumerate all +@@ -230,6 +231,9 @@ static int vidioc_enum_fmt(struct file * + enum_all_formats = !!(f->index & V4L2_FMTDESC_FLAG_ENUM_ALL); + f->index = index; + ++ if (enum_all_formats) ++ need_postproc = HANTRO_AUTO_POSTPROC; ++ + /* + * When dealing with an encoder: + * - on the capture side we want to filter out all MODE_NONE formats. +@@ -242,7 +246,7 @@ static int vidioc_enum_fmt(struct file * + */ + skip_mode_none = capture == ctx->is_encoder; + +- formats = hantro_get_formats(ctx, &num_fmts, HANTRO_AUTO_POSTPROC); ++ formats = hantro_get_formats(ctx, &num_fmts, need_postproc); + for (i = 0; i < num_fmts; i++) { + bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE; + fmt = &formats[i]; diff --git a/queue-7.1/media-vidtv-fix-reference-leak-on-failed-device-registration.patch b/queue-7.1/media-vidtv-fix-reference-leak-on-failed-device-registration.patch new file mode 100644 index 0000000000..070d09d708 --- /dev/null +++ b/queue-7.1/media-vidtv-fix-reference-leak-on-failed-device-registration.patch @@ -0,0 +1,49 @@ +From 9aa21e1549db8882ff77b691e7714153df21dff0 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Wed, 15 Apr 2026 23:28:26 +0800 +Subject: media: vidtv: fix reference leak on failed device registration + +From: Guangshuo Li + +commit 9aa21e1549db8882ff77b691e7714153df21dff0 upstream. + +When platform_device_register() fails in vidtv_bridge_init(), the +embedded struct device in vidtv_bridge_dev has already been initialized +by device_initialize(), but the failure path returns the error without +dropping the device reference for the current platform device: + + vidtv_bridge_init() + -> platform_device_register(&vidtv_bridge_dev) + -> device_initialize(&vidtv_bridge_dev.dev) + -> setup_pdev_dma_masks(&vidtv_bridge_dev) + -> platform_device_add(&vidtv_bridge_dev) + +This leads to a reference leak when platform_device_register() fails. +Fix this by calling platform_device_put() before returning the error. + +The issue was identified by a static analysis tool I developed and +confirmed by manual review. + +Fixes: f90cf6079bf67 ("media: vidtv: add a bridge driver") +Cc: stable@vger.kernel.org +Signed-off-by: Guangshuo Li +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/test-drivers/vidtv/vidtv_bridge.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c ++++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c +@@ -594,8 +594,10 @@ static int __init vidtv_bridge_init(void + int ret; + + ret = platform_device_register(&vidtv_bridge_dev); +- if (ret) ++ if (ret) { ++ platform_device_put(&vidtv_bridge_dev); + return ret; ++ } + + ret = platform_driver_register(&vidtv_bridge_driver); + if (ret) diff --git a/queue-7.1/media-vimc-fix-reference-leak-on-failed-device-registration.patch b/queue-7.1/media-vimc-fix-reference-leak-on-failed-device-registration.patch new file mode 100644 index 0000000000..1184720622 --- /dev/null +++ b/queue-7.1/media-vimc-fix-reference-leak-on-failed-device-registration.patch @@ -0,0 +1,45 @@ +From 33e2b833c66b890a0d71c4fa82d4c97143f7f75f Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Wed, 15 Apr 2026 23:45:37 +0800 +Subject: media: vimc: fix reference leak on failed device registration + +From: Guangshuo Li + +commit 33e2b833c66b890a0d71c4fa82d4c97143f7f75f upstream. + +When platform_device_register() fails in vimc_init(), the embedded +struct device in vimc_pdev has already been initialized by +device_initialize(), but the failure path returns the error without +dropping the device reference for the current platform device: + + vimc_init() + -> platform_device_register(&vimc_pdev) + -> device_initialize(&vimc_pdev.dev) + -> setup_pdev_dma_masks(&vimc_pdev) + -> platform_device_add(&vimc_pdev) + +This leads to a reference leak when platform_device_register() fails. +Fix this by calling platform_device_put() before returning the error. + +The issue was identified by a static analysis tool I developed and +confirmed by manual review. + +Fixes: 4babf057c143f ("media: vimc: allocate vimc_device dynamically") +Cc: stable@vger.kernel.org +Signed-off-by: Guangshuo Li +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/test-drivers/vimc/vimc-core.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/test-drivers/vimc/vimc-core.c ++++ b/drivers/media/test-drivers/vimc/vimc-core.c +@@ -421,6 +421,7 @@ static int __init vimc_init(void) + if (ret) { + dev_err(&vimc_pdev.dev, + "platform device registration failed (err=%d)\n", ret); ++ platform_device_put(&vimc_pdev); + return ret; + } + diff --git a/queue-7.1/media-vivid-add-vivid_update_reduced_fps.patch b/queue-7.1/media-vivid-add-vivid_update_reduced_fps.patch new file mode 100644 index 0000000000..be577ed214 --- /dev/null +++ b/queue-7.1/media-vivid-add-vivid_update_reduced_fps.patch @@ -0,0 +1,104 @@ +From 1d793a29efb4260f90913f5287939bf95573b073 Mon Sep 17 00:00:00 2001 +From: Hans Verkuil +Date: Wed, 20 May 2026 09:30:44 +0200 +Subject: media: vivid: add vivid_update_reduced_fps() + +From: Hans Verkuil + +commit 1d793a29efb4260f90913f5287939bf95573b073 upstream. + +Don't call vivid_update_format_cap() when switching to/from reduced fps +for HDMI inputs: that will also reset the format, which is overkill for +this. + +Make a new vivid_update_reduced_fps() function that just updates the +dev->timeperframe_vid_cap. + +Reviewed-by: Nicolas Dufresne +Fixes: c79aa6aeadb0 ("[media] vivid-capture: add control for reduced frame rate") +Cc: stable@vger.kernel.org +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/test-drivers/vivid/vivid-ctrls.c | 3 +- + drivers/media/test-drivers/vivid/vivid-vid-cap.c | 32 +++++++++++++---------- + drivers/media/test-drivers/vivid/vivid-vid-cap.h | 1 + 3 files changed, 22 insertions(+), 14 deletions(-) + +--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c ++++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c +@@ -609,7 +609,8 @@ static int vivid_vid_cap_s_ctrl(struct v + break; + case VIVID_CID_REDUCED_FPS: + dev->reduced_fps = ctrl->val; +- vivid_update_format_cap(dev, true); ++ if (dev->input_type[dev->input] == HDMI) ++ vivid_update_reduced_fps(dev); + break; + case VIVID_CID_HAS_CROP_CAP: + dev->has_crop_cap = ctrl->val; +--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c +@@ -364,6 +364,24 @@ static enum tpg_pixel_aspect vivid_get_p + return TPG_PIXEL_ASPECT_SQUARE; + } + ++void vivid_update_reduced_fps(struct vivid_dev *dev) ++{ ++ struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; ++ unsigned int size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); ++ u64 pixelclock; ++ ++ if (dev->reduced_fps && can_reduce_fps(bt)) { ++ pixelclock = div_u64(bt->pixelclock * 1000, 1001); ++ bt->flags |= V4L2_DV_FL_REDUCED_FPS; ++ } else { ++ pixelclock = bt->pixelclock; ++ bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; ++ } ++ dev->timeperframe_vid_cap = (struct v4l2_fract) { ++ size / 100, (u32)pixelclock / 100 ++ }; ++} ++ + /* + * Called whenever the format has to be reset which can occur when + * changing inputs, standard, timings, etc. +@@ -372,8 +390,6 @@ void vivid_update_format_cap(struct vivi + { + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; + u32 dims[V4L2_CTRL_MAX_DIMS] = {}; +- unsigned size; +- u64 pixelclock; + + switch (dev->input_type[dev->input]) { + case WEBCAM: +@@ -402,17 +418,7 @@ void vivid_update_format_cap(struct vivi + case HDMI: + dev->src_rect.width = bt->width; + dev->src_rect.height = bt->height; +- size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); +- if (dev->reduced_fps && can_reduce_fps(bt)) { +- pixelclock = div_u64(bt->pixelclock * 1000, 1001); +- bt->flags |= V4L2_DV_FL_REDUCED_FPS; +- } else { +- pixelclock = bt->pixelclock; +- bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; +- } +- dev->timeperframe_vid_cap = (struct v4l2_fract) { +- size / 100, (u32)pixelclock / 100 +- }; ++ vivid_update_reduced_fps(dev); + if (bt->interlaced) + dev->field_cap = V4L2_FIELD_ALTERNATE; + else +--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h ++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h +@@ -9,6 +9,7 @@ + #define _VIVID_VID_CAP_H_ + + void vivid_update_quality(struct vivid_dev *dev); ++void vivid_update_reduced_fps(struct vivid_dev *dev); + void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls); + void vivid_update_outputs(struct vivid_dev *dev); + void vivid_update_connected_outputs(struct vivid_dev *dev); diff --git a/queue-7.1/media-vivid-check-for-vb2_is_busy-when-toggling-caps.patch b/queue-7.1/media-vivid-check-for-vb2_is_busy-when-toggling-caps.patch new file mode 100644 index 0000000000..d6b941b016 --- /dev/null +++ b/queue-7.1/media-vivid-check-for-vb2_is_busy-when-toggling-caps.patch @@ -0,0 +1,115 @@ +From c2d1a2130c93f6d758af58590b86b2254c7a1dec Mon Sep 17 00:00:00 2001 +From: Hans Verkuil +Date: Wed, 20 May 2026 09:22:41 +0200 +Subject: media: vivid: check for vb2_is_busy() when toggling caps + +From: Hans Verkuil + +commit c2d1a2130c93f6d758af58590b86b2254c7a1dec upstream. + +The vivid_update_format_cap/out() functions must only be called if the +capture/output queue are not busy. But for the controls that select +the CROP/COMPOSE/SCALE capability that is not checked. + +Only when streaming starts will they be set to 'grabbed' and it is +impossible to change the control, but between REQBUFS and STREAMON you +are still allowed to set these controls. Since vivid_update_format_cap/out +will change the format, this can cause unexpected results. + +Besides adding these checks, also add a WARN_ON in +vivid_update_format_cap/out() if the queue is busy. + +I'm 90% certain that this is the cause of this syzbot bug: + +https://syzkaller.appspot.com/bug?extid=dac8f5eaa46837e97b89 + +But since we never have reproducers, it is hard to be certain. In any case, +these checks are needed regardless. + +Reviewed-by: Nicolas Dufresne +Fixes: 73c3f48230cd ("[media] vivid: add the control handling code") +Cc: stable@vger.kernel.org +Reported-by: syzbot+dac8f5eaa46837e97b89@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=dac8f5eaa46837e97b89 +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/test-drivers/vivid/vivid-ctrls.c | 12 ++++++++++++ + drivers/media/test-drivers/vivid/vivid-vid-cap.c | 6 ++++++ + drivers/media/test-drivers/vivid/vivid-vid-out.c | 6 ++++++ + 3 files changed, 24 insertions(+) + +--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c ++++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c +@@ -613,14 +613,20 @@ static int vivid_vid_cap_s_ctrl(struct v + vivid_update_reduced_fps(dev); + break; + case VIVID_CID_HAS_CROP_CAP: ++ if (vb2_is_busy(&dev->vb_vid_cap_q)) ++ return -EBUSY; + dev->has_crop_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_COMPOSE_CAP: ++ if (vb2_is_busy(&dev->vb_vid_cap_q)) ++ return -EBUSY; + dev->has_compose_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_SCALER_CAP: ++ if (vb2_is_busy(&dev->vb_vid_cap_q)) ++ return -EBUSY; + dev->has_scaler_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; +@@ -1117,14 +1123,20 @@ static int vivid_vid_out_s_ctrl(struct v + + switch (ctrl->id) { + case VIVID_CID_HAS_CROP_OUT: ++ if (vb2_is_busy(&dev->vb_vid_out_q)) ++ return -EBUSY; + dev->has_crop_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_COMPOSE_OUT: ++ if (vb2_is_busy(&dev->vb_vid_out_q)) ++ return -EBUSY; + dev->has_compose_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_SCALER_OUT: ++ if (vb2_is_busy(&dev->vb_vid_out_q)) ++ return -EBUSY; + dev->has_scaler_out = ctrl->val; + vivid_update_format_out(dev); + break; +--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c +@@ -391,6 +391,12 @@ void vivid_update_format_cap(struct vivi + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; + u32 dims[V4L2_CTRL_MAX_DIMS] = {}; + ++ /* ++ * This resets the format, so must never be called while vb2_is_busy(). ++ */ ++ if (WARN_ON(vb2_is_busy(&dev->vb_vid_cap_q))) ++ return; ++ + switch (dev->input_type[dev->input]) { + case WEBCAM: + default: +--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c ++++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c +@@ -214,6 +214,12 @@ void vivid_update_format_out(struct vivi + unsigned size, p; + u64 pixelclock; + ++ /* ++ * This resets the format, so must never be called while vb2_is_busy(). ++ */ ++ if (WARN_ON(vb2_is_busy(&dev->vb_vid_out_q))) ++ return; ++ + switch (dev->output_type[dev->output]) { + case SVID: + default: diff --git a/queue-7.1/media-vivid-fix-cleanup-bugs-in-vivid_init.patch b/queue-7.1/media-vivid-fix-cleanup-bugs-in-vivid_init.patch new file mode 100644 index 0000000000..8faa7c21f0 --- /dev/null +++ b/queue-7.1/media-vivid-fix-cleanup-bugs-in-vivid_init.patch @@ -0,0 +1,66 @@ +From a07c179a92e949172ca52f6d4a13202ea88cd4b7 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Thu, 16 Apr 2026 00:20:58 +0800 +Subject: media: vivid: fix cleanup bugs in vivid_init() + +From: Guangshuo Li + +commit a07c179a92e949172ca52f6d4a13202ea88cd4b7 upstream. + +When platform_device_register() fails in vivid_init(), the embedded +struct device in vivid_pdev has already been initialized by +device_initialize(), but the failure path jumps to free_output_strings +without dropping the device reference for the current platform device: + + vivid_init() + -> platform_device_register(&vivid_pdev) + -> device_initialize(&vivid_pdev.dev) + -> setup_pdev_dma_masks(&vivid_pdev) + -> platform_device_add(&vivid_pdev) + +This leads to a reference leak when platform_device_register() fails. +Fix this by calling platform_device_put() before jumping to the common +cleanup path. + +Also, the unreg_driver label incorrectly calls +platform_driver_register() instead of platform_driver_unregister(), +which breaks cleanup when workqueue creation fails after successful +driver registration. Fix that as well. + +The reference leak was identified by a static analysis tool I developed +and confirmed by manual review. The incorrect cleanup call was found +during code inspection. + +Fixes: f46d740fb0258 ("[media] vivid: turn this into a platform_device") +Fixes: d7c969f37515d ("media: vivid: Add 'Is Connected To' menu controls") +Cc: stable@vger.kernel.org +Signed-off-by: Guangshuo Li +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/test-drivers/vivid/vivid-core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/media/test-drivers/vivid/vivid-core.c ++++ b/drivers/media/test-drivers/vivid/vivid-core.c +@@ -2289,8 +2289,10 @@ static int __init vivid_init(void) + } + } + ret = platform_device_register(&vivid_pdev); +- if (ret) ++ if (ret) { ++ platform_device_put(&vivid_pdev); + goto free_output_strings; ++ } + ret = platform_driver_register(&vivid_pdrv); + if (ret) + goto unreg_device; +@@ -2311,7 +2313,7 @@ static int __init vivid_init(void) + destroy_hdmi_wq: + destroy_workqueue(update_hdmi_ctrls_workqueue); + unreg_driver: +- platform_driver_register(&vivid_pdrv); ++ platform_driver_unregister(&vivid_pdrv); + unreg_device: + platform_device_unregister(&vivid_pdev); + free_output_strings: diff --git a/queue-7.1/media-vpif_capture-fix-of-node-reference-imbalance.patch b/queue-7.1/media-vpif_capture-fix-of-node-reference-imbalance.patch new file mode 100644 index 0000000000..c60b9b2b2c --- /dev/null +++ b/queue-7.1/media-vpif_capture-fix-of-node-reference-imbalance.patch @@ -0,0 +1,36 @@ +From 2282f979560af6bbc8ee2c1ee8663197312cee5b Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 7 Apr 2026 12:08:31 +0200 +Subject: media: vpif_capture: fix OF node reference imbalance + +From: Johan Hovold + +commit 2282f979560af6bbc8ee2c1ee8663197312cee5b upstream. + +The driver reuses the OF node of the parent device but fails to take +another reference to balance the one dropped by the platform bus code +when unbinding the parent and releasing the child devices. + +Fix this by using the intended helper for reusing OF nodes. + +Fixes: 4a5f8ae50b66 ("[media] davinci: vpif_capture: get subdevs from DT when available") +Cc: stable@vger.kernel.org # 4.13 +Cc: Kevin Hilman +Signed-off-by: Johan Hovold +Signed-off-by: Hans Verkuil +Signed-off-by: Greg Kroah-Hartman +--- + drivers/media/platform/ti/davinci/vpif_capture.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/media/platform/ti/davinci/vpif_capture.c ++++ b/drivers/media/platform/ti/davinci/vpif_capture.c +@@ -1498,7 +1498,7 @@ vpif_capture_get_pdata(struct platform_d + * video ports & endpoints data. + */ + if (pdev->dev.parent && pdev->dev.parent->of_node) +- pdev->dev.of_node = pdev->dev.parent->of_node; ++ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) + return pdev->dev.platform_data; + diff --git a/queue-7.1/platform-loongarch-laptop-explicitly-reset-bl_powered-state-when-suspend.patch b/queue-7.1/platform-loongarch-laptop-explicitly-reset-bl_powered-state-when-suspend.patch new file mode 100644 index 0000000000..8b050afc45 --- /dev/null +++ b/queue-7.1/platform-loongarch-laptop-explicitly-reset-bl_powered-state-when-suspend.patch @@ -0,0 +1,40 @@ +From 91a70492c03040d51b36f595530d6491d5d6c541 Mon Sep 17 00:00:00 2001 +From: Zixing Liu +Date: Fri, 24 Jul 2026 16:33:14 +0800 +Subject: platform/loongarch: laptop: Explicitly reset bl_powered state when suspend + +From: Zixing Liu + +commit 91a70492c03040d51b36f595530d6491d5d6c541 upstream. + +On EAECIS NL60R with EC firmware version 1.11, resuming from S3 has a +very high chance (>90%) of causing the EC to lose the previous backlight +power state. When this happens, the laptop resumes normally from S3, but +the backlight remains off (when shining on the screen with a flash light, +we can see the screen contents are updating normally). + +Since there is no generic way to query the EC's backlight state on +Loongson laptop platforms, assume the worst-case scenario and restart +the backlight power inside the kernel each time the system resumes. + +Cc: stable@vger.kernel.org +Fixes: 53c762b47f72 ("platform/loongarch: laptop: Add backlight power control support") +Tested-by: Yao Zi +Tested-by: Xi Ruoyao +Signed-off-by: Zixing Liu +Signed-off-by: Huacai Chen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/loongarch/loongson-laptop.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/platform/loongarch/loongson-laptop.c ++++ b/drivers/platform/loongarch/loongson-laptop.c +@@ -189,6 +189,7 @@ static int __init setup_acpi_notify(stru + + static int loongson_hotkey_suspend(struct device *dev) + { ++ bl_powered = false; + return 0; + } + diff --git a/queue-7.1/series b/queue-7.1/series index ff816b16c8..384054254b 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -499,3 +499,67 @@ media-msi2500-return-queued-buffers-on-start_streaming-failure.patch media-nuvoton-npcm-video-fix-error-handling-in-npcm_video_init.patch media-nuvoton-npcm-video-fix-memory-leaks-in-probe-and-remove.patch media-nxp-imx8-isi-add-missing-v4l2_subdev_cleanup-in-crossbar-and-pipe.patch +media-nxp-imx8-isi-clean-up-already-initialized-pipes-on-probe-failure.patch +media-nxp-imx8-isi-fix-missing-v4l2_subdev_cleanup-in-pipe-init-error-path.patch +media-nxp-imx8-isi-fix-potential-out-of-bounds-issues.patch +media-nxp-imx8-isi-fix-scale-factor-calculation-for-hardware-rounding.patch +media-pci-dm1105-free-allocated-workqueue.patch +media-pwc-drain-fill_buf-on-start_streaming-failure.patch +media-pwc-return-queued-buffers-on-start_streaming-failure.patch +media-qcom-camss-fix-rdi-streaming-for-csid-680.patch +media-qcom-camss-fix-rdi-streaming-for-csid-gen2.patch +media-qcom-camss-fix-rdi-streaming-for-csid-gen3.patch +media-qcom-camss-fix-rdi-streaming-for-csid-340.patch +media-radio-si476x-unregister-v4l2_device-on-probe-failure.patch +media-rtl2832-fix-use-after-free-in-rtl2832_remove.patch +media-rtl2832_sdr-return-queued-buffers-on-start_streaming-failure.patch +media-rzg2l-cru-skip-icnmc-configuration-when-icnsvc-is-used.patch +media-rzv2h-ivc-wait-for-frame-end-in-stop_streaming.patch +media-saa7134-fix-a-possible-memory-leak-in-saa7134_video_init1.patch +media-stm32-dcmipp-return-queued-buffers-on-start_streaming-failure.patch +media-stm32-dcmi-unregister-notifier-on-probe-failure.patch +media-sun4i-csi-return-queued-buffers-on-start_streaming-failure.patch +media-synopsys-hdmirx-fix-hpd-lane-hold-time.patch +media-tegra-video-vi-fix-invalid-u32-return-value-in-format-lookup.patch +media-ti-vpe-fix-fwnode_handle-leak-in-vip_probe_complete.patch +media-ti-vpe-fix-the-error-code-of-devm_kzalloc-in-vip_probe_slice.patch +media-ti-vpe-fix-the-error-code-of-devm_request_irq.patch +media-ti-vpe-unwind-v4l2-device-registration-on-probe-error.patch +media-uapi-rkisp-correct-name-version-enum.patch +media-v4l2-ctrls-request-add-null-check-in-v4l2_ctrl_request_complete.patch +media-v4l2-ctrls-validate-hevc-active-reference-counts.patch +media-v4l2-fwnode-fix-subdev-owner-overwritten-in-v4l2_async_register_subdev_sensor.patch +media-v4l2-subdev-fail-enable-disable-_streams-and-s_streaming-nicely.patch +media-vb2-use-ssize_t-for-vb2_read-vb2_write.patch +media-verisilicon-export-only-needed-pixels-formats.patch +media-vidtv-fix-reference-leak-on-failed-device-registration.patch +media-vimc-fix-reference-leak-on-failed-device-registration.patch +media-vivid-add-vivid_update_reduced_fps.patch +media-vivid-check-for-vb2_is_busy-when-toggling-caps.patch +media-vivid-fix-cleanup-bugs-in-vivid_init.patch +media-vpif_capture-fix-of-node-reference-imbalance.patch +alsa-hda-realtek-fix-speakers-on-lunnen-ground-14.patch +alsa-seq-close-a-re-opened-queue-timer-in-the-destructor.patch +alsa-hda-codecs-hdmi-disable-keep-alive-before-audio-format-change.patch +alsa-timer-drain-a-slave-s-callback-before-its-master-detaches-it.patch +alsa-timer-don-t-re-enter-an-instance-callback-that-is-still-running.patch +wifi-ath6kl-fix-oob-access-from-firmware-addba-window-size.patch +wifi-ath6kl-fix-use-after-free-in-aggr_reset_state.patch +wifi-mwifiex-fix-null-dereference-when-the-ap-has-ht-cap-but-no-ht-oper.patch +wifi-wilc1000-validate-assoc-response-length-before-subtracting-header.patch +wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch +wifi-mt76-mt7921-drop-txrx_notify-on-non-mmio-buses.patch +wifi-mt76-mt7925-drop-txrx_notify-on-non-mmio-buses.patch +wifi-mt76-restrict-npu-ppe-active-checks-to-mmio-devices.patch +wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch +wifi-brcmfmac-make-release_scratchbuffers-idempotent.patch +wifi-brcmfmac-set-f2-blocksize-to-256-for-bcm43752.patch +wifi-ath11k-fix-refcount-leak-in-ath11k_ahb_fw_resources_init.patch +wifi-ath12k-fix-null-pointer-dereference-in-rhash-table-destroy.patch +staging-rtl8723bs-fix-oob-reads-in-rtw_get_wps_ie.patch +staging-rtl8723bs-fix-inverted-ht40-secondary-channel-offset.patch +bluetooth-hci_sync-protect-uuid-list-traversal.patch +bluetooth-rfcomm-fix-session-uaf-in-set_termios.patch +exec-fix-unsigned-loop-counter-wrap-in-transfer_args_to_stack.patch +binfmt_misc-set-have_execfd-only-once-the-interpreter-is-opened.patch +platform-loongarch-laptop-explicitly-reset-bl_powered-state-when-suspend.patch diff --git a/queue-7.1/staging-rtl8723bs-fix-inverted-ht40-secondary-channel-offset.patch b/queue-7.1/staging-rtl8723bs-fix-inverted-ht40-secondary-channel-offset.patch new file mode 100644 index 0000000000..17a804b560 --- /dev/null +++ b/queue-7.1/staging-rtl8723bs-fix-inverted-ht40-secondary-channel-offset.patch @@ -0,0 +1,59 @@ +From 30d49cba27f8905bc288cef5846963f0004f644c Mon Sep 17 00:00:00 2001 +From: MinJea Kim +Date: Tue, 14 Jul 2026 22:14:21 +0900 +Subject: staging: rtl8723bs: fix inverted HT40 secondary channel offset + +From: MinJea Kim + +commit 30d49cba27f8905bc288cef5846963f0004f644c upstream. + +rtw_get_chan_type() maps the driver's channel offset to nl80211 channel +types the wrong way around. + +In this driver HAL_PRIME_CHNL_OFFSET_LOWER means the primary channel is +the lower 20 MHz half of the 40 MHz pair, i.e. the secondary channel is +above the primary one: rtw_get_center_ch() computes the center channel +as "channel + 2" for OFFSET_LOWER, and bwmode_update_check() sets +OFFSET_LOWER when the AP's HT operation IE announces SCA (secondary +channel above). In nl80211 terms that is NL80211_CHAN_HT40PLUS, not +HT40MINUS. + +Because of the inversion, cfg80211_rtw_get_channel() reports an HT40+ +association as HT40-. For an HT40+ AP on a low channel (e.g. channel 3) +the resulting chandef spans below the 2.4 GHz band edge and is invalid, +so the regulatory core tears the connection down 60 seconds +(REG_ENFORCE_GRACE_MS) after the AP's country IE triggers a regdomain +change: reg_check_chans_work() considers the reported chandef unusable +and calls cfg80211_leave(). The supplicant then reconnects, the country +IE changes the regdomain again, and the cycle repeats, causing a +disconnect/reconnect loop every ~65 seconds for as long as the link is +up. + +Observed on a TECLAST X80 Power tablet (RTL8723BS) associated to an +HT40+ AP on channel 3 with a KR country IE; a kprobe trace showed +cfg80211_disconnect() being invoked from reg_check_chans_work(). With +the mapping fixed, "iw dev wlan0 info" reports the correct +"width: 40 MHz, center1: 2432 MHz" and the periodic disconnects stop. + +Fixes: 5402cc178c5d ("staging: rtl8723bs: add get_channel cfg80211 implementation") +Cc: stable@vger.kernel.org +Assisted-by: Claude-Code:claude-fable-5 bpftrace +Signed-off-by: MinJea Kim +Link: https://patch.msgid.link/20260714131421.3980-1-qndkdrnl@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +@@ -1956,7 +1956,7 @@ static u8 rtw_get_chan_type(struct adapt + else + return NL80211_CHAN_NO_HT; + case CHANNEL_WIDTH_40: +- if (mlme_ext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ if (mlme_ext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + return NL80211_CHAN_HT40PLUS; + else + return NL80211_CHAN_HT40MINUS; diff --git a/queue-7.1/staging-rtl8723bs-fix-oob-reads-in-rtw_get_wps_ie.patch b/queue-7.1/staging-rtl8723bs-fix-oob-reads-in-rtw_get_wps_ie.patch new file mode 100644 index 0000000000..c4e897b18c --- /dev/null +++ b/queue-7.1/staging-rtl8723bs-fix-oob-reads-in-rtw_get_wps_ie.patch @@ -0,0 +1,49 @@ +From 0e95ff792ae0aa6fbad9455943e9e1e4062670e9 Mon Sep 17 00:00:00 2001 +From: Moksh Panicker +Date: Thu, 25 Jun 2026 20:29:11 +0000 +Subject: staging: rtl8723bs: fix OOB reads in rtw_get_wps_ie() + +From: Moksh Panicker + +commit 0e95ff792ae0aa6fbad9455943e9e1e4062670e9 upstream. + +rtw_get_wps_ie() iterates over IE data from network frames without +validating that the IE header and payload fit within the remaining +buffer before reading them. Specifically: + +- in_ie[cnt + 1] is read without checking cnt + 1 < in_len +- memcmp(&in_ie[cnt + 2], ...) accesses cnt + 2 without bounds check +- in_ie[cnt + 1] is used as length without verifying payload fits + +Add bounds checks at the top of the loop body to break early if fewer +than 2 bytes remain for the IE header, or if the declared payload +extends past the end of the buffer. Also require at least 4 bytes of +payload before comparing the WPS OUI. + +Fixes: 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver") +Cc: stable +Signed-off-by: Moksh Panicker +Link: https://patch.msgid.link/20260625202911.26782-1-mokshpanicker.7@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c ++++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +@@ -671,7 +671,14 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_le + while (cnt < in_len) { + eid = in_ie[cnt]; + +- if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { ++ if (cnt + 2 > in_len) ++ break; ++ ++ if (in_ie[cnt + 1] + 2 > in_len - cnt) ++ break; ++ ++ if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (in_ie[cnt + 1] >= 4) && ++ (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { + wpsie_ptr = &in_ie[cnt]; + + if (wps_ie) diff --git a/queue-7.1/wifi-ath11k-fix-refcount-leak-in-ath11k_ahb_fw_resources_init.patch b/queue-7.1/wifi-ath11k-fix-refcount-leak-in-ath11k_ahb_fw_resources_init.patch new file mode 100644 index 0000000000..7505d0da30 --- /dev/null +++ b/queue-7.1/wifi-ath11k-fix-refcount-leak-in-ath11k_ahb_fw_resources_init.patch @@ -0,0 +1,36 @@ +From 0e120ee0822b7cc650bd7b29682a34e137cec10d Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Tue, 9 Jun 2026 09:25:28 +0000 +Subject: wifi: ath11k: fix refcount leak in ath11k_ahb_fw_resources_init() + +From: Wentao Liang + +commit 0e120ee0822b7cc650bd7b29682a34e137cec10d upstream. + +of_get_child_by_name() returns a node pointer with refcount +incremented, but the error path when ath11k_ahb_setup_msa_resources() +fails does not release it. Add the missing of_node_put() to avoid +leaking the reference. + +Cc: stable@vger.kernel.org +Fixes: 095cb947490c ("wifi: ath11k: allow missing memory-regions") +Signed-off-by: Wentao Liang +Reviewed-by: Baochen Qiang +Reviewed-by: Rameshkumar Sundaram +Link: https://patch.msgid.link/20260609092528.220547-1-vulab@iscas.ac.cn +Signed-off-by: Jeff Johnson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/ath/ath11k/ahb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -996,6 +996,7 @@ static int ath11k_ahb_fw_resources_init( + ret = ath11k_ahb_setup_msa_resources(ab); + if (ret) { + ath11k_err(ab, "failed to setup msa resources\n"); ++ of_node_put(node); + return ret; + } + diff --git a/queue-7.1/wifi-ath12k-fix-null-pointer-dereference-in-rhash-table-destroy.patch b/queue-7.1/wifi-ath12k-fix-null-pointer-dereference-in-rhash-table-destroy.patch new file mode 100644 index 0000000000..248218248a --- /dev/null +++ b/queue-7.1/wifi-ath12k-fix-null-pointer-dereference-in-rhash-table-destroy.patch @@ -0,0 +1,92 @@ +From 70231dcd782201579990ded73e0435d18bb524ca Mon Sep 17 00:00:00 2001 +From: Jose Ignacio Tornos Martinez +Date: Mon, 15 Jun 2026 13:21:03 +0200 +Subject: wifi: ath12k: fix NULL pointer dereference in rhash table destroy + +From: Jose Ignacio Tornos Martinez + +commit 70231dcd782201579990ded73e0435d18bb524ca upstream. + +When unbinding the ath12k driver, kernel NULL pointer dereferences +occur in irq_work_sync() called from rhashtable_destroy(). + +Two hash tables are affected: +1. ath12k_link_sta hash table in ath12k_base +2. ath12k_dp_link_peer hash table in ath12k_dp + +The issue happens because the destroy functions are called unconditionally +in cleanup paths, but the hash tables are only initialized late in their +respective init functions. If the device was never fully started or if the +init functions failed before initializing the hash tables, the pointers +will be NULL. The issues are always reproducible from a VM because the MSI +addressing initialization is failing. + +Call trace for ath12k_link_sta_rhash_tbl_destroy: + RIP: irq_work_sync+0x1e/0x70 + rhashtable_destroy+0x12/0x60 + ath12k_link_sta_rhash_tbl_destroy+0x19/0x40 [ath12k] + ath12k_core_stop+0xe/0x80 [ath12k] + ath12k_core_hw_group_cleanup+0x6b/0xb0 [ath12k] + ath12k_pci_remove+0x60/0x110 [ath12k] + +Call trace for ath12k_dp_link_peer_rhash_tbl_destroy: + RIP: irq_work_sync+0x1e/0x70 + rhashtable_destroy+0x12/0x60 + ath12k_dp_link_peer_rhash_tbl_destroy+0x29/0x50 [ath12k] + ath12k_dp_cmn_device_deinit+0x21/0x140 [ath12k] + ath12k_core_hw_group_cleanup+0x6b/0xb0 [ath12k] + ath12k_pci_remove+0x60/0x110 [ath12k] + +Fix this by adding NULL checks before calling rhashtable_destroy() in +both destroy functions. + +The NULL check approach was chosen because the rhashtable pointer +serves as the initialization state indicator. The init can fail at +various points, leaving some components uninitialized. Checking the +pointer directly is simpler than adding separate state flags that +would need synchronization. + +Fixes: 57ccca410237 ("wifi: ath12k: Add hash table for ath12k_link_sta in ath12k_base") +Fixes: a88cf5f71adf ("wifi: ath12k: Add hash table for ath12k_dp_link_peer") +Cc: stable@vger.kernel.org +Signed-off-by: Jose Ignacio Tornos Martinez +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260615112103.601982-1-jtornosm@redhat.com +Signed-off-by: Jeff Johnson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/ath/ath12k/dp_peer.c | 7 +++++-- + drivers/net/wireless/ath/ath12k/peer.c | 3 +++ + 2 files changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath12k/dp_peer.c ++++ b/drivers/net/wireless/ath/ath12k/dp_peer.c +@@ -274,11 +274,14 @@ int ath12k_dp_link_peer_rhash_tbl_init(s + + void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp) + { +- mutex_lock(&dp->link_peer_rhash_tbl_lock); ++ guard(mutex)(&dp->link_peer_rhash_tbl_lock); ++ ++ if (!dp->rhead_peer_addr) ++ return; ++ + rhashtable_destroy(dp->rhead_peer_addr); + kfree(dp->rhead_peer_addr); + dp->rhead_peer_addr = NULL; +- mutex_unlock(&dp->link_peer_rhash_tbl_lock); + } + + static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp, +--- a/drivers/net/wireless/ath/ath12k/peer.c ++++ b/drivers/net/wireless/ath/ath12k/peer.c +@@ -444,6 +444,9 @@ err_free: + + void ath12k_link_sta_rhash_tbl_destroy(struct ath12k_base *ab) + { ++ if (!ab->rhead_sta_addr) ++ return; ++ + rhashtable_destroy(ab->rhead_sta_addr); + kfree(ab->rhead_sta_addr); + ab->rhead_sta_addr = NULL; diff --git a/queue-7.1/wifi-ath6kl-fix-oob-access-from-firmware-addba-window-size.patch b/queue-7.1/wifi-ath6kl-fix-oob-access-from-firmware-addba-window-size.patch new file mode 100644 index 0000000000..9c5f71790a --- /dev/null +++ b/queue-7.1/wifi-ath6kl-fix-oob-access-from-firmware-addba-window-size.patch @@ -0,0 +1,52 @@ +From 44126b6994eeb28f2103b638e698f40a1244f327 Mon Sep 17 00:00:00 2001 +From: Tristan Madani +Date: Thu, 2 Jul 2026 00:50:20 +0000 +Subject: wifi: ath6kl: fix OOB access from firmware ADDBA window size + +From: Tristan Madani + +commit 44126b6994eeb28f2103b638e698f40a1244f327 upstream. + +aggr_recv_addba_req_evt() logs a debug message when the firmware-supplied +win_sz is outside [AGGR_WIN_SZ_MIN, AGGR_WIN_SZ_MAX] but does not +return. The out-of-range win_sz is then used in TID_WINDOW_SZ() to +compute a kzalloc size and stored in rxtid->hold_q_sz, leading to +zero-size or overflowed allocations and subsequent out-of-bounds access. + +Clean up any previously active aggregation session for the TID first, +then return early when win_sz is out of the valid range, instead of +proceeding with a broken allocation size. + +Fixes: bdcd81707973 ("Add ath6kl cleaned up driver") +Cc: stable@vger.kernel.org +Reviewed-by: Vasanthakumar Thiagarajan +Signed-off-by: Tristan Madani +Link: https://patch.msgid.link/20260702005020.708717-1-tristmd@gmail.com +Signed-off-by: Jeff Johnson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/ath/ath6kl/txrx.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath6kl/txrx.c ++++ b/drivers/net/wireless/ath/ath6kl/txrx.c +@@ -1723,13 +1723,15 @@ void aggr_recv_addba_req_evt(struct ath6 + + rxtid = &aggr_conn->rx_tid[tid]; + +- if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) +- ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", +- __func__, win_sz, tid); +- + if (rxtid->aggr) + aggr_delete_tid_state(aggr_conn, tid); + ++ if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) { ++ ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", ++ __func__, win_sz, tid); ++ return; ++ } ++ + rxtid->seq_next = seq_no; + hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); + rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL); diff --git a/queue-7.1/wifi-ath6kl-fix-use-after-free-in-aggr_reset_state.patch b/queue-7.1/wifi-ath6kl-fix-use-after-free-in-aggr_reset_state.patch new file mode 100644 index 0000000000..225bcee3d2 --- /dev/null +++ b/queue-7.1/wifi-ath6kl-fix-use-after-free-in-aggr_reset_state.patch @@ -0,0 +1,46 @@ +From ba7debb4dd6427386862220e8335a53a4bfc235d Mon Sep 17 00:00:00 2001 +From: Daniel Hodges +Date: Fri, 6 Feb 2026 13:52:07 -0500 +Subject: wifi: ath6kl: fix use-after-free in aggr_reset_state() + +From: Daniel Hodges + +commit ba7debb4dd6427386862220e8335a53a4bfc235d upstream. + +The aggr_reset_state() function uses timer_delete() (non-synchronous) +for the aggregation timer before proceeding to delete TID state and +before the structure is freed by callers like aggr_module_destroy(). + +If the timer callback (aggr_timeout) is executing when aggr_reset_state() +is called, the callback will continue to access aggr_conn fields like +rx_tid[] and stat[] which may be freed immediately after by +kfree(aggr_info->aggr_conn) in aggr_module_destroy(). + +Additionally, the timer callback can re-arm itself via mod_timer() while +aggr_reset_state() is running, creating a more complex race condition. + +Use timer_delete_sync() instead to ensure any running timer callback +has completed before returning. + +Fixes: bdcd81707973 ("Add ath6kl cleaned up driver") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Hodges +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260206185207.30098-1-git@danielhodges.dev +Signed-off-by: Jeff Johnson +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/ath/ath6kl/txrx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath6kl/txrx.c ++++ b/drivers/net/wireless/ath/ath6kl/txrx.c +@@ -1830,7 +1830,7 @@ void aggr_reset_state(struct aggr_info_c + return; + + if (aggr_conn->timer_scheduled) { +- timer_delete(&aggr_conn->timer); ++ timer_delete_sync(&aggr_conn->timer); + aggr_conn->timer_scheduled = false; + } + diff --git a/queue-7.1/wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch b/queue-7.1/wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch new file mode 100644 index 0000000000..c429249725 --- /dev/null +++ b/queue-7.1/wifi-brcmfmac-drain-bus_reset-work-on-device-removal.patch @@ -0,0 +1,288 @@ +From 43b25879f004c98defa2776bedc6ca4763c51945 Mon Sep 17 00:00:00 2001 +From: Fan Wu +Date: Sat, 18 Jul 2026 02:43:53 +0000 +Subject: wifi: brcmfmac: drain bus_reset work on device removal + +From: Fan Wu + +commit 43b25879f004c98defa2776bedc6ca4763c51945 upstream. + +brcmf_fw_crashed() and the debugfs "reset" entry both schedule +drvr->bus_reset, whose callback recovers drvr through container_of() +and dereferences it. The removal path frees drvr (brcmf_free -> +wiphy_free) without draining the work, so a bus_reset callback pending +or running during removal can outlive drvr. + +Cancellation cannot live in brcmf_detach() or brcmf_free(): the work +callback reaches teardown through the bus .reset op (PCIe +brcmf_pcie_reset -> brcmf_detach; SDIO brcmf_sdio_bus_reset -> +brcmf_sdiod_remove -> brcmf_free), so cancelling there would wait for +the running work and deadlock. + +Add a per-bus mutex (bus_reset_lock) and route all arming through +brcmf_bus_schedule_reset(), which under the lock skips when the bus is +marked removing. Each bus remove entry calls +brcmf_bus_cancel_reset_work(), which under the same lock sets removing +and cancels the work. Holding the mutex across cancel_work_sync() makes +the set-removing + drain step atomic. Every producer reaches the arming +path from process context -- the PCIe firmware-halt notification runs in +the threaded IRQ handler (brcmf_pcie_isr_thread) and the SDIO hostmail +path runs from the data workqueue -- so the mutex is taken only in +sleepable contexts. Where applicable the remove entry first stops the +firmware-crash producer: on PCIe mask the mailbox and synchronize_irq; +on SDIO unregister the bus interrupt and cancel the data worker, which +also reports firmware halts through brcmf_fw_crashed(). The mutex is +initialized at bus allocation. The SDIO suspend power-off path frees +drvr through the same brcmf_sdiod_remove() and takes the same lock; +resume re-allows the work only on a successful re-probe. + +Also guard brcmf_fw_crashed() against a NULL bus_if/drvr: it can fire +before brcmf_attach() wires up drvr, and it dereferences drvr +(bphy_err/brcmf_dev_coredump) before reaching the arming gate. + +The bus_reset work is shared across buses, so the drain is applied to +every remove path: PCIe (the .reset op introduced by the Fixes commit), +SDIO (arms the same work through brcmf_fw_crashed()), and USB (via the +debugfs "reset" entry). cancel_work_sync() drains a running or pending +bus_reset work item before removal frees drvr, and patch 1/2 makes the +scratch-buffer release safe when reset teardown has already released +those DMA buffers. + +This patch fixes the lifetime of the bus_reset work item itself. It does +not attempt to address the separate, pre-existing lifetime of the +asynchronous firmware completion started by the PCIe reset path. That +callback needs its own lifetime/ownership protocol and is being tracked +separately. + +This issue was found by an in-house static analysis tool. + +Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash") +Cc: stable@vger.kernel.org +Signed-off-by: Fan Wu +Assisted-by: Codex:gpt-5.6 +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260718024353.3147201-3-fanwu01@zju.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 13 +++ + drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 6 + + drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 46 ++++++++++++-- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 6 + + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 6 + + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | 1 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 3 + 7 files changed, 77 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -1069,6 +1069,7 @@ static int brcmf_ops_sdio_probe(struct s + bus_if = kzalloc_obj(*bus_if); + if (!bus_if) + return -ENOMEM; ++ mutex_init(&bus_if->bus_reset_lock); + sdiodev = kzalloc_obj(*sdiodev); + if (!sdiodev) { + kfree(bus_if); +@@ -1130,6 +1131,14 @@ static void brcmf_ops_sdio_remove(struct + if (func->num != 1) + return; + ++ /* Drain bus_reset before the shared brcmf_sdiod_remove() ++ * teardown, which the SDIO reset callback also reaches. The ++ * data worker can arm bus_reset via brcmf_fw_crashed(); cancel ++ * it first. ++ */ ++ brcmf_sdio_cancel_datawork(sdiodev->bus); ++ brcmf_bus_cancel_reset_work(bus_if); ++ + /* only proceed with rest of cleanup if func 1 */ + brcmf_sdiod_remove(sdiodev); + +@@ -1204,6 +1213,8 @@ static int brcmf_ops_sdio_suspend(struct + } else { + /* power will be cut so remove device, probe again in resume */ + brcmf_sdiod_intr_unregister(sdiodev); ++ brcmf_sdio_cancel_datawork(sdiodev->bus); ++ brcmf_bus_cancel_reset_work(bus_if); + ret = brcmf_sdiod_remove(sdiodev); + if (ret) + brcmf_err("Failed to remove device on suspend\n"); +@@ -1229,6 +1240,8 @@ static int brcmf_ops_sdio_resume(struct + ret = brcmf_sdiod_probe(sdiodev); + if (ret) + brcmf_err("Failed to probe device on resume\n"); ++ else ++ brcmf_bus_allow_reset_work(bus_if); + } else { + if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported) + disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include "debug.h" + + /* IDs of the 6 default common rings of msgbuf protocol */ +@@ -179,6 +180,8 @@ struct brcmf_bus { + enum brcmf_fwvendor fwvid; + bool always_use_fws_queue; + bool wowl_supported; ++ bool removing; /* device removal in progress; quiesce async work */ ++ struct mutex bus_reset_lock; + + const struct brcmf_bus_ops *ops; + struct brcmf_bus_msgbuf *msgbuf; +@@ -186,6 +189,9 @@ struct brcmf_bus { + struct list_head list; + }; + ++void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if); ++void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if); ++ + /* + * callback wrappers + */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1167,6 +1167,35 @@ static int brcmf_revinfo_read(struct seq + return 0; + } + ++/* ++ * Serialize arming from debugfs reset and brcmf_fw_crashed() against ++ * teardown. The remove path sets ->removing and drains the work while ++ * holding bus_reset_lock, so a racing armer is either drained or skips it. ++ */ ++static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if) ++{ ++ mutex_lock(&bus_if->bus_reset_lock); ++ if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing) ++ schedule_work(&bus_if->drvr->bus_reset); ++ mutex_unlock(&bus_if->bus_reset_lock); ++} ++ ++void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if) ++{ ++ mutex_lock(&bus_if->bus_reset_lock); ++ bus_if->removing = true; ++ if (bus_if->drvr) ++ cancel_work_sync(&bus_if->drvr->bus_reset); ++ mutex_unlock(&bus_if->bus_reset_lock); ++} ++ ++void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if) ++{ ++ mutex_lock(&bus_if->bus_reset_lock); ++ bus_if->removing = false; ++ mutex_unlock(&bus_if->bus_reset_lock); ++} ++ + static void brcmf_core_bus_reset(struct work_struct *work) + { + struct brcmf_pub *drvr = container_of(work, struct brcmf_pub, +@@ -1187,7 +1216,7 @@ static ssize_t bus_reset_write(struct fi + if (value != 1) + return -EINVAL; + +- schedule_work(&drvr->bus_reset); ++ brcmf_bus_schedule_reset(drvr->bus_if); + + return count; + } +@@ -1417,14 +1446,23 @@ void brcmf_dev_coredump(struct device *d + void brcmf_fw_crashed(struct device *dev) + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); +- struct brcmf_pub *drvr = bus_if->drvr; ++ struct brcmf_pub *drvr; ++ ++ /* May fire before brcmf_attach() wires up drvr, or after removal ++ * has cleared it; guard the derefs below (and the arming gate in ++ * brcmf_bus_schedule_reset() already checks drvr/->removing). ++ */ ++ if (!bus_if) ++ return; ++ drvr = bus_if->drvr; ++ if (!drvr) ++ return; + + bphy_err(drvr, "Firmware has halted or crashed\n"); + + brcmf_dev_coredump(dev); + +- if (drvr->bus_reset.func) +- schedule_work(&drvr->bus_reset); ++ brcmf_bus_schedule_reset(bus_if); + } + + void brcmf_detach(struct device *dev) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -2499,6 +2499,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, c + ret = -ENOMEM; + goto fail; + } ++ mutex_init(&bus->bus_reset_lock); + bus->msgbuf = kzalloc_obj(*bus->msgbuf); + if (!bus->msgbuf) { + ret = -ENOMEM; +@@ -2594,6 +2595,11 @@ brcmf_pcie_remove(struct pci_dev *pdev) + if (devinfo->ci) + brcmf_pcie_intr_disable(devinfo); + ++ if (devinfo->irq_allocated) ++ synchronize_irq(pdev->irq); ++ ++ brcmf_bus_cancel_reset_work(bus); ++ + brcmf_detach(&pdev->dev); + brcmf_free(&pdev->dev); + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -4560,6 +4560,12 @@ fail: + return ret; + } + ++void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus) ++{ ++ if (bus) ++ cancel_work_sync(&bus->datawork); ++} ++ + /* Detach and free everything */ + void brcmf_sdio_remove(struct brcmf_sdio *bus) + { +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -361,6 +361,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio + int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); + void brcmf_sdio_remove(struct brcmf_sdio *bus); + void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr); ++void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus); + + void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active); + void brcmf_sdio_wowl_config(struct device *dev, bool enabled); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -1260,6 +1260,7 @@ static int brcmf_usb_probe_cb(struct brc + ret = -ENOMEM; + goto fail; + } ++ mutex_init(&bus->bus_reset_lock); + + bus->dev = dev; + bus_pub->bus = bus; +@@ -1329,6 +1330,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usb + return; + brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo); + ++ brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus); ++ + brcmf_detach(devinfo->dev); + brcmf_free(devinfo->dev); + kfree(devinfo->bus_pub.bus); diff --git a/queue-7.1/wifi-brcmfmac-make-release_scratchbuffers-idempotent.patch b/queue-7.1/wifi-brcmfmac-make-release_scratchbuffers-idempotent.patch new file mode 100644 index 0000000000..dbd7763271 --- /dev/null +++ b/queue-7.1/wifi-brcmfmac-make-release_scratchbuffers-idempotent.patch @@ -0,0 +1,63 @@ +From 538c51e9d124cf656f2dd0c0394a8545efc7102d Mon Sep 17 00:00:00 2001 +From: Fan Wu +Date: Sat, 18 Jul 2026 02:43:52 +0000 +Subject: wifi: brcmfmac: make release_scratchbuffers idempotent + +From: Fan Wu + +commit 538c51e9d124cf656f2dd0c0394a8545efc7102d upstream. + +brcmf_pcie_release_scratchbuffers() frees the shared.scratch and +shared.ringupd DMA buffers with dma_free_coherent() but does not clear +the pointers afterwards, unlike the sibling release_ringbuffers() which +NULLs commonrings/flowrings/idxbuf on release. + +Both the bus_reset .reset callback (brcmf_pcie_reset) and +brcmf_pcie_remove() call release_scratchbuffers. When reset teardown +has run before removal, remove's own teardown would call +dma_free_coherent() a second time on the already-freed DMA allocation. + +NULL the pointers after free, matching release_ringbuffers(), so a later +release observes that the allocation has already been released. This +patch makes repeated sequential release safe; the reset-work lifetime is +handled separately by the following patch. + +This issue was found by an in-house static analysis tool. + +Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash") +Cc: stable@vger.kernel.org +Signed-off-by: Fan Wu +Assisted-by: Codex:gpt-5.6 +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260718024353.3147201-2-fanwu01@zju.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1383,16 +1383,20 @@ fail: + static void + brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo) + { +- if (devinfo->shared.scratch) ++ if (devinfo->shared.scratch) { + dma_free_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_SCRATCH_BUF_LEN, + devinfo->shared.scratch, + devinfo->shared.scratch_dmahandle); +- if (devinfo->shared.ringupd) ++ devinfo->shared.scratch = NULL; ++ } ++ if (devinfo->shared.ringupd) { + dma_free_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_RINGUPD_BUF_LEN, + devinfo->shared.ringupd, + devinfo->shared.ringupd_dmahandle); ++ devinfo->shared.ringupd = NULL; ++ } + } + + static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) diff --git a/queue-7.1/wifi-brcmfmac-set-f2-blocksize-to-256-for-bcm43752.patch b/queue-7.1/wifi-brcmfmac-set-f2-blocksize-to-256-for-bcm43752.patch new file mode 100644 index 0000000000..dfd15feffe --- /dev/null +++ b/queue-7.1/wifi-brcmfmac-set-f2-blocksize-to-256-for-bcm43752.patch @@ -0,0 +1,55 @@ +From 29ab31f3f27157648f2f7e6d5e1fd9792fdf0614 Mon Sep 17 00:00:00 2001 +From: LiangCheng Wang +Date: Wed, 15 Jul 2026 14:49:38 +0800 +Subject: wifi: brcmfmac: set F2 blocksize to 256 for BCM43752 + +From: LiangCheng Wang + +commit 29ab31f3f27157648f2f7e6d5e1fd9792fdf0614 upstream. + +The BCM43752 is not reliable with the default 512-byte SDIO function 2 +block size: on an i.MX8MP board with an AMPAK AP6275S module at +SDR104 / 200 MHz, an iperf TX stress test kills WLAN within seconds: + + mmc_submit_one: CMD53 sg block write failed -84 + brcmf_sdio_dpc: failed backplane access over SDIO, halting operation + +Commit d2587c57ffd8 ("brcmfmac: add 43752 SDIO ids and initialization") +set up the 43752 like the 4373 for the F2 watermark but missed the F2 +block size, which the 4373 limits to 256 bytes. The vendor driver +(bcmdhd) also programs a 256-byte F2 block size for this chip and runs +the same hardware without errors. + +Group the 43752 with the 4373, matching the F2 watermark handling. +With this change a 10-minute bidirectional iperf3 soak completes with +zero SDIO errors at ~270 Mbit/s in each direction. + +Backporting note: kernels before v6.18 name this id +SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, so on those trees the case +label added by this patch must be adjusted to that name. Cherry-picking +the rename commit 74e2ef72bd4b ("wifi: brcmfmac: fix 43752 SDIO FWVID +incorrectly labelled as Cypress (CYW)") first is not a clean +alternative: on trees before v6.17 its context collides with the 43751 +additions, and trees before v6.2 lack the FWVID framework it touches. + +Fixes: d2587c57ffd8 ("brcmfmac: add 43752 SDIO ids and initialization") +Cc: stable@vger.kernel.org # see patch description, needs adjustments for <= 6.17 +Signed-off-by: LiangCheng Wang +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260715-b43752-f2-blksz-v2-1-f9be49856050@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -911,6 +911,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_ + return ret; + } + switch (sdiodev->func2->device) { ++ case SDIO_DEVICE_ID_BROADCOM_43752: + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: + f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE; + break; diff --git a/queue-7.1/wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch b/queue-7.1/wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch new file mode 100644 index 0000000000..0daa30e827 --- /dev/null +++ b/queue-7.1/wifi-mt76-mt7615-drop-txrx_notify-on-non-mmio-buses.patch @@ -0,0 +1,53 @@ +From 39afc46c0243d10b7795e6e6cf4ae91f41732120 Mon Sep 17 00:00:00 2001 +From: Devin Wittmayer +Date: Sat, 27 Jun 2026 12:13:36 -0700 +Subject: wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses + +From: Devin Wittmayer + +commit 39afc46c0243d10b7795e6e6cf4ae91f41732120 upstream. + +PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7615_rx_check() and +mt7615_queue_rx_skb() dispatch it to mt7615_mac_tx_free() on every bus. +mt7615_mac_tx_free() cleans the DMA tx queues with +mt76_queue_tx_cleanup(), which calls queue_ops->tx_cleanup(). Only the +mmio queue ops implement that callback; on the mt7663 USB and SDIO +buses it is NULL, so a TXRX_NOTIFY there calls a NULL pointer in the RX +worker. Same defect as the mt7921 and mt7925 patches in this series. + +Drop the event on non-mmio buses via mt76_is_mmio(), as in +commit 5683e1488aa9 ("wifi: mt76: connac: do not check WED status for +non-mmio devices"). + +Fixes: eb99cc95c3b6 ("mt76: mt7615: introduce mt7663u support") +Cc: stable@vger.kernel.org +Signed-off-by: Devin Wittmayer +Link: https://patch.msgid.link/20260627191336.20223-4-lucid_duck@justthetip.ca +Signed-off-by: Felix Fietkau +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -1601,6 +1601,8 @@ bool mt7615_rx_check(struct mt76_dev *md + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: ++ if (!mt76_is_mmio(mdev)) ++ return false; + mt7615_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: +@@ -1634,6 +1636,10 @@ void mt7615_queue_rx_skb(struct mt76_dev + dev_kfree_skb(skb); + break; + case PKT_TYPE_TXRX_NOTIFY: ++ if (!mt76_is_mmio(mdev)) { ++ dev_kfree_skb(skb); ++ break; ++ } + mt7615_mac_tx_free(dev, skb->data, skb->len); + dev_kfree_skb(skb); + break; diff --git a/queue-7.1/wifi-mt76-mt7921-drop-txrx_notify-on-non-mmio-buses.patch b/queue-7.1/wifi-mt76-mt7921-drop-txrx_notify-on-non-mmio-buses.patch new file mode 100644 index 0000000000..995731b9cc --- /dev/null +++ b/queue-7.1/wifi-mt76-mt7921-drop-txrx_notify-on-non-mmio-buses.patch @@ -0,0 +1,63 @@ +From da4082e91acabc1498611ed8ccc53f0610baefc6 Mon Sep 17 00:00:00 2001 +From: Devin Wittmayer +Date: Sat, 27 Jun 2026 12:13:34 -0700 +Subject: wifi: mt76: mt7921: drop TXRX_NOTIFY on non-mmio buses + +From: Devin Wittmayer + +commit da4082e91acabc1498611ed8ccc53f0610baefc6 upstream. + +PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7921_rx_check() and +mt7921_queue_rx_skb() dispatch it to mt7921_mac_tx_free() on every bus. +mt7921_mac_tx_free() cleans the DMA tx queues with +mt76_queue_tx_cleanup(), which calls queue_ops->tx_cleanup(). Only the +mmio queue ops implement that callback; on USB and SDIO it is NULL, so +a TXRX_NOTIFY there calls a NULL pointer in the RX worker: + + BUG: kernel NULL pointer dereference, address: 0000000000000000 + RIP: 0010:0x0 + Call Trace: + mt7921_mac_tx_free+0x64/0x310 [mt7921_common] + mt7921_rx_check+0x5f/0xf0 [mt7921_common] + mt76u_rx_worker+0x1b9/0x620 [mt76_usb] + +Drop the event on non-mmio buses via mt76_is_mmio(), as in +commit 5683e1488aa9 ("wifi: mt76: connac: do not check WED status for +non-mmio devices"). + +Fixes: 48fab5bbef40 ("mt76: mt7921: introduce mt7921s support") +Cc: stable@vger.kernel.org +Signed-off-by: Devin Wittmayer +Link: https://patch.msgid.link/20260627191336.20223-2-lucid_duck@justthetip.ca +Signed-off-by: Felix Fietkau +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +@@ -569,8 +569,9 @@ bool mt7921_rx_check(struct mt76_dev *md + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ +- mt7921_mac_tx_free(dev, data, len); /* mmio */ ++ if (!mt76_is_mmio(mdev)) ++ return false; ++ mt7921_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: + for (rxd += 2; rxd + 8 <= end; rxd += 8) +@@ -599,7 +600,10 @@ void mt7921_queue_rx_skb(struct mt76_dev + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ ++ if (!mt76_is_mmio(mdev)) { ++ napi_consume_skb(skb, 1); ++ break; ++ } + mt7921_mac_tx_free(dev, skb->data, skb->len); + napi_consume_skb(skb, 1); + break; diff --git a/queue-7.1/wifi-mt76-mt7925-drop-txrx_notify-on-non-mmio-buses.patch b/queue-7.1/wifi-mt76-mt7925-drop-txrx_notify-on-non-mmio-buses.patch new file mode 100644 index 0000000000..67792c632c --- /dev/null +++ b/queue-7.1/wifi-mt76-mt7925-drop-txrx_notify-on-non-mmio-buses.patch @@ -0,0 +1,63 @@ +From feeff151c83e7f0ffcdedcad5343852d23d1f6e1 Mon Sep 17 00:00:00 2001 +From: Devin Wittmayer +Date: Sat, 27 Jun 2026 12:13:35 -0700 +Subject: wifi: mt76: mt7925: drop TXRX_NOTIFY on non-mmio buses + +From: Devin Wittmayer + +commit feeff151c83e7f0ffcdedcad5343852d23d1f6e1 upstream. + +PKT_TYPE_TXRX_NOTIFY is an mmio-only event, but mt7925_rx_check() and +mt7925_queue_rx_skb() dispatch it to mt7925_mac_tx_free() on every bus. +mt7925_mac_tx_free() cleans the DMA tx queues with +mt76_queue_tx_cleanup(), which calls queue_ops->tx_cleanup(). Only the +mmio queue ops implement that callback; on USB it is NULL, so a +TXRX_NOTIFY there calls a NULL pointer in the RX worker: + + BUG: kernel NULL pointer dereference, address: 0000000000000000 + RIP: 0010:0x0 + Call Trace: + mt7925_mac_tx_free+0x58/0x350 [mt7925_common] + mt7925_rx_check+0xe2/0x130 [mt7925_common] + mt76u_rx_worker+0x1b9/0x620 [mt76_usb] + +Drop the event on non-mmio buses via mt76_is_mmio(), as in +commit 5683e1488aa9 ("wifi: mt76: connac: do not check WED status for +non-mmio devices"). + +Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") +Cc: stable@vger.kernel.org +Signed-off-by: Devin Wittmayer +Link: https://patch.msgid.link/20260627191336.20223-3-lucid_duck@justthetip.ca +Signed-off-by: Felix Fietkau +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -1194,8 +1194,9 @@ bool mt7925_rx_check(struct mt76_dev *md + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ +- mt7925_mac_tx_free(dev, data, len); /* mmio */ ++ if (!mt76_is_mmio(mdev)) ++ return false; ++ mt7925_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: + for (rxd += 4; rxd + 12 <= end; rxd += 12) +@@ -1231,7 +1232,10 @@ void mt7925_queue_rx_skb(struct mt76_dev + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ ++ if (!mt76_is_mmio(mdev)) { ++ napi_consume_skb(skb, 1); ++ break; ++ } + mt7925_mac_tx_free(dev, skb->data, skb->len); + napi_consume_skb(skb, 1); + break; diff --git a/queue-7.1/wifi-mt76-restrict-npu-ppe-active-checks-to-mmio-devices.patch b/queue-7.1/wifi-mt76-restrict-npu-ppe-active-checks-to-mmio-devices.patch new file mode 100644 index 0000000000..2103887c14 --- /dev/null +++ b/queue-7.1/wifi-mt76-restrict-npu-ppe-active-checks-to-mmio-devices.patch @@ -0,0 +1,51 @@ +From 7981aca2bd28a1f7ad7eeab89715442a95b1f72e Mon Sep 17 00:00:00 2001 +From: Devin Wittmayer +Date: Mon, 20 Jul 2026 16:27:36 -0700 +Subject: wifi: mt76: restrict NPU/PPE active checks to MMIO devices + +From: Devin Wittmayer + +commit 7981aca2bd28a1f7ad7eeab89715442a95b1f72e upstream. + +mt76_npu_device_active() and mt76_ppe_device_active() read dev->mmio.npu +and dev->mmio.ppe_dev. The mmio, usb and sdio bus structs share a union in +struct mt76_dev, so on USB and SDIO these read unrelated data from the +usb/sdio struct, which is non-NULL in practice. + +mt76_npu_device_active() then returns true on USB, and +mt76_rx_poll_complete() takes the offload path and skips +mt76_rx_aggr_reorder(). RX A-MPDU subframes are delivered out of order and +the peer's TCP stack treats that as loss: heavy retransmissions and reduced +throughput in AP mode. Seen on mt7921u, mt7925u, mt76x2u and mt76x0u. + +Gate both helpers on mt76_is_mmio() so they only run for the bus type that +owns the mmio union member. + +Fixes: 7fb554b1b623 ("wifi: mt76: Introduce the NPU generic layer") +Cc: stable@vger.kernel.org +Tested-by: Nick Morrow +Signed-off-by: Devin Wittmayer +Link: https://patch.msgid.link/20260720232640.41293-1-lucid_duck@justthetip.ca +Signed-off-by: Felix Fietkau +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -1735,12 +1735,12 @@ static inline int mt76_npu_send_txrx_add + + static inline bool mt76_npu_device_active(struct mt76_dev *dev) + { +- return !!rcu_access_pointer(dev->mmio.npu); ++ return mt76_is_mmio(dev) && !!rcu_access_pointer(dev->mmio.npu); + } + + static inline bool mt76_ppe_device_active(struct mt76_dev *dev) + { +- return !!rcu_access_pointer(dev->mmio.ppe_dev); ++ return mt76_is_mmio(dev) && !!rcu_access_pointer(dev->mmio.ppe_dev); + } + + static inline int mt76_npu_send_msg(struct airoha_npu *npu, int ifindex, diff --git a/queue-7.1/wifi-mwifiex-fix-null-dereference-when-the-ap-has-ht-cap-but-no-ht-oper.patch b/queue-7.1/wifi-mwifiex-fix-null-dereference-when-the-ap-has-ht-cap-but-no-ht-oper.patch new file mode 100644 index 0000000000..4c847ab74f --- /dev/null +++ b/queue-7.1/wifi-mwifiex-fix-null-dereference-when-the-ap-has-ht-cap-but-no-ht-oper.patch @@ -0,0 +1,52 @@ +From c3d68e294cbb6a4090bb219d3dcaca85a011809b Mon Sep 17 00:00:00 2001 +From: Doruk Tan Ozturk +Date: Thu, 16 Jul 2026 12:30:42 +0200 +Subject: wifi: mwifiex: fix NULL dereference when the AP has HT-cap but no HT-oper + +From: Doruk Tan Ozturk + +commit c3d68e294cbb6a4090bb219d3dcaca85a011809b upstream. + +mwifiex_tdls_add_ht_oper() gates its follow-the-AP-bandwidth path on +bss_desc->bcn_ht_cap being present, but then dereferences a different +pointer, bss_desc->bcn_ht_oper: + + if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && + bss_desc->bcn_ht_cap && + ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param)) + +bcn_ht_cap and bcn_ht_oper are populated independently while parsing the +associated AP's beacon in mwifiex_update_bss_desc_with_ie(): an AP that +advertises an HT Capabilities element but no HT Operation element leaves +bcn_ht_cap non-NULL and bcn_ht_oper NULL. Setting up a TDLS link to a +peer while associated to such an AP then dereferences the NULL +bcn_ht_oper and crashes the kernel. Every other bcn_ht_oper user in the +driver NULL-checks it first. + +Guard on the pointer that is actually dereferenced. + +Found by 0sec automated security-research tooling (https://0sec.ai). + +Fixes: 396939f94084 ("mwifiex: add HT operation IE in TDLS setup confirm") +Cc: stable@vger.kernel.org +Assisted-by: 0sec:multi-model +Signed-off-by: Doruk Tan Ozturk +Reviewed-by: Francesco Dolcini +Link: https://patch.msgid.link/20260716103042.88469-1-doruk@0sec.ai +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/marvell/mwifiex/tdls.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/marvell/mwifiex/tdls.c ++++ b/drivers/net/wireless/marvell/mwifiex/tdls.c +@@ -215,7 +215,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_ + + /* follow AP's channel bandwidth */ + if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && +- bss_desc->bcn_ht_cap && ++ bss_desc->bcn_ht_oper && + ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param)) + ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param; + diff --git a/queue-7.1/wifi-wilc1000-validate-assoc-response-length-before-subtracting-header.patch b/queue-7.1/wifi-wilc1000-validate-assoc-response-length-before-subtracting-header.patch new file mode 100644 index 0000000000..9dd8c85acd --- /dev/null +++ b/queue-7.1/wifi-wilc1000-validate-assoc-response-length-before-subtracting-header.patch @@ -0,0 +1,58 @@ +From 4c4c97b60a5e978121d9ee8cb0ab3916e5d6a8de Mon Sep 17 00:00:00 2001 +From: Huihui Huang +Date: Tue, 14 Jul 2026 17:17:58 +0800 +Subject: wifi: wilc1000: validate assoc response length before subtracting header + +From: Huihui Huang + +commit 4c4c97b60a5e978121d9ee8cb0ab3916e5d6a8de upstream. + +wilc_parse_assoc_resp_info() computes the trailing IE length as + + ies_len = buffer_len - sizeof(*res); + +without first checking that buffer_len is at least sizeof(struct +wilc_assoc_resp) (6 bytes). buffer_len is the length reported for a +received association response (host_int_parse_assoc_resp_info() passes +hif_drv->assoc_resp / assoc_resp_info_len straight in) and must be +validated before the driver accesses the fixed header. + +For a frame shorter than the 6-byte fixed header, the subtraction wraps. +For a four-byte response the result is truncated to a u16 ies_len of +65534, so kmemdup() then attempts to copy 65534 bytes starting at +buffer + sizeof(*res), beyond the valid association-response data +(CWE-125). A response shorter than four bytes can also cause an +out-of-bounds read of res->status_code at offsets 2 and 3. + +Reject frames too short to hold the fixed header before touching the +header or computing ies_len. Also set the connection status to a failure +on this path: the caller falls through to a +"conn_info->status == WLAN_STATUS_SUCCESS" check after the parser +returns, so leaving the status untouched could let a malformed short +response be treated as a successful association. + +Fixes: c5c77ba18ea6 ("staging: wilc1000: Add SDIO/SPI 802.11 driver") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Huihui Huang +Link: https://patch.msgid.link/20260714091811.3596126-1-hhhuang@smu.edu.sg +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/microchip/wilc1000/hif.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/net/wireless/microchip/wilc1000/hif.c ++++ b/drivers/net/wireless/microchip/wilc1000/hif.c +@@ -600,6 +600,11 @@ static s32 wilc_parse_assoc_resp_info(u8 + u16 ies_len; + struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer; + ++ if (buffer_len < sizeof(*res)) { ++ ret_conn_info->status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ return -EINVAL; ++ } ++ + ret_conn_info->status = le16_to_cpu(res->status_code); + if (ret_conn_info->status == WLAN_STATUS_SUCCESS) { + ies = &buffer[sizeof(*res)];