]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 4 Jun 2026 11:02:05 +0000 (13:02 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 4 Jun 2026 11:02:05 +0000 (13:02 +0200)
added patches:
comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch
comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch
counter-fix-refcount-leak-in-counter_alloc-error-path.patch
drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch
drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch
drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch
drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch
drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch
drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch
drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch
drm-gem-fix-race-between-change_handle-and-handle_delete.patch
drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch
drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch
drm-i915-fix-potential-uaf-in-ttm-object-purge.patch
drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch
gpib-cb7210-fix-region-leak-when-request_irq-fails.patch
input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch
input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch
input-xpad-add-nova-2-lite-from-gamesir.patch
input-xpad-add-support-for-asus-rog-raikiri-ii.patch
ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch
misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch
scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch
scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch
scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch
serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch
serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch
serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch
serial-dz-convert-to-use-a-platform-device.patch
serial-dz-fix-bootconsole-handover-lockup.patch
serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch
serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch
serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch
serial-sh-sci-fix-memory-region-release-in-error-path.patch
serial-zs-convert-to-use-a-platform-device.patch
serial-zs-fix-bootconsole-handover-lockup.patch
serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch
serial-zs-switch-to-using-channel-reset.patch
thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch
thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch
tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch
tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch
usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch
usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch
usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch
usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch
usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch
usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch
usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch
usb-gadget-net2280-fix-double-free-in-probe-error-path.patch
usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch
usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch
usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch
usb-serial-belkin_sa-validate-interrupt-status-length.patch
usb-serial-cypress_m8-validate-interrupt-packet-headers.patch
usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch
usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch
usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch
usb-serial-option-add-meig-srm813q.patch
usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch
usb-storage-add-quirks-for-pny-elite-portable-ssd.patch
usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch
usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch
usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch
usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch
usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch
usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch

73 files changed:
queue-6.18/comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch [new file with mode: 0644]
queue-6.18/comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch [new file with mode: 0644]
queue-6.18/counter-fix-refcount-leak-in-counter_alloc-error-path.patch [new file with mode: 0644]
queue-6.18/drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch [new file with mode: 0644]
queue-6.18/drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch [new file with mode: 0644]
queue-6.18/drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch [new file with mode: 0644]
queue-6.18/drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch [new file with mode: 0644]
queue-6.18/drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch [new file with mode: 0644]
queue-6.18/drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch [new file with mode: 0644]
queue-6.18/drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch [new file with mode: 0644]
queue-6.18/drm-gem-fix-race-between-change_handle-and-handle_delete.patch [new file with mode: 0644]
queue-6.18/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch [new file with mode: 0644]
queue-6.18/drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch [new file with mode: 0644]
queue-6.18/drm-i915-fix-potential-uaf-in-ttm-object-purge.patch [new file with mode: 0644]
queue-6.18/drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch [new file with mode: 0644]
queue-6.18/gpib-cb7210-fix-region-leak-when-request_irq-fails.patch [new file with mode: 0644]
queue-6.18/input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch [new file with mode: 0644]
queue-6.18/input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch [new file with mode: 0644]
queue-6.18/input-xpad-add-nova-2-lite-from-gamesir.patch [new file with mode: 0644]
queue-6.18/input-xpad-add-support-for-asus-rog-raikiri-ii.patch [new file with mode: 0644]
queue-6.18/ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch [new file with mode: 0644]
queue-6.18/misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch [new file with mode: 0644]
queue-6.18/scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch [new file with mode: 0644]
queue-6.18/scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch [new file with mode: 0644]
queue-6.18/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch [new file with mode: 0644]
queue-6.18/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch [new file with mode: 0644]
queue-6.18/scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch [new file with mode: 0644]
queue-6.18/serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch [new file with mode: 0644]
queue-6.18/serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch [new file with mode: 0644]
queue-6.18/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch [new file with mode: 0644]
queue-6.18/serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch [new file with mode: 0644]
queue-6.18/serial-dz-convert-to-use-a-platform-device.patch [new file with mode: 0644]
queue-6.18/serial-dz-fix-bootconsole-handover-lockup.patch [new file with mode: 0644]
queue-6.18/serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch [new file with mode: 0644]
queue-6.18/serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch [new file with mode: 0644]
queue-6.18/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch [new file with mode: 0644]
queue-6.18/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch [new file with mode: 0644]
queue-6.18/serial-sh-sci-fix-memory-region-release-in-error-path.patch [new file with mode: 0644]
queue-6.18/serial-zs-convert-to-use-a-platform-device.patch [new file with mode: 0644]
queue-6.18/serial-zs-fix-bootconsole-handover-lockup.patch [new file with mode: 0644]
queue-6.18/serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch [new file with mode: 0644]
queue-6.18/serial-zs-switch-to-using-channel-reset.patch [new file with mode: 0644]
queue-6.18/series
queue-6.18/thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch [new file with mode: 0644]
queue-6.18/thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch [new file with mode: 0644]
queue-6.18/tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch [new file with mode: 0644]
queue-6.18/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch [new file with mode: 0644]
queue-6.18/usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch [new file with mode: 0644]
queue-6.18/usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch [new file with mode: 0644]
queue-6.18/usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch [new file with mode: 0644]
queue-6.18/usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch [new file with mode: 0644]
queue-6.18/usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch [new file with mode: 0644]
queue-6.18/usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch [new file with mode: 0644]
queue-6.18/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch [new file with mode: 0644]
queue-6.18/usb-gadget-net2280-fix-double-free-in-probe-error-path.patch [new file with mode: 0644]
queue-6.18/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch [new file with mode: 0644]
queue-6.18/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch [new file with mode: 0644]
queue-6.18/usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch [new file with mode: 0644]
queue-6.18/usb-serial-belkin_sa-validate-interrupt-status-length.patch [new file with mode: 0644]
queue-6.18/usb-serial-cypress_m8-validate-interrupt-packet-headers.patch [new file with mode: 0644]
queue-6.18/usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch [new file with mode: 0644]
queue-6.18/usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch [new file with mode: 0644]
queue-6.18/usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch [new file with mode: 0644]
queue-6.18/usb-serial-option-add-meig-srm813q.patch [new file with mode: 0644]
queue-6.18/usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch [new file with mode: 0644]
queue-6.18/usb-storage-add-quirks-for-pny-elite-portable-ssd.patch [new file with mode: 0644]
queue-6.18/usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch [new file with mode: 0644]
queue-6.18/usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch [new file with mode: 0644]
queue-6.18/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch [new file with mode: 0644]
queue-6.18/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch [new file with mode: 0644]
queue-6.18/usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch [new file with mode: 0644]
queue-6.18/usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch [new file with mode: 0644]
queue-6.18/usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch [new file with mode: 0644]

diff --git a/queue-6.18/comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch b/queue-6.18/comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch
new file mode 100644 (file)
index 0000000..19eb8ef
--- /dev/null
@@ -0,0 +1,37 @@
+From 542f5248cb481073203e0dadab5bcbd28aeae308 Mon Sep 17 00:00:00 2001
+From: Ian Abbott <abbotti@mev.co.uk>
+Date: Wed, 22 Apr 2026 17:21:19 +0100
+Subject: comedi: comedi_test: fix check for valid scan_begin_src in waveform_ai_cmdtest()
+
+From: Ian Abbott <abbotti@mev.co.uk>
+
+commit 542f5248cb481073203e0dadab5bcbd28aeae308 upstream.
+
+Commit 783ddaebd397 ("staging: comedi: comedi_test: support
+scan_begin_src == TRIG_FOLLOW") neglected to add a test that
+`scan_begin_src` has only one bit set.  The allowed values are
+`TRIG_FOLLOW` and `TRIG_TIMER`, but the code incorrectly also allows
+`TRIG_FOLLOW | TRIG_TIMER`.  Add a call to
+`comedi_check_trigger_is_unique()` to check that only one trigger source
+bit is set.
+
+Fixes: 783ddaebd397 ("staging: comedi: comedi_test: support scan_begin_src == TRIG_FOLLOW")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Link: https://patch.msgid.link/20260422162138.36003-1-abbotti@mev.co.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/comedi/drivers/comedi_test.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/comedi/drivers/comedi_test.c
++++ b/drivers/comedi/drivers/comedi_test.c
+@@ -274,6 +274,7 @@ static int waveform_ai_cmdtest(struct co
+       /* Step 2a : make sure trigger sources are unique */
+       err |= comedi_check_trigger_is_unique(cmd->convert_src);
++      err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
+       err |= comedi_check_trigger_is_unique(cmd->stop_src);
+       /* Step 2b : and mutually compatible */
diff --git a/queue-6.18/comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch b/queue-6.18/comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch
new file mode 100644 (file)
index 0000000..b36e941
--- /dev/null
@@ -0,0 +1,69 @@
+From 8a3bee801d420be8a7a0bae4a26547b353b8fe22 Mon Sep 17 00:00:00 2001
+From: Ian Abbott <abbotti@mev.co.uk>
+Date: Wed, 22 Apr 2026 15:46:37 +0100
+Subject: comedi: comedi_test: Fix limiting of convert_arg in waveform_ai_cmdtest()
+
+From: Ian Abbott <abbotti@mev.co.uk>
+
+commit 8a3bee801d420be8a7a0bae4a26547b353b8fe22 upstream.
+
+The function checks and possibly modifies the description of an
+asynchronous command to be run on the analog input subdevice of a comedi
+device attached to the "comedi_test" driver, returning 0 if no
+modifications were required, or a positive value that indicates which
+step of the checking process it failed on.  Step 4 fixes up various
+argument values for various trigger sources.
+
+There are two bugs in the fixing up of the `convert_arg` value to keep
+the `scan_begin_arg` value within the range of `unsigned int` when
+`scan_begin_src` and `convert_src` both have the value `TRIG_TIMER`,
+which indicates that the corresponding `_arg` values hold a time period
+in nanoseconds.  The code also uses `scan_end_arg` which hold the number
+of "conversions" within each "scan".  The goal is to end up with the
+scan period being less than or equal to the convert period multiplied by
+the number of conversions per scan.  It intends to do that by clamping
+the `convert_arg` value to a maximum value of `UINT_MAX / scan_end_arg`
+rounded down to a multiple of 1000 (`NSEC_PER_USEC`).
+
+(The rounding from nanoseconds to microseconds is because the driver is
+modelling a device that uses a 1 MHz clock for timing.  This is partly
+because that is a more typical timing base for real hardware devices
+driven by comedi, and partly because the driver used to use `struct
+timeval` internally.)
+
+The first bug is that the code checks if `scan_begin_arg == TRIG_TIMER`
+when it should be checking if `scan_begin_src == TRIG_TIMER`.  The
+bugged check will always fail because if `scan_begin_src == TRIG_TIMER`,
+then `scan_begin_arg` will be at least 1000 (`NSEC_PER_USEC`), otherwise
+`scan_begin_src == TRIG_FOLLOW` and `scan_begin_arg` will be 0.  (N.B
+`TRIG_TIMER` is defined as `0x10`.)  The second bug is that is rounding
+the maximum value down to a multiple of 1000000000 (`NSEC_PER_SEC`)
+instead of 1000 (`NSEC_PER_USEC`), however this bug is not reached due
+to the first bug.  This patch fixes both bugs.
+
+Fixes: 783ddaebd397 ("staging: comedi: comedi_test: support scan_begin_src == TRIG_FOLLOW")
+Fixes: 5afdcad2f818 ("staging: comedi: comedi_test: limit maximum convert_arg")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Link: https://patch.msgid.link/20260422144637.27692-1-abbotti@mev.co.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/comedi/drivers/comedi_test.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/comedi/drivers/comedi_test.c
++++ b/drivers/comedi/drivers/comedi_test.c
+@@ -325,10 +325,10 @@ static int waveform_ai_cmdtest(struct co
+               arg = min(arg,
+                         rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC));
+               arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC);
+-              if (cmd->scan_begin_arg == TRIG_TIMER) {
++              if (cmd->scan_begin_src == TRIG_TIMER) {
+                       /* limit convert_arg to keep scan_begin_arg in range */
+                       limit = UINT_MAX / cmd->scan_end_arg;
+-                      limit = rounddown(limit, (unsigned int)NSEC_PER_SEC);
++                      limit = rounddown(limit, (unsigned int)NSEC_PER_USEC);
+                       arg = min(arg, limit);
+               }
+               err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
diff --git a/queue-6.18/counter-fix-refcount-leak-in-counter_alloc-error-path.patch b/queue-6.18/counter-fix-refcount-leak-in-counter_alloc-error-path.patch
new file mode 100644 (file)
index 0000000..999f74b
--- /dev/null
@@ -0,0 +1,47 @@
+From d9eeb0ea0d2de658663bfaa9c26eccdd8fd64440 Mon Sep 17 00:00:00 2001
+From: Guangshuo Li <lgs201920130244@gmail.com>
+Date: Mon, 13 Apr 2026 21:46:04 +0800
+Subject: counter: Fix refcount leak in counter_alloc() error path
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+commit d9eeb0ea0d2de658663bfaa9c26eccdd8fd64440 upstream.
+
+After device_initialize(), the lifetime of the embedded struct device
+is expected to be managed through the device core reference counting.
+
+In counter_alloc(), if dev_set_name() fails after device_initialize(),
+the error path removes the chrdev, frees the ID, and frees the backing
+allocation directly instead of releasing the device reference with
+put_device(). This bypasses the normal device lifetime rules and may
+leave the reference count of the embedded struct device unbalanced,
+resulting in a refcount leak.
+
+The issue was identified by a static analysis tool I developed and
+confirmed by manual review.
+
+Fix this by using put_device() in the dev_set_name() failure path and
+let counter_device_release() handle the final cleanup.
+
+Fixes: 4da08477ea1f ("counter: Set counter device name")
+Cc: stable@vger.kernel.org
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Link: https://lore.kernel.org/r/20260413134604.2861772-1-lgs201920130244@gmail.com
+Signed-off-by: William Breathitt Gray <wbg@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/counter/counter-core.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/counter/counter-core.c
++++ b/drivers/counter/counter-core.c
+@@ -124,7 +124,8 @@ struct counter_device *counter_alloc(siz
+ err_dev_set_name:
+-      counter_chrdev_remove(counter);
++      put_device(dev);
++      return NULL;
+ err_chrdev_add:
+       ida_free(&counter_ida, dev->id);
diff --git a/queue-6.18/drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch b/queue-6.18/drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch
new file mode 100644 (file)
index 0000000..e1e4a57
--- /dev/null
@@ -0,0 +1,46 @@
+From dd4f3ee535b3b0ac027f75dbf9dc5fc88733c765 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Timur=20Krist=C3=B3f?= <timur.kristof@gmail.com>
+Date: Tue, 19 May 2026 10:41:54 +0200
+Subject: drm/amd/pm/si: Disregard vblank time when no displays are connected
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Timur Kristóf <timur.kristof@gmail.com>
+
+commit dd4f3ee535b3b0ac027f75dbf9dc5fc88733c765 upstream.
+
+When no displays are connected, there is no vblank
+happening so the power management code shouldn't
+worry about it.
+
+This fixes a regression that caused the memory clock
+to be stuck at maximum when there were no displays
+connected to a SI GPU.
+
+Fixes: 9003a0746864 ("drm/amd/pm: Treat zero vblank time as too short in si_dpm (v3)")
+Fixes: 9d73b107a61b ("drm/amd/pm: Use pm_display_cfg in legacy DPM (v2)")
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Tested-by: Jeremy Klarenbeek <jeremy.klarenbeek99@gmail.com>
+Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 6d87e0199f7b83735b56e422d59f170a201897a8)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+@@ -3081,6 +3081,10 @@ static bool si_dpm_vblank_too_short(void
+       /* we never hit the non-gddr5 limit so disable it */
+       u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
++      /* Disregard vblank time when there are no displays connected */
++      if (!adev->pm.pm_display_cfg.num_display)
++              return false;
++
+       /* Consider zero vblank time too short and disable MCLK switching.
+        * Note that the vblank time is set to maximum when no displays are attached,
+        * so we'll still enable MCLK switching in that case.
diff --git a/queue-6.18/drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch b/queue-6.18/drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch
new file mode 100644 (file)
index 0000000..2b102b6
--- /dev/null
@@ -0,0 +1,44 @@
+From a1ba4594232c87c3b8defd6f89a2e40f8b08395d Mon Sep 17 00:00:00 2001
+From: Ziyi Guo <n7l8m4@u.northwestern.edu>
+Date: Sun, 8 Feb 2026 00:02:55 +0000
+Subject: drm/amdgpu: check num_entries in GEM_OP GET_MAPPING_INFO
+
+From: Ziyi Guo <n7l8m4@u.northwestern.edu>
+
+commit a1ba4594232c87c3b8defd6f89a2e40f8b08395d upstream.
+
+kvcalloc(args->num_entries, sizeof(*vm_entries), GFP_KERNEL) at
+amdgpu_gem.c:1050 uses the user-supplied num_entries directly without
+any upper bounds check. Since num_entries is a __u32 and
+sizeof(drm_amdgpu_gem_vm_entry) is 32 bytes, a large num_entries
+produces an allocation exceeding INT_MAX, triggering
+WARNING in __kvmalloc_node_noprof(), causing a kernel WARNING,
+TAINT_WARN, and panic on CONFIG_PANIC_ON_WARN=y systems.
+
+Add a size bounds check before we invoke the kvzalloc() to
+reject oversized num_entries early with -EINVAL.
+
+Fixes: 4d82724f7f2b ("drm/amdgpu: Add mapping info option for GEM_OP ioctl")
+Signed-off-by: Ziyi Guo <n7l8m4@u.northwestern.edu>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 1fe7bf5457f6efd7be60b17e23163ba54341d73d)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+@@ -1074,6 +1074,11 @@ int amdgpu_gem_op_ioctl(struct drm_devic
+                * If that number is larger than the size of the array, the ioctl must
+                * be retried.
+                */
++              if (args->num_entries > INT_MAX / sizeof(*vm_entries)) {
++                      r = -EINVAL;
++                      goto out_exec;
++              }
++
+               vm_entries = kvcalloc(args->num_entries, sizeof(*vm_entries), GFP_KERNEL);
+               if (!vm_entries) {
+                       r = -ENOMEM;
diff --git a/queue-6.18/drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch b/queue-6.18/drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch
new file mode 100644 (file)
index 0000000..80e576f
--- /dev/null
@@ -0,0 +1,63 @@
+From 1c824497d8acd3187d585d6187cedc1897dcc871 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
+Date: Wed, 18 Feb 2026 12:31:29 +0100
+Subject: drm/amdgpu: fix calling VM invalidation in amdgpu_hmm_invalidate_gfx
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+commit 1c824497d8acd3187d585d6187cedc1897dcc871 upstream.
+
+Otherwise we don't invalidate page tables on next CS.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Reviewed-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Tested-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit b6444d1bcbc34f6f2a31a3aab3059be082f3683e)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c |    1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c  |    7 +++++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
+@@ -78,6 +78,7 @@ static bool amdgpu_hmm_invalidate_gfx(st
+       mmu_interval_set_seq(mni, cur_seq);
++      amdgpu_vm_bo_invalidate(bo, false);
+       r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
+                                 false, MAX_SCHEDULE_TIMEOUT);
+       mutex_unlock(&adev->notifier_lock);
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+@@ -1610,6 +1610,7 @@ int amdgpu_vm_handle_moved(struct amdgpu
+ {
+       struct amdgpu_bo_va *bo_va;
+       struct dma_resv *resv;
++      struct amdgpu_bo *bo;
+       bool clear, unlock;
+       int r;
+@@ -1629,11 +1630,13 @@ int amdgpu_vm_handle_moved(struct amdgpu
+       while (!list_empty(&vm->invalidated)) {
+               bo_va = list_first_entry(&vm->invalidated, struct amdgpu_bo_va,
+                                        base.vm_status);
+-              resv = bo_va->base.bo->tbo.base.resv;
++              bo = bo_va->base.bo;
++              resv = bo->tbo.base.resv;
+               spin_unlock(&vm->status_lock);
+               /* Try to reserve the BO to avoid clearing its ptes */
+-              if (!adev->debug_vm && dma_resv_trylock(resv)) {
++              if (!adev->debug_vm && !amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
++                  dma_resv_trylock(resv)) {
+                       clear = false;
+                       unlock = true;
+               /* The caller is already holding the reservation lock */
diff --git a/queue-6.18/drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch b/queue-6.18/drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch
new file mode 100644 (file)
index 0000000..848a06c
--- /dev/null
@@ -0,0 +1,72 @@
+From 2e7f55eb408c3f72ee1957a0d0ad11d8648a6379 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 17 May 2026 09:17:42 -0400
+Subject: drm/amdgpu: fix lock leak on ENOMEM in AMDGPU_GEM_OP_GET_MAPPING_INFO
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 2e7f55eb408c3f72ee1957a0d0ad11d8648a6379 upstream.
+
+The AMDGPU_GEM_OP_GET_MAPPING_INFO branch of amdgpu_gem_op_ioctl()
+holds three cleanup-tracked resources before calling kvcalloc():
+the drm_gem_object reference from drm_gem_object_lookup(), the
+drm_exec lock on the looked-up GEM via drm_exec_lock_obj(), and
+the drm_exec lock on the per-process VM root page directory via
+amdgpu_vm_lock_pd().  All three are released by the out_exec
+label that every other error path in this function jumps to.
+The kvcalloc() failure path returns -ENOMEM directly, skipping
+out_exec and leaking all three.
+
+The leaked per-process VM root PD dma_resv lock is the
+load-bearing leak: any subsequent operation on the same VM
+(further GEM ops, command-submission, eviction, TTM shrinker
+callbacks) blocks on the held lock.  DRM_IOCTL_AMDGPU_GEM_OP is
+DRM_AUTH | DRM_RENDER_ALLOW, so this is an unprivileged-local
+denial of service against the caller's GPU context, reachable
+by any process with /dev/dri/renderD* access.
+
+Route the failure through out_exec so drm_exec_fini() and
+drm_gem_object_put() run.
+
+Reproduced on stock 7.0.0-10, Ryzen 7 5700U / Radeon Vega
+(Lucienne): the failing ioctl returns -ENOMEM and a second
+GET_MAPPING_INFO on the same fd then blocks in
+drm_exec_lock_obj() on the leaked dma_resv.  SIGKILL on the
+caller does not reap the task; the fd-release path during
+process exit goes through amdgpu_gem_object_close() ->
+drm_exec_prepare_obj() on the same lock, leaving the task in D
+state until the box is rebooted.  The patched kernel was not
+rebuilt and re-tested on this hardware; the fix is mechanical.
+Tested on a single Lucienne / Vega box only.
+
+Ziyi Guo posted an independent INT_MAX-bound check for
+args->num_entries in the same branch [1]; the two patches are
+complementary and can land in either order.
+
+Fixes: 4d82724f7f2b ("drm/amdgpu: Add mapping info option for GEM_OP ioctl")
+Link: https://lore.kernel.org/all/20260208000255.4073363-1-n7l8m4@u.northwestern.edu/ # [1]
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit b69d3256d79de15f54c322986ff4da68f1d65b0a)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+@@ -1075,8 +1075,10 @@ int amdgpu_gem_op_ioctl(struct drm_devic
+                * be retried.
+                */
+               vm_entries = kvcalloc(args->num_entries, sizeof(*vm_entries), GFP_KERNEL);
+-              if (!vm_entries)
+-                      return -ENOMEM;
++              if (!vm_entries) {
++                      r = -ENOMEM;
++                      goto out_exec;
++              }
+               amdgpu_vm_bo_va_for_each_valid_mapping(bo_va, mapping) {
+                       if (num_mappings < args->num_entries) {
diff --git a/queue-6.18/drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch b/queue-6.18/drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch
new file mode 100644 (file)
index 0000000..e78c870
--- /dev/null
@@ -0,0 +1,52 @@
+From 6842b6a4b72da9b2906ffc5ca9d846ace2c54c14 Mon Sep 17 00:00:00 2001
+From: David Francis <David.Francis@amd.com>
+Date: Thu, 14 May 2026 10:31:20 -0400
+Subject: drm/amdkfd: Check for pdd drm file first in CRIU restore path
+
+From: David Francis <David.Francis@amd.com>
+
+commit 6842b6a4b72da9b2906ffc5ca9d846ace2c54c14 upstream.
+
+CRIU restore ioctls are meant to be called by CRIU with no
+existing drm file. There's an error path
+for if the drm file unexpectedly exists. It was positioned so
+it was missing a fput(drm_file).
+
+Do that check earlier, as soon as we have the pdd.
+
+Signed-off-by: David Francis <David.Francis@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 2bab781dac78916c5cc8de76345a4102449267d7)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+@@ -2253,6 +2253,11 @@ static int criu_restore_devices(struct k
+                       ret = -EINVAL;
+                       goto exit;
+               }
++
++              if (pdd->drm_file) {
++                      ret = -EINVAL;
++                      goto exit;
++              }
+               pdd->user_gpu_id = device_buckets[i].user_gpu_id;
+               drm_file = fget(device_buckets[i].drm_fd);
+@@ -2262,11 +2267,6 @@ static int criu_restore_devices(struct k
+                       ret = -EINVAL;
+                       goto exit;
+               }
+-
+-              if (pdd->drm_file) {
+-                      ret = -EINVAL;
+-                      goto exit;
+-              }
+               /* create the vm using render nodes for kfd pdd */
+               if (kfd_process_device_init_vm(pdd, drm_file)) {
diff --git a/queue-6.18/drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch b/queue-6.18/drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch
new file mode 100644 (file)
index 0000000..8014d77
--- /dev/null
@@ -0,0 +1,43 @@
+From 93f5534b35a05ef8a0109c1eefa800062fee810a Mon Sep 17 00:00:00 2001
+From: Eric Huang <jinhuieric.huang@amd.com>
+Date: Tue, 12 May 2026 10:19:52 -0400
+Subject: drm/amdkfd: fix a vulnerability of integer overflow in kfd debugger
+
+From: Eric Huang <jinhuieric.huang@amd.com>
+
+commit 93f5534b35a05ef8a0109c1eefa800062fee810a upstream.
+
+get_queue_ids() computes array_size = num_queues * sizeof(uint32_t),
+which could overflow on 32-bit size_t build. using array_size()
+instead, it saturates to SIZE_MAX on overflow.
+
+Signed-off-by: Eric Huang <jinhuieric.huang@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 2d57a0475f085c08b49312dfd8edcb461845f285)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c |    8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+@@ -3292,12 +3292,14 @@ static void copy_context_work_handler(st
+ static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
+ {
+-      size_t array_size = num_queues * sizeof(uint32_t);
+-
+       if (!usr_queue_id_array)
+               return NULL;
+-      return memdup_user(usr_queue_id_array, array_size);
++      if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
++              return ERR_PTR(-EINVAL);
++
++      return memdup_user(usr_queue_id_array,
++                         array_size(num_queues, sizeof(uint32_t)));
+ }
+ int resume_queues(struct kfd_process *p,
diff --git a/queue-6.18/drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch b/queue-6.18/drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch
new file mode 100644 (file)
index 0000000..696cc00
--- /dev/null
@@ -0,0 +1,34 @@
+From e984d61d92e702096058f0f828f4b2b8563b88ce Mon Sep 17 00:00:00 2001
+From: Eric Huang <jinhuieric.huang@amd.com>
+Date: Thu, 7 May 2026 15:51:49 -0400
+Subject: drm/amdkfd: fix NULL pointer bug in svm_range_set_attr
+
+From: Eric Huang <jinhuieric.huang@amd.com>
+
+commit e984d61d92e702096058f0f828f4b2b8563b88ce upstream.
+
+The process_info could be NULL if user doesn't call kfd_ioctl_acquire_vm
+before calling kfd_ioctl_svm.
+
+Signed-off-by: Eric Huang <jinhuieric.huang@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 83a26c812e0529eb040d31a76f73e33e637243d4)
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_svm.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+@@ -3680,6 +3680,9 @@ svm_range_set_attr(struct kfd_process *p
+       svms = &p->svms;
++      if (!process_info)
++              return -EINVAL;
++
+       mutex_lock(&process_info->lock);
+       svm_range_list_lock_and_flush_work(svms, mm);
diff --git a/queue-6.18/drm-gem-fix-race-between-change_handle-and-handle_delete.patch b/queue-6.18/drm-gem-fix-race-between-change_handle-and-handle_delete.patch
new file mode 100644 (file)
index 0000000..b8eb3f7
--- /dev/null
@@ -0,0 +1,47 @@
+From 7164d78559b0ff29931a366a840a9e5dd53d4b7c Mon Sep 17 00:00:00 2001
+From: Zhenghang Xiao <kipreyyy@gmail.com>
+Date: Tue, 26 May 2026 16:53:13 +0800
+Subject: drm/gem: fix race between change_handle and handle_delete
+
+From: Zhenghang Xiao <kipreyyy@gmail.com>
+
+commit 7164d78559b0ff29931a366a840a9e5dd53d4b7c upstream.
+
+drm_gem_change_handle_ioctl leaves the old handle live in the IDR
+during the window between spin_unlock(table_lock) and the final
+spin_lock(table_lock). A concurrent drm_gem_handle_delete on the old
+handle succeeds in this window, decrements handle_count to 0, and frees
+the GEM object while the new handle's IDR entry still references it.
+
+NULL the old handle's IDR entry before dropping table_lock so that any
+concurrent GEM_CLOSE on the old handle sees NULL and returns -EINVAL.
+Restore the old entry on the prime-bookkeeping error path.
+
+Fixes: 5e28b7b94408 ("drm: Set old handle to NULL before prime swap in change_handle")
+Signed-off-by: Zhenghang Xiao <kipreyyy@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Link: https://patch.msgid.link/20260526085313.26791-1-kipreyyy@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_gem.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/gpu/drm/drm_gem.c
++++ b/drivers/gpu/drm/drm_gem.c
+@@ -1015,6 +1015,7 @@ int drm_gem_change_handle_ioctl(struct d
+              goto out_unlock;
+        }
++      idr_replace(&file_priv->object_idr, NULL, args->handle);
+       spin_unlock(&file_priv->table_lock);
+       if (obj->dma_buf) {
+@@ -1023,6 +1024,7 @@ int drm_gem_change_handle_ioctl(struct d
+               if (ret < 0) {
+                       spin_lock(&file_priv->table_lock);
+                       idr_remove(&file_priv->object_idr, handle);
++                      idr_replace(&file_priv->object_idr, obj, args->handle);
+                       spin_unlock(&file_priv->table_lock);
+                       goto out_unlock;
+               }
diff --git a/queue-6.18/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch b/queue-6.18/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch
new file mode 100644 (file)
index 0000000..eb3df16
--- /dev/null
@@ -0,0 +1,67 @@
+From 13d33b9ef67066c77c84273fac5a1d3fde3533d1 Mon Sep 17 00:00:00 2001
+From: Berkant Koc <me@berkoc.com>
+Date: Tue, 19 May 2026 22:08:17 +0200
+Subject: drm/hyperv: validate resolution_count and fix WIN8 fallback
+
+From: Berkant Koc <me@berkoc.com>
+
+commit 13d33b9ef67066c77c84273fac5a1d3fde3533d1 upstream.
+
+A SYNTHVID_RESOLUTION_RESPONSE with resolution_count > 64 walks past
+the supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT] array in the
+parse loop. Bound resolution_count against the array size, folded
+into the existing zero-check.
+
+When the WIN10 resolution probe fails, the caller in
+hyperv_connect_vsp() left hv->screen_*_max / preferred_* unpopulated,
+which sets mode_config.max_width / max_height to 0 and makes
+drm_internal_framebuffer_create() reject every userspace framebuffer
+with -EINVAL. The pre-WIN10 branch had the same gap for
+preferred_width / preferred_height. Use a single post-probe fallback
+guarded by screen_width_max == 0 so both paths converge on the WIN8
+defaults.
+
+Signed-off-by: Berkant Koc <me@berkoc.com>
+Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline
+Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device")
+Cc: stable@vger.kernel.org # 5.14+
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Tested-by: Michael Kelley <mhklinux@outlook.com>
+Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
+Link: https://patch.msgid.link/6945b22419c7d404b4954a113de2ac9c900dba93.1779542874.git.me@berkoc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/hyperv/hyperv_drm_proto.c |   13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
++++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
+@@ -396,8 +396,11 @@ static int hyperv_get_supported_resoluti
+               return -ETIMEDOUT;
+       }
+-      if (msg->resolution_resp.resolution_count == 0) {
+-              drm_err(dev, "No supported resolutions\n");
++      if (msg->resolution_resp.resolution_count == 0 ||
++          msg->resolution_resp.resolution_count >
++          SYNTHVID_MAX_RESOLUTION_COUNT) {
++              drm_err(dev, "Invalid resolution count: %d\n",
++                      msg->resolution_resp.resolution_count);
+               return -ENODEV;
+       }
+@@ -513,9 +516,13 @@ int hyperv_connect_vsp(struct hv_device
+               ret = hyperv_get_supported_resolution(hdev);
+               if (ret)
+                       drm_err(dev, "Failed to get supported resolution from host, use default\n");
+-      } else {
++      }
++
++      if (!hv->screen_width_max) {
+               hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
+               hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
++              hv->preferred_width = SYNTHVID_WIDTH_WIN8;
++              hv->preferred_height = SYNTHVID_HEIGHT_WIN8;
+       }
+       hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
diff --git a/queue-6.18/drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch b/queue-6.18/drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch
new file mode 100644 (file)
index 0000000..e3ee6f2
--- /dev/null
@@ -0,0 +1,187 @@
+From 7f87763f47a3c22fb50265a00619ef10f2394b18 Mon Sep 17 00:00:00 2001
+From: Berkant Koc <me@berkoc.com>
+Date: Sat, 23 May 2026 15:27:47 +0200
+Subject: drm/hyperv: validate VMBus packet size in receive callback
+
+From: Berkant Koc <me@berkoc.com>
+
+commit 7f87763f47a3c22fb50265a00619ef10f2394b18 upstream.
+
+hyperv_receive_sub() reads msg->vid_hdr.type and dispatches into one
+of four message-type branches without knowing how many bytes the host
+wrote into hv->recv_buf. The completion path then runs
+memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE), so the consumer that
+wakes on wait_for_completion_timeout() can read up to 16 KiB of
+residue from a prior message as if it were the response payload.
+
+Pass bytes_recvd into hyperv_receive_sub() and reject any packet that
+does not cover the pipe + synthvid header. A single switch on
+msg->vid_hdr.type then computes the type-specific payload size: the
+three completion-driving types (SYNTHVID_VERSION_RESPONSE,
+SYNTHVID_RESOLUTION_RESPONSE, SYNTHVID_VRAM_LOCATION_ACK) fall through
+to a shared exit that requires that size before memcpy/complete, while
+SYNTHVID_FEATURE_CHANGE validates its own payload and returns before
+reading is_dirt_needed. Unknown types are dropped.
+
+SYNTHVID_RESOLUTION_RESPONSE is variable length: the host fills
+resolution_count entries, not the full SYNTHVID_MAX_RESOLUTION_COUNT
+array. Validate the fixed prefix first so resolution_count can be
+read, bound it against the array, then require only the count-sized
+array, so the shorter responses the host actually sends are accepted.
+
+Only run the sub-handler when vmbus_recvpacket() returned success. The
+memcpy length is bytes_recvd, which is bounded by VMBUS_MAX_PACKET_SIZE
+only on a successful receive; on -ENOBUFS vmbus_recvpacket() instead
+reports the required length, which can exceed hv->recv_buf, so copying
+bytes_recvd would read and write past the 16 KiB buffers. Gating on the
+success return keeps the copy bounded. The nonzero-return path is itself
+a malformed-message case and is now logged rather than silently skipped;
+channel recovery is not attempted.
+
+Rejected packets are reported via drm_err_ratelimited() rather than
+silently dropped, matching the CoCo-hardened pattern in
+hv_kvp_onchannelcallback().
+
+Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video device")
+Cc: stable@vger.kernel.org # 5.14+
+Signed-off-by: Berkant Koc <me@berkoc.com>
+Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Tested-by: Michael Kelley <mhklinux@outlook.com>
+Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
+Link: https://patch.msgid.link/8200dbc199c7a9b75ac7e8af6c748d2189b5ebd5.1779542874.git.me@berkoc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/hyperv/hyperv_drm_proto.c |  100 ++++++++++++++++++++++++++----
+ 1 file changed, 87 insertions(+), 13 deletions(-)
+
+--- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
++++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
+@@ -425,30 +425,92 @@ static int hyperv_get_supported_resoluti
+       return 0;
+ }
+-static void hyperv_receive_sub(struct hv_device *hdev)
++static void hyperv_receive_sub(struct hv_device *hdev, u32 bytes_recvd)
+ {
+       struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
+       struct synthvid_msg *msg;
++      size_t hdr_size;
++      size_t need;
+       if (!hv)
+               return;
+-      msg = (struct synthvid_msg *)hv->recv_buf;
+-
+-      /* Complete the wait event */
+-      if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+-          msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
+-          msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
+-              memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE);
+-              complete(&hv->wait);
++      hdr_size = sizeof(struct pipe_msg_hdr) +
++                 sizeof(struct synthvid_msg_hdr);
++      if (bytes_recvd < hdr_size) {
++              drm_err_ratelimited(&hv->dev,
++                                  "synthvid packet too small for header: %u\n",
++                                  bytes_recvd);
+               return;
+       }
+-      if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
++      msg = (struct synthvid_msg *)hv->recv_buf;
++      need = hdr_size;
++
++      switch (msg->vid_hdr.type) {
++      case SYNTHVID_VERSION_RESPONSE:
++              need += sizeof(struct synthvid_version_resp);
++              break;
++      case SYNTHVID_RESOLUTION_RESPONSE:
++              /*
++               * The resolution response is variable length: the host
++               * fills resolution_count entries, not the full
++               * SYNTHVID_MAX_RESOLUTION_COUNT array. Require the fixed
++               * prefix first so resolution_count can be read, then
++               * demand exactly the count-sized array.
++               */
++              need += offsetof(struct synthvid_supported_resolution_resp,
++                               supported_resolution);
++              if (bytes_recvd < need)
++                      break;
++              if (msg->resolution_resp.resolution_count >
++                  SYNTHVID_MAX_RESOLUTION_COUNT) {
++                      drm_err_ratelimited(&hv->dev,
++                                          "synthvid resolution count too large: %u\n",
++                                          msg->resolution_resp.resolution_count);
++                      return;
++              }
++              need += msg->resolution_resp.resolution_count *
++                      sizeof(struct hvd_screen_info);
++              break;
++      case SYNTHVID_VRAM_LOCATION_ACK:
++              need += sizeof(struct synthvid_vram_location_ack);
++              break;
++      case SYNTHVID_FEATURE_CHANGE:
++              /*
++               * Not a completion-driving message: validate its own payload
++               * and consume it here rather than falling through to the
++               * memcpy/complete shared by the wait-event responses.
++               */
++              if (bytes_recvd < need +
++                  sizeof(struct synthvid_feature_change)) {
++                      drm_err_ratelimited(&hv->dev,
++                                          "synthvid feature change packet too small: %u\n",
++                                          bytes_recvd);
++                      return;
++              }
+               hv->dirt_needed = msg->feature_chg.is_dirt_needed;
+               if (hv->dirt_needed)
+                       hyperv_hide_hw_ptr(hv->hdev);
++              return;
++      default:
++              return;
++      }
++
++      /*
++       * Shared completion path for the wait-event responses
++       * (VERSION_RESPONSE, RESOLUTION_RESPONSE, VRAM_LOCATION_ACK):
++       * require the type-specific payload before handing the buffer to
++       * the waiter.
++       */
++      if (bytes_recvd < need) {
++              drm_err_ratelimited(&hv->dev,
++                                  "synthvid packet too small for type %u: %u < %zu\n",
++                                  msg->vid_hdr.type, bytes_recvd, need);
++              return;
+       }
++      memcpy(hv->init_buf, msg, bytes_recvd);
++      complete(&hv->wait);
+ }
+ static void hyperv_receive(void *ctx)
+@@ -469,9 +531,21 @@ static void hyperv_receive(void *ctx)
+               ret = vmbus_recvpacket(hdev->channel, recv_buf,
+                                      VMBUS_MAX_PACKET_SIZE,
+                                      &bytes_recvd, &req_id);
+-              if (bytes_recvd > 0 &&
+-                  recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
+-                      hyperv_receive_sub(hdev);
++              if (ret) {
++                      /*
++                       * A nonzero return (e.g. -ENOBUFS for an oversized
++                       * packet) is itself a malformed message: bytes_recvd
++                       * then reports the required length rather than a copied
++                       * payload, so it must not be forwarded to the
++                       * sub-handler. Channel recovery is not attempted.
++                       */
++                      drm_err_ratelimited(&hv->dev,
++                                          "vmbus_recvpacket failed: %d (need %u)\n",
++                                          ret, bytes_recvd);
++              } else if (bytes_recvd > 0 &&
++                         recv_buf->pipe_hdr.type == PIPE_MSG_DATA) {
++                      hyperv_receive_sub(hdev, bytes_recvd);
++              }
+       } while (bytes_recvd > 0 && ret == 0);
+ }
diff --git a/queue-6.18/drm-i915-fix-potential-uaf-in-ttm-object-purge.patch b/queue-6.18/drm-i915-fix-potential-uaf-in-ttm-object-purge.patch
new file mode 100644 (file)
index 0000000..5b4fc59
--- /dev/null
@@ -0,0 +1,152 @@
+From 5c4063c87a619e4df954c179d24628636f5db15f Mon Sep 17 00:00:00 2001
+From: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
+Date: Fri, 8 May 2026 14:23:51 +0200
+Subject: drm/i915: Fix potential UAF in TTM object purge
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
+
+commit 5c4063c87a619e4df954c179d24628636f5db15f upstream.
+
+TLDR: The bo->ttm object might be changed by calling ttm_bo_validate(),
+      move casting it to an i915_tt object later to actually get the right
+      pointer.
+
+A user reported hitting the following bug under heavy use on DG2:
+
+[26620.095550] Oops: general protection fault, probably for non-canonical address 0xa56b6b6b6b6b6b8b: 0000 1 SMP NOPTI
+[26620.095556] CPU: 2 UID: 0 PID: 631 Comm: Xorg Not tainted 6.18.8 #1 PREEMPT(lazy)
+[26620.095558] Hardware name: ASRock B850M Steel Legend WiFi/B850M Steel Legend WiFi, BIOS 3.50 09/18/2025
+[26620.095559] RIP: 0010:i915_ttm_purge+0x84/0x100 [i915]
+[26620.095604] Code: 00 00 00 48 8d 54 24 10 48 89 e6 48 89 fb e8 83 aa ae ff 85 c0 75 6f 48 83 bb a8 01 00 00 00 74 2c 48 8b 45 78 48 85 c0 74 23 <48> 8b 78 20 48 c7 c2 ff ff ff ff 31 f6 e8 7a 73 e3 e0 48 8b 7d 78
+[26620.095605] RSP: 0018:ffffc90005fd7430 EFLAGS: 00010282
+[26620.095607] RAX: a56b6b6b6b6b6b6b RBX: ffff8881f46c3dc0 RCX: 0000000000000000
+[26620.095608] RDX: 0000000000000000 RSI: 0000000000000246 RDI: 00000000ffffffff
+[26620.095609] RBP: ffff888289610f00 R08: 0000000000000001 R09: ffff88823b022000
+[26620.095609] R10: ffff888103029b28 R11: ffff8881fc7f3800 R12: ffff88810b6150d0
+[26620.095609] R13: ffff888289610f00 R14: 0000000000000000 R15: ffff8881f46c3dc0
+[26620.095610] FS: 00007f1004d86900(0000) GS:ffff88901c858000(0000) knlGS:0000000000000000
+[26620.095611] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[26620.095611] CR2: 00007f0fdf489000 CR3: 000000035b0c1000 CR4: 0000000000750ef0
+[26620.095612] PKRU: 55555554
+[26620.095612] Call Trace:
+[26620.095615] <TASK>
+[26620.095615] i915_ttm_move+0x2b9/0x420 [i915]
+[26620.095642] ? ttm_tt_init+0x65/0x80 [ttm]
+[26620.095644] ? i915_ttm_tt_create+0xc6/0x150 [i915]
+[26620.095667] ttm_bo_handle_move_mem+0xb6/0x160 [ttm]
+[26620.095669] ttm_bo_evict+0x100/0x150 [ttm]
+[26620.095671] ? preempt_count_add+0x64/0xa0
+[26620.095673] ? _raw_spin_lock+0xe/0x30
+[26620.095675] ? _raw_spin_unlock+0xd/0x30
+[26620.095675] ? i915_gem_object_evictable+0xb7/0xd0 [i915]
+[26620.095704] ttm_bo_evict_cb+0x6e/0xd0 [ttm]
+[26620.095705] ttm_lru_walk_for_evict+0xa6/0x200 [ttm]
+[26620.095708] ttm_bo_alloc_resource+0x185/0x4f0 [ttm]
+[26620.095709] ? init_object+0x62/0xd0
+[26620.095712] ttm_bo_validate+0x7a/0x180 [ttm]
+[26620.095713] ? _raw_spin_unlock_irqrestore+0x16/0x30
+[26620.095714] __i915_ttm_get_pages+0xb0/0x170 [i915]
+[26620.095737] i915_ttm_get_pages+0x9f/0x150 [i915]
+[26620.095759] ? i915_gem_do_execbuffer+0xedc/0x2b40 [i915]
+[26620.095786] ? alloc_debug_processing+0xd0/0x100
+[26620.095787] ? _raw_spin_unlock_irqrestore+0x16/0x30
+[26620.095788] ? i915_vma_instance+0xa0/0x4e0 [i915]
+[26620.095822] __i915_gem_object_get_pages+0x2f/0x40 [i915]
+[26620.095848] i915_vma_pin_ww+0x706/0x980 [i915]
+[26620.095875] ? i915_gem_do_execbuffer+0xedc/0x2b40 [i915]
+[26620.095904] eb_validate_vmas+0x170/0xa00 [i915]
+[26620.095930] i915_gem_do_execbuffer+0x1201/0x2b40 [i915]
+[26620.095953] ? alloc_debug_processing+0xd0/0x100
+[26620.095954] ? _raw_spin_unlock_irqrestore+0x16/0x30
+[26620.095955] ? i915_gem_execbuffer2_ioctl+0xc9/0x240 [i915]
+[26620.095977] ? __wake_up_sync_key+0x32/0x50
+[26620.095979] ? i915_gem_execbuffer2_ioctl+0xc9/0x240 [i915]
+[26620.096001] ? __slab_alloc.isra.0+0x67/0xc0
+[26620.096003] i915_gem_execbuffer2_ioctl+0x11a/0x240 [i915]
+
+Results from decode_stacktrace.sh pointed to dereference of a file pointer
+field of a i915 TTM page vector container associated with an object being
+purged on eviction.  That path is taken when the object is marked as no
+longer needed.
+
+Code analysis revealed a possibility of the i915 TTM page vector container
+being replaced with a new instance inside a function that purges content
+of the object, should it be still busy.  That function is called,
+indirectly via a more general function that changes the object's placement
+and caching policy, before the problematic dereference, but still after
+a pointer to the container is captured, rendering the pointer no longer
+valid.
+
+Fix the issue by capturing the pointer to the container only after its
+potential replacement.
+
+v2: Move the container_of() inside the if block (Sebastian),
+  - a simplified version of the commit description that explains briefly
+    why the change is necessary (Christian).
+
+Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/14882
+Fixes: 7ae034590ceae ("drm/i915/ttm: add tt shmem backend")
+Signed-off-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
+Cc: stable@vger.kernel.org # v5.17+
+Cc: Matthew Auld <matthew.auld@intel.com>
+Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Cc: Sebastian Brzezinka <sebastian.brzezinka@intel.com>
+Cc: Christian König <christian.koenig@amd.com>
+Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Andi Shyti <andi.shyti@linux.intel.com>
+Link: https://lore.kernel.org/r/20260508122612.469227-2-janusz.krzysztofik@linux.intel.com
+(cherry picked from commit 4462966a93eb185849b7f174f0d0de53476d00a4)
+Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/gem/i915_gem_ttm.c |   28 ++++++++++++++++------------
+ 1 file changed, 16 insertions(+), 12 deletions(-)
+
+--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+@@ -416,8 +416,6 @@ void i915_ttm_free_cached_io_rsgt(struct
+ int i915_ttm_purge(struct drm_i915_gem_object *obj)
+ {
+       struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+-      struct i915_ttm_tt *i915_tt =
+-              container_of(bo->ttm, typeof(*i915_tt), ttm);
+       struct ttm_operation_ctx ctx = {
+               .interruptible = true,
+               .no_wait_gpu = false,
+@@ -432,16 +430,22 @@ int i915_ttm_purge(struct drm_i915_gem_o
+       if (ret)
+               return ret;
+-      if (bo->ttm && i915_tt->filp) {
+-              /*
+-               * The below fput(which eventually calls shmem_truncate) might
+-               * be delayed by worker, so when directly called to purge the
+-               * pages(like by the shrinker) we should try to be more
+-               * aggressive and release the pages immediately.
+-               */
+-              shmem_truncate_range(file_inode(i915_tt->filp),
+-                                   0, (loff_t)-1);
+-              fput(fetch_and_zero(&i915_tt->filp));
++      if (bo->ttm) {
++              struct i915_ttm_tt *i915_tt =
++                      container_of(bo->ttm, typeof(*i915_tt), ttm);
++
++              if (i915_tt->filp) {
++                      /*
++                       * The below fput(which eventually calls shmem_truncate)
++                       * might be delayed by worker, so when directly called
++                       * to purge the pages(like by the shrinker) we should
++                       * try to be more aggressive and release the pages
++                       * immediately.
++                       */
++                      shmem_truncate_range(file_inode(i915_tt->filp),
++                                           0, (loff_t)-1);
++                      fput(fetch_and_zero(&i915_tt->filp));
++              }
+       }
+       obj->write_domain = 0;
diff --git a/queue-6.18/drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch b/queue-6.18/drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch
new file mode 100644 (file)
index 0000000..fe46f19
--- /dev/null
@@ -0,0 +1,77 @@
+From 8bb9093df555f9e89fdbe1405118b11384c03e04 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jouni=20H=C3=B6gander?= <jouni.hogander@intel.com>
+Date: Wed, 20 May 2026 13:49:43 +0300
+Subject: drm/i915/psr: Block DC states on vblank enable when Panel Replay supported
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jouni Högander <jouni.hogander@intel.com>
+
+commit 8bb9093df555f9e89fdbe1405118b11384c03e04 upstream.
+
+Currently we are blocking DC states only when Panel Replay is enabled on
+vblank enable. It may happen that Panel Replay is getting enabled when
+vblank is already enabled. Fix this by blocking DC states always if Panel
+Replay is supported.
+
+While at it take care of possible dual eDP case by looping all encoders
+supporting PSR.
+
+Fixes: 0c427ac78a1d ("drm/i915/psr: Add interface to notify PSR of vblank enable/disable")
+Cc: <stable@vger.kernel.org> # v6.16+
+Signed-off-by: Jouni Högander <jouni.hogander@intel.com>
+Reviewed-by: MichaÅ‚ Grzelak <michal.grzelak@intel.com>
+Link: https://patch.msgid.link/20260520104944.239797-1-jouni.hogander@intel.com
+(cherry picked from commit eb5911f990554f7ce947dd53df00c114362e4465)
+Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/display/intel_psr.c |   19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+--- a/drivers/gpu/drm/i915/display/intel_psr.c
++++ b/drivers/gpu/drm/i915/display/intel_psr.c
+@@ -3982,32 +3982,33 @@ void intel_psr_notify_vblank_enable_disa
+                                           bool enable)
+ {
+       struct intel_encoder *encoder;
++      bool block_dc_states = false;
+       for_each_intel_encoder_with_psr(display->drm, encoder) {
+               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+               mutex_lock(&intel_dp->psr.lock);
+-              if (intel_dp->psr.panel_replay_enabled) {
+-                      mutex_unlock(&intel_dp->psr.lock);
+-                      break;
+-              }
++              if (CAN_PANEL_REPLAY(intel_dp))
++                      block_dc_states = true;
+-              if (intel_dp->psr.enabled && intel_dp->psr.pkg_c_latency_used)
++              if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled &&
++                  intel_dp->psr.pkg_c_latency_used)
+                       intel_psr_apply_underrun_on_idle_wa_locked(intel_dp);
+               mutex_unlock(&intel_dp->psr.lock);
+-              return;
+       }
+       /*
+        * NOTE: intel_display_power_set_target_dc_state is used
+-       * only by PSR * code for DC3CO handling. DC3CO target
++       * only by PSR code for DC3CO handling. DC3CO target
+        * state is currently disabled in * PSR code. If DC3CO
+        * is taken into use we need take that into account here
+        * as well.
+        */
+-      intel_display_power_set_target_dc_state(display, enable ? DC_STATE_DISABLE :
+-                                              DC_STATE_EN_UPTO_DC6);
++      if (block_dc_states)
++              intel_display_power_set_target_dc_state(display, enable ?
++                                                      DC_STATE_DISABLE :
++                                                      DC_STATE_EN_UPTO_DC6);
+ }
+ static void
diff --git a/queue-6.18/gpib-cb7210-fix-region-leak-when-request_irq-fails.patch b/queue-6.18/gpib-cb7210-fix-region-leak-when-request_irq-fails.patch
new file mode 100644 (file)
index 0000000..46f90c2
--- /dev/null
@@ -0,0 +1,53 @@
+From 2eae90a457baa0048a96ed38ad93090ee38c8b2f Mon Sep 17 00:00:00 2001
+From: Hongling Zeng <zenghongling@kylinos.cn>
+Date: Mon, 18 May 2026 10:29:39 +0800
+Subject: gpib: cb7210: Fix region leak when request_irq fails
+
+From: Hongling Zeng <zenghongling@kylinos.cn>
+
+commit 2eae90a457baa0048a96ed38ad93090ee38c8b2f upstream.
+
+When request_irq() fails, the region allocated by request_region()
+is not released. Fix this by adding an error handling path with
+proper goto labels to release the region.
+
+Fixes: e9dc69956d4d ("staging: gpib: Add Computer Boards GPIB driver")
+Closes: https://lore.kernel.org/oe-kbuild-all/202605160620.ReBOadPX-lkp@intel.com/
+Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
+Cc: stable <stable@kernel.org>
+Link: https://patch.msgid.link/20260518022939.16881-1-zenghongling@kylinos.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/staging/gpib/cb7210/cb7210.c |   10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/staging/gpib/cb7210/cb7210.c
++++ b/drivers/staging/gpib/cb7210/cb7210.c
+@@ -1048,7 +1048,8 @@ static int cb_isa_attach(struct gpib_boa
+       if (!request_region(config->ibbase, cb7210_iosize, DRV_NAME)) {
+               dev_err(board->gpib_dev, "ioports starting at 0x%x are already in use\n",
+                       config->ibbase);
+-              return -EBUSY;
++              retval = -EBUSY;
++              goto err_release_region;
+       }
+       nec_priv->iobase = config->ibbase;
+       cb_priv->fifo_iobase = nec7210_iobase(cb_priv);
+@@ -1061,11 +1062,16 @@ static int cb_isa_attach(struct gpib_boa
+       // install interrupt handler
+       if (request_irq(config->ibirq, cb7210_interrupt, isr_flags, DRV_NAME, board)) {
+               dev_err(board->gpib_dev, "failed to obtain IRQ %d\n", config->ibirq);
+-              return -EBUSY;
++              retval = -EBUSY;
++              goto err_release_region;
+       }
+       cb_priv->irq = config->ibirq;
+       return cb7210_init(cb_priv, board);
++
++err_release_region:
++      release_region(nec7210_iobase(cb_priv), cb7210_iosize);
++      return retval;
+ }
+ static void cb_isa_detach(struct gpib_board *board)
diff --git a/queue-6.18/input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch b/queue-6.18/input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch
new file mode 100644 (file)
index 0000000..1a12fab
--- /dev/null
@@ -0,0 +1,53 @@
+From baa0210fb6a9dc3882509a9411b6d284d88fe30e Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Mon, 4 May 2026 11:54:45 -0700
+Subject: Input: atmel_mxt_ts - fix boundary check in mxt_prepare_cfg_mem
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+commit baa0210fb6a9dc3882509a9411b6d284d88fe30e upstream.
+
+When a configuration file provides an object size that is larger than the
+driver's known mxt_obj_size(object), the driver intends to discard the
+extra bytes.
+
+The loop iterates using for (i = 0; i < size; i++). Inside the loop, the
+condition to skip processing extra bytes is:
+
+    if (i > mxt_obj_size(object))
+        continue;
+
+Since i is a 0-based index, the valid indices for the object are 0 through
+mxt_obj_size(object) - 1.
+
+When i == mxt_obj_size(object), the condition evaluates to false, and the
+code processes the byte instead of discarding it.
+
+This causes the code to calculate byte_offset = reg + i - cfg->start_ofs
+and writes the byte there, overwriting exactly one byte of the adjacent
+instance or object.
+
+Update the boundary check to skip extra bytes correctly by using >=.
+
+Fixes: 50a77c658b80 ("Input: atmel_mxt_ts - download device config using firmware loader")
+Cc: stable@vger.kernel.org
+Assisted-by: Gemini:gemini-3.1-pro
+Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
+Link: https://patch.msgid.link/20260504185448.4055973-1-dmitry.torokhov@gmail.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/input/touchscreen/atmel_mxt_ts.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/input/touchscreen/atmel_mxt_ts.c
++++ b/drivers/input/touchscreen/atmel_mxt_ts.c
+@@ -1477,7 +1477,7 @@ static int mxt_prepare_cfg_mem(struct mx
+                       }
+                       cfg->raw_pos += offset;
+-                      if (i > mxt_obj_size(object))
++                      if (i >= mxt_obj_size(object))
+                               continue;
+                       byte_offset = reg + i - cfg->start_ofs;
diff --git a/queue-6.18/input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch b/queue-6.18/input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch
new file mode 100644 (file)
index 0000000..ff3fac9
--- /dev/null
@@ -0,0 +1,45 @@
+From 16ca52bc209fa4bf9239cd9e5643e95533476b58 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Nicol=C3=A1s=20Bazaes?= <contacto@bazaes.cl>
+Date: Wed, 13 May 2026 21:35:49 -0400
+Subject: Input: synaptics - add LEN2058 to SMBus passlist for ThinkPad E490
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nicolás Bazaes <contacto@bazaes.cl>
+
+commit 16ca52bc209fa4bf9239cd9e5643e95533476b58 upstream.
+
+The Lenovo ThinkPad E490 (PNP ID: LEN2058) has a Synaptics TM3471-020
+touchpad that supports SMBus/RMI4 mode but is not listed in
+smbus_pnp_ids[]. Without this entry, RMI4 over SMBus is not enabled
+by default, and the touchpad falls back to PS/2 mode.
+
+Adding LEN2058 to the passlist enables automatic RMI4 detection without
+requiring the psmouse.synaptics_intertouch parameter, and matches
+the behavior of similar ThinkPad models already in the list
+(E480/LEN2054, E580/LEN2055).
+
+Tested on ThinkPad E490 with kernel 7.0.5-zen1 and Arch Linux.
+RMI4 over SMBus is confirmed working without any kernel parameters.
+
+Signed-off-by: Nicolás Bazaes <contacto@bazaes.cl>
+Assisted-by: Claude:claude-sonnet-4-6
+Link: https://patch.msgid.link/20260514013552.14234-1-contacto@bazaes.cl
+Cc: stable@vger.kernel.org
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/input/mouse/synaptics.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/input/mouse/synaptics.c
++++ b/drivers/input/mouse/synaptics.c
+@@ -190,6 +190,7 @@ static const char * const smbus_pnp_ids[
+       "LEN2044", /* L470  */
+       "LEN2054", /* E480 */
+       "LEN2055", /* E580 */
++      "LEN2058", /* E490 */
+       "LEN2068", /* T14 Gen 1 */
+       "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */
+       "SYN3003", /* HP EliteBook 850 G1 */
diff --git a/queue-6.18/input-xpad-add-nova-2-lite-from-gamesir.patch b/queue-6.18/input-xpad-add-nova-2-lite-from-gamesir.patch
new file mode 100644 (file)
index 0000000..bf58d75
--- /dev/null
@@ -0,0 +1,31 @@
+From 1f6ac0f8441c48c4cc250141e1da8486c13512ba Mon Sep 17 00:00:00 2001
+From: Qbeliw Tanaka <q.tanaka@gmx.com>
+Date: Thu, 30 Apr 2026 21:44:12 -0700
+Subject: Input: xpad - add "Nova 2 Lite" from GameSir
+
+From: Qbeliw Tanaka <q.tanaka@gmx.com>
+
+commit 1f6ac0f8441c48c4cc250141e1da8486c13512ba upstream.
+
+Add support for the gamepad "Nova 2 Lite" from GameSir, compatible with
+the Xbox 360 gamepad.
+
+Signed-off-by: Qbeliw Tanaka <q.tanaka@gmx.com>
+Link: https://patch.msgid.link/20260429.162040.930225048583399359.q.tanaka@gmx.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/input/joystick/xpad.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/input/joystick/xpad.c
++++ b/drivers/input/joystick/xpad.c
+@@ -425,6 +425,7 @@ static const struct xpad_device {
+       { 0x3285, 0x0662, "Nacon Revolution5 Pro", 0, XTYPE_XBOX360 },
+       { 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE },
+       { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 },
++      { 0x3537, 0x100f, "GameSir Nova 2 Lite", 0, XTYPE_XBOX360 },
+       { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
+       { 0x3651, 0x1000, "CRKD SG", 0, XTYPE_XBOX360 },
+       { 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT },
diff --git a/queue-6.18/input-xpad-add-support-for-asus-rog-raikiri-ii.patch b/queue-6.18/input-xpad-add-support-for-asus-rog-raikiri-ii.patch
new file mode 100644 (file)
index 0000000..8c5e02b
--- /dev/null
@@ -0,0 +1,43 @@
+From c897cf120696b94f56ed0f3197ba9a77071a59ec Mon Sep 17 00:00:00 2001
+From: Dmitriy Zharov <contact@zharov.dev>
+Date: Thu, 30 Apr 2026 22:35:22 +0400
+Subject: Input: xpad - add support for ASUS ROG RAIKIRI II
+
+From: Dmitriy Zharov <contact@zharov.dev>
+
+commit c897cf120696b94f56ed0f3197ba9a77071a59ec upstream.
+
+Add the VID/PIDs for the ASUS ROG RAIKIRI II controller to xpad_device
+and the VID to xpad_table. The controller has a physical PC/XBOX toggle
+which switches between XBOX360 and XBOXONE protocols.
+
+Signed-off-by: Dmitriy Zharov <contact@zharov.dev>
+Link: https://patch.msgid.link/20260430183522.122151-1-contact@zharov.dev
+Cc: stable@vger.kernel.org
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/input/joystick/xpad.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/input/joystick/xpad.c
++++ b/drivers/input/joystick/xpad.c
+@@ -220,6 +220,10 @@ static const struct xpad_device {
+       { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 },
+       { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+       { 0x0b05, 0x1abb, "ASUS ROG RAIKIRI PRO", 0, XTYPE_XBOXONE },
++      { 0x0b05, 0x1c91, "ASUS ROG RAIKIRI II", 0, XTYPE_XBOX360 },
++      { 0x0b05, 0x1c92, "ASUS ROG RAIKIRI II WIRELESS", 0, XTYPE_XBOX360 },
++      { 0x0b05, 0x1c96, "ASUS ROG RAIKIRI II XBOX", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
++      { 0x0b05, 0x1d04, "ASUS ROG RAIKIRI II XBOX WIRELESS", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+       { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX },
+       { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+@@ -542,6 +546,7 @@ static const struct usb_device_id xpad_t
+       { USB_DEVICE(0x0738, 0x4540) },         /* Mad Catz Beat Pad */
+       XPAD_XBOXONE_VENDOR(0x0738),            /* Mad Catz FightStick TE 2 */
+       XPAD_XBOX360_VENDOR(0x07ff),            /* Mad Catz Gamepad */
++      XPAD_XBOX360_VENDOR(0x0b05),            /* ASUS controllers */
+       XPAD_XBOXONE_VENDOR(0x0b05),            /* ASUS controllers */
+       XPAD_XBOX360_VENDOR(0x0c12),            /* Zeroplus X-Box 360 controllers */
+       XPAD_XBOX360_VENDOR(0x0db0),            /* Micro Star International X-Box 360 controllers */
diff --git a/queue-6.18/ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch b/queue-6.18/ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch
new file mode 100644 (file)
index 0000000..b221db2
--- /dev/null
@@ -0,0 +1,61 @@
+From 0e60dafe97eca61721f3db456f97d97a80c6c8ae Mon Sep 17 00:00:00 2001
+From: Ali Ganiyev <ali.qaniyev@gmail.com>
+Date: Mon, 25 May 2026 10:23:47 +0900
+Subject: ksmbd: OOB read regression in smb_check_perm_dacl() ACE-walk loops
+
+From: Ali Ganiyev <ali.qaniyev@gmail.com>
+
+commit 0e60dafe97eca61721f3db456f97d97a80c6c8ae upstream.
+
+Commit d07b26f39246 ("ksmbd: require minimum ACE size in
+smb_check_perm_dacl()") introduced a transposed bounds check:
+
+    if (offsetof(struct smb_ace, sid) + aces_size < CIFS_SID_BASE_SIZE)
+
+Since offsetof(..sid) is 8 and CIFS_SID_BASE_SIZE is 8, this evaluates
+to `aces_size < 0`. Because `aces_size` is always non-negative, this
+check becomes dead code and never breaks the loop.
+
+Worse, that commit removed the old 4-byte guard, meaning the loop now
+reads `ace->size` (offset 2) even when `aces_size` is 0-3 bytes. This
+re-opens a 2-byte heap out-of-bounds (OOB) read past the pntsd allocation
+during subsequent SMB2_CREATE operations.
+
+Fix this by properly transposing the comparison to require at least
+16 bytes (8-byte offset + 8-byte SID base), matching the correct form
+used in smb_inherit_dacl().
+
+Fixes: d07b26f39246 ("ksmbd: require minimum ACE size in smb_check_perm_dacl()")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ali Ganiyev <ali.qaniyev@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/smb/server/smbacl.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -1446,8 +1446,8 @@ int smb_check_perm_dacl(struct ksmbd_con
+               ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+               aces_size = acl_size - sizeof(struct smb_acl);
+               for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
+-                      if (offsetof(struct smb_ace, sid) +
+-                          aces_size < CIFS_SID_BASE_SIZE)
++                      if (aces_size < offsetof(struct smb_ace, sid) +
++                          CIFS_SID_BASE_SIZE)
+                               break;
+                       ace_size = le16_to_cpu(ace->size);
+                       if (ace_size > aces_size ||
+@@ -1470,8 +1470,8 @@ int smb_check_perm_dacl(struct ksmbd_con
+       ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
+       aces_size = acl_size - sizeof(struct smb_acl);
+       for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
+-              if (offsetof(struct smb_ace, sid) +
+-                  aces_size < CIFS_SID_BASE_SIZE)
++              if (aces_size < offsetof(struct smb_ace, sid) +
++                  CIFS_SID_BASE_SIZE)
+                       break;
+               ace_size = le16_to_cpu(ace->size);
+               if (ace_size > aces_size ||
diff --git a/queue-6.18/misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch b/queue-6.18/misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch
new file mode 100644 (file)
index 0000000..a1698e1
--- /dev/null
@@ -0,0 +1,56 @@
+From 36770417153644bc88281c7284730ef1d14d8d3c Mon Sep 17 00:00:00 2001
+From: Xiaolei Wang <xiaolei.wang@windriver.com>
+Date: Mon, 18 May 2026 15:34:05 +0800
+Subject: misc: rp1: Send IACK on IRQ activate to fix kdump/kexec
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Xiaolei Wang <xiaolei.wang@windriver.com>
+
+commit 36770417153644bc88281c7284730ef1d14d8d3c upstream.
+
+After a kexec/kdump reboot, the macb Ethernet controller fails to
+receive any packets, causing DHCP to hang indefinitely and the network
+interface to be unusable despite link being up.
+
+The root cause is that RP1's level-triggered MSI-X interrupt sources
+(such as macb on hwirq 6) may have their internal state machines stuck
+in the "waiting for IACK" state. This happens because the previous
+kernel crashed before sending the acknowledgment for a pending level
+interrupt.
+
+In this stuck state, RP1 will not generate new MSI-X writes even though
+the interrupt source remains asserted. Since no new MSI-X is sent, the
+GIC never sees a new edge, the chained IRQ handler is never invoked,
+and the interrupt is permanently lost.
+
+Fix this by sending MSIX_CFG_IACK in rp1_irq_activate(). This
+unconditionally resets the MSI-X state machine back to idle when a
+child device requests its interrupt. If the interrupt source is still
+asserted, RP1 will immediately issue a new MSI-X with the freshly
+configured msg_addr/msg_data, and normal interrupt delivery resumes.
+
+Writing IACK when the state machine is already idle (i.e., on a normal
+cold boot) is harmless â€” it has no effect.
+
+Fixes: 49d63971f963 ("misc: rp1: RaspberryPi RP1 misc driver")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Xiaolei Wang <xiaolei.wang@windriver.com>
+Link: https://patch.msgid.link/20260518073405.2115003-1-xiaolei.wang@windriver.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/misc/rp1/rp1_pci.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/misc/rp1/rp1_pci.c
++++ b/drivers/misc/rp1/rp1_pci.c
+@@ -148,6 +148,7 @@ static int rp1_irq_activate(struct irq_d
+       struct rp1_dev *rp1 = d->host_data;
+       msix_cfg_set(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE);
++      msix_cfg_set(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_IACK);
+       return 0;
+ }
diff --git a/queue-6.18/scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch b/queue-6.18/scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch
new file mode 100644 (file)
index 0000000..56f3a2c
--- /dev/null
@@ -0,0 +1,53 @@
+From 9eed1bd59937e6828b00d2f2dfef631d964f3636 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Mon, 18 May 2026 10:43:07 -0400
+Subject: scsi: fcoe: Reject FIP descriptors with zero fip_dlen in CVL walker
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 9eed1bd59937e6828b00d2f2dfef631d964f3636 upstream.
+
+drivers/scsi/fcoe/fcoe_ctlr.c::fcoe_ctlr_recv_clr_vlink() advanced the
+descriptor cursor by an attacker-supplied fip_dlen without ever
+requiring dlen >= sizeof(struct fip_desc) in the default branch.  The
+named descriptor cases (FIP_DT_MAC, FIP_DT_NAME, FIP_DT_VN_ID) checked
+their per-type minimum lengths, but a FIP_DT_NON_CRITICAL descriptor
+(fip_dtype >= 128, which the standard requires receivers to silently
+ignore) skipped that check entirely.
+
+An unauthenticated L2 peer on the FCoE control VLAN could hang
+fcoe_ctlr_recv_work on an fcoe, qedf, or bnx2fc initiator indefinitely
+by emitting one FIP CVL frame whose single descriptor had fip_dtype ==
+FIP_DT_NON_CRITICAL and fip_dlen == 0: the cursor advanced zero bytes
+per iteration and the loop condition rlen >= sizeof(*desc) stayed true
+forever, blocking every subsequent FIP frame on that controller.
+
+Tighten the outer dlen guard to also reject dlen < sizeof(struct
+fip_desc), so a malformed descriptor whose length cannot even cover the
+descriptor header is rejected before the switch.  This is the same
+lower-bound the named cases already apply and is the minimum scope that
+closes the loop.
+
+Fixes: 97c8389d54b9 ("[SCSI] fcoe, libfcoe: Add support for FIP. FCoE discovery and keep-alive.")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Reviewed-by: Hannes Reinecke <hare@kernel.org>
+Link: https://patch.msgid.link/20260518144307.2820961-1-michael.bommarito@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/fcoe/fcoe_ctlr.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/scsi/fcoe/fcoe_ctlr.c
++++ b/drivers/scsi/fcoe/fcoe_ctlr.c
+@@ -1386,7 +1386,7 @@ static void fcoe_ctlr_recv_clr_vlink(str
+       while (rlen >= sizeof(*desc)) {
+               dlen = desc->fip_dlen * FIP_BPW;
+-              if (dlen > rlen)
++              if (dlen < sizeof(*desc) || dlen > rlen)
+                       goto err;
+               /* Drop CVL if there are duplicate critical descriptors */
+               if ((desc->fip_dtype < 32) &&
diff --git a/queue-6.18/scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch b/queue-6.18/scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch
new file mode 100644 (file)
index 0000000..bc0bdc2
--- /dev/null
@@ -0,0 +1,163 @@
+From a9a39233ec1fc9f97ea1340a4d09bb7ec2be5153 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Wed, 20 May 2026 09:30:15 -0400
+Subject: scsi: scsi_transport_fc: Widen FPIN pname walker counter to u32
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit a9a39233ec1fc9f97ea1340a4d09bb7ec2be5153 upstream.
+
+An adjacent Fibre Channel fabric actor that can deliver an FPIN ELS
+frame to an lpfc or qla2xxx Linux initiator can trigger a non-return in
+the generic FC transport. This is not a local userspace or IP network
+path; the attacker must be able to inject fabric traffic, for example as
+a compromised switch or fabric controller, or as a same-zone N_Port on a
+fabric that permits source spoofing.
+
+The Link-Integrity and Peer-Congestion FPIN walkers used a u8 loop
+counter against the 32-bit on-wire pname_count field, and did not bound
+pname_count by the descriptor body already validated by the TLV walker.
+A pname_count of 256 therefore wraps the counter and keeps the loop
+condition true indefinitely.
+
+Factor the shared pname_list[] walk into one helper, widen the counter
+to u32, and clamp pname_count against the entries that fit in the
+descriptor body before iterating.
+
+Fixes: 3dcfe0de5a97 ("scsi: fc: Parse FPIN packets and update statistics")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Link: https://patch.msgid.link/20260520133015.1018937-1-michael.bommarito@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/scsi_transport_fc.c |   77 ++++++++++++++++++++-------------------
+ 1 file changed, 41 insertions(+), 36 deletions(-)
+
+--- a/drivers/scsi/scsi_transport_fc.c
++++ b/drivers/scsi/scsi_transport_fc.c
+@@ -735,6 +735,37 @@ fc_cn_stats_update(u16 event_type, struc
+       }
+ }
++static void
++fc_fpin_pname_stats_update(struct Scsi_Host *shost,
++                         struct fc_rport *attach_rport, u16 event_type,
++                         u32 desc_len, u32 fixed_len, u32 pname_count,
++                         __be64 *pname_list,
++                         void (*stats_update)(u16 event_type,
++                                              struct fc_fpin_stats *stats))
++{
++      u32 i;
++      struct fc_rport *rport;
++      u64 wwpn;
++
++      if (desc_len < fixed_len)
++              pname_count = 0;
++      else
++              pname_count = min(pname_count, (desc_len - fixed_len) /
++                                 sizeof(pname_list[0]));
++
++      for (i = 0; i < pname_count; i++) {
++              wwpn = be64_to_cpu(pname_list[i]);
++              rport = fc_find_rport_by_wwpn(shost, wwpn);
++              if (rport &&
++                  (rport->roles & FC_PORT_ROLE_FCP_TARGET ||
++                   rport->roles & FC_PORT_ROLE_NVME_TARGET)) {
++                      if (rport == attach_rport)
++                              continue;
++                      stats_update(event_type, &rport->fpin_stats);
++              }
++      }
++}
++
+ /*
+  * fc_fpin_li_stats_update - routine to update Link Integrity
+  * event statistics.
+@@ -745,13 +776,11 @@ fc_cn_stats_update(u16 event_type, struc
+ static void
+ fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv)
+ {
+-      u8 i;
+       struct fc_rport *rport = NULL;
+       struct fc_rport *attach_rport = NULL;
+       struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+       struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv;
+       u16 event_type = be16_to_cpu(li_desc->event_type);
+-      u64 wwpn;
+       rport = fc_find_rport_by_wwpn(shost,
+                                     be64_to_cpu(li_desc->attached_wwpn));
+@@ -762,22 +791,11 @@ fc_fpin_li_stats_update(struct Scsi_Host
+               fc_li_stats_update(event_type, &attach_rport->fpin_stats);
+       }
+-      if (be32_to_cpu(li_desc->pname_count) > 0) {
+-              for (i = 0;
+-                  i < be32_to_cpu(li_desc->pname_count);
+-                  i++) {
+-                      wwpn = be64_to_cpu(li_desc->pname_list[i]);
+-                      rport = fc_find_rport_by_wwpn(shost, wwpn);
+-                      if (rport &&
+-                          (rport->roles & FC_PORT_ROLE_FCP_TARGET ||
+-                          rport->roles & FC_PORT_ROLE_NVME_TARGET)) {
+-                              if (rport == attach_rport)
+-                                      continue;
+-                              fc_li_stats_update(event_type,
+-                                                 &rport->fpin_stats);
+-                      }
+-              }
+-      }
++      fc_fpin_pname_stats_update(shost, attach_rport, event_type,
++                                 be32_to_cpu(li_desc->desc_len),
++                                 FC_TLV_DESC_LENGTH_FROM_SZ(*li_desc),
++                                 be32_to_cpu(li_desc->pname_count),
++                                 li_desc->pname_list, fc_li_stats_update);
+       if (fc_host->port_name == be64_to_cpu(li_desc->attached_wwpn))
+               fc_li_stats_update(event_type, &fc_host->fpin_stats);
+@@ -825,13 +843,11 @@ static void
+ fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost,
+                               struct fc_tlv_desc *tlv)
+ {
+-      u8 i;
+       struct fc_rport *rport = NULL;
+       struct fc_rport *attach_rport = NULL;
+       struct fc_fn_peer_congn_desc *pc_desc =
+           (struct fc_fn_peer_congn_desc *)tlv;
+       u16 event_type = be16_to_cpu(pc_desc->event_type);
+-      u64 wwpn;
+       rport = fc_find_rport_by_wwpn(shost,
+                                     be64_to_cpu(pc_desc->attached_wwpn));
+@@ -842,22 +858,11 @@ fc_fpin_peer_congn_stats_update(struct S
+               fc_cn_stats_update(event_type, &attach_rport->fpin_stats);
+       }
+-      if (be32_to_cpu(pc_desc->pname_count) > 0) {
+-              for (i = 0;
+-                  i < be32_to_cpu(pc_desc->pname_count);
+-                  i++) {
+-                      wwpn = be64_to_cpu(pc_desc->pname_list[i]);
+-                      rport = fc_find_rport_by_wwpn(shost, wwpn);
+-                      if (rport &&
+-                          (rport->roles & FC_PORT_ROLE_FCP_TARGET ||
+-                           rport->roles & FC_PORT_ROLE_NVME_TARGET)) {
+-                              if (rport == attach_rport)
+-                                      continue;
+-                              fc_cn_stats_update(event_type,
+-                                                 &rport->fpin_stats);
+-                      }
+-              }
+-      }
++      fc_fpin_pname_stats_update(shost, attach_rport, event_type,
++                                 be32_to_cpu(pc_desc->desc_len),
++                                 FC_TLV_DESC_LENGTH_FROM_SZ(*pc_desc),
++                                 be32_to_cpu(pc_desc->pname_count),
++                                 pc_desc->pname_list, fc_cn_stats_update);
+ }
+ /*
diff --git a/queue-6.18/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch b/queue-6.18/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
new file mode 100644 (file)
index 0000000..57e62ba
--- /dev/null
@@ -0,0 +1,199 @@
+From bf33e01f88388c43e285492a63e539df6ffed64c Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Mon, 11 May 2026 14:49:14 -0400
+Subject: scsi: target: iscsi: Bound iscsi_encode_text_output() appends to rsp_buf
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit bf33e01f88388c43e285492a63e539df6ffed64c upstream.
+
+iscsi_encode_text_output() concatenates "key=value\0" records into
+login->rsp_buf, an 8192-byte kzalloc(MAX_KEY_VALUE_PAIRS) buffer
+allocated in iscsit_alloc_login_setup_buffer(). The three sprintf() call
+sites in this function (lines 1398, 1411, 1424 in v7.1-rc2) never check
+the remaining buffer capacity:
+
+       *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+       *length += 1;
+       output_buf = textbuf + *length;
+
+The 8192-byte ceiling at iscsi_target_check_login_request() bounds the
+*input* Login PDU payload, but a single PDU can carry up to 2048 minimal
+four-byte "a=b\0" pairs, each unknown key expanding to a 16-byte
+"a=NotUnderstood\0" output record via iscsi_add_notunderstood_response().
+2048 * 16 = 32 KiB of output into an 8 KiB buffer, producing a ~24 KiB
+heap overrun in the kmalloc-8k slab.
+
+The fix introduces a static iscsi_encode_text_record() helper that uses
+snprintf() with a per-call bounds check against the remaining buffer,
+and threads a u32 textbuf_size parameter through
+iscsi_encode_text_output(). Both call sites in
+iscsi_target_handle_csg_zero() (PHASE_SECURITY) and
+iscsi_target_handle_csg_one() (PHASE_OPERATIONAL) pass
+MAX_KEY_VALUE_PAIRS. On overflow the encoder logs the condition, calls
+iscsi_release_extra_responses() to drop queued records, and returns -1;
+both caller sites now emit ISCSI_STATUS_CLS_INITIATOR_ERR /
+ISCSI_LOGIN_STATUS_INIT_ERR via iscsit_tx_login_rsp() before returning,
+so the initiator sees an explicit failed-login response rather than a
+silent connection drop. (Prior to this patch only the PHASE_OPERATIONAL
+caller did that; the PHASE_SECURITY caller is converted to the same
+shape.)
+
+Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Tested-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/target/iscsi/iscsi_target_nego.c       |    7 ++
+ drivers/target/iscsi/iscsi_target_parameters.c |   62 +++++++++++++++++++------
+ drivers/target/iscsi/iscsi_target_parameters.h |    2 
+ 3 files changed, 55 insertions(+), 16 deletions(-)
+
+--- a/drivers/target/iscsi/iscsi_target_nego.c
++++ b/drivers/target/iscsi/iscsi_target_nego.c
+@@ -899,10 +899,14 @@ static int iscsi_target_handle_csg_zero(
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
++                      MAX_KEY_VALUE_PAIRS,
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
+-      if (ret < 0)
++      if (ret < 0) {
++              iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
++                              ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
++      }
+       if (!iscsi_check_negotiated_keys(conn->param_list)) {
+               bool auth_required = iscsi_conn_auth_required(conn);
+@@ -986,6 +990,7 @@ static int iscsi_target_handle_csg_one(s
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
++                      MAX_KEY_VALUE_PAIRS,
+                       conn->param_list,
+                       conn->tpg->tpg_attrib.login_keys_workaround);
+       if (ret < 0) {
+--- a/drivers/target/iscsi/iscsi_target_parameters.c
++++ b/drivers/target/iscsi/iscsi_target_parameters.c
+@@ -1371,19 +1371,42 @@ free_buffer:
+       return -1;
+ }
++/*
++ * Append "key=value" plus a trailing NUL into @textbuf at *@length.
++ * Returns 0 on success and advances *@length, or -EMSGSIZE if the
++ * record (including the NUL) would not fit in the remaining buffer.
++ */
++static int iscsi_encode_text_record(char *textbuf, u32 *length,
++                                  u32 textbuf_size,
++                                  const char *key, const char *value)
++{
++      int n;
++      u32 avail;
++
++      if (*length >= textbuf_size)
++              return -EMSGSIZE;
++
++      avail = textbuf_size - *length;
++      n = snprintf(textbuf + *length, avail, "%s=%s", key, value);
++      if (n < 0 || (u32)n + 1 > avail)
++              return -EMSGSIZE;
++
++      *length += n + 1;
++      return 0;
++}
++
+ int iscsi_encode_text_output(
+       u8 phase,
+       u8 sender,
+       char *textbuf,
+       u32 *length,
++      u32 textbuf_size,
+       struct iscsi_param_list *param_list,
+       bool keys_workaround)
+ {
+-      char *output_buf = NULL;
+       struct iscsi_extra_response *er;
+       struct iscsi_param *param;
+-
+-      output_buf = textbuf + *length;
++      int ret;
+       if (iscsi_enforce_integrity_rules(phase, param_list) < 0)
+               return -1;
+@@ -1395,10 +1418,12 @@ int iscsi_encode_text_output(
+                   !IS_PSTATE_RESPONSE_SENT(param) &&
+                   !IS_PSTATE_REPLY_OPTIONAL(param) &&
+                   (param->phase & phase)) {
+-                      *length += sprintf(output_buf, "%s=%s",
+-                              param->name, param->value);
+-                      *length += 1;
+-                      output_buf = textbuf + *length;
++                      ret = iscsi_encode_text_record(textbuf, length,
++                                                     textbuf_size,
++                                                     param->name,
++                                                     param->value);
++                      if (ret < 0)
++                              goto err_overflow;
+                       SET_PSTATE_RESPONSE_SENT(param);
+                       pr_debug("Sending key: %s=%s\n",
+                               param->name, param->value);
+@@ -1408,10 +1433,12 @@ int iscsi_encode_text_output(
+                   !IS_PSTATE_ACCEPTOR(param) &&
+                   !IS_PSTATE_PROPOSER(param) &&
+                   (param->phase & phase)) {
+-                      *length += sprintf(output_buf, "%s=%s",
+-                              param->name, param->value);
+-                      *length += 1;
+-                      output_buf = textbuf + *length;
++                      ret = iscsi_encode_text_record(textbuf, length,
++                                                     textbuf_size,
++                                                     param->name,
++                                                     param->value);
++                      if (ret < 0)
++                              goto err_overflow;
+                       SET_PSTATE_PROPOSER(param);
+                       iscsi_check_proposer_for_optional_reply(param,
+                                                               keys_workaround);
+@@ -1421,14 +1448,21 @@ int iscsi_encode_text_output(
+       }
+       list_for_each_entry(er, &param_list->extra_response_list, er_list) {
+-              *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+-              *length += 1;
+-              output_buf = textbuf + *length;
++              ret = iscsi_encode_text_record(textbuf, length, textbuf_size,
++                                             er->key, er->value);
++              if (ret < 0)
++                      goto err_overflow;
+               pr_debug("Sending key: %s=%s\n", er->key, er->value);
+       }
+       iscsi_release_extra_responses(param_list);
+       return 0;
++
++err_overflow:
++      pr_err("iSCSI login response buffer (%u bytes) exhausted, dropping login.\n",
++             textbuf_size);
++      iscsi_release_extra_responses(param_list);
++      return -1;
+ }
+ int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list)
+--- a/drivers/target/iscsi/iscsi_target_parameters.h
++++ b/drivers/target/iscsi/iscsi_target_parameters.h
+@@ -43,7 +43,7 @@ extern struct iscsi_param *iscsi_find_pa
+ extern int iscsi_extract_key_value(char *, char **, char **);
+ extern int iscsi_update_param_value(struct iscsi_param *, char *);
+ extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsit_conn *);
+-extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
++extern int iscsi_encode_text_output(u8, u8, char *, u32 *, u32,
+                       struct iscsi_param_list *, bool);
+ extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
+ extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
diff --git a/queue-6.18/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch b/queue-6.18/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
new file mode 100644 (file)
index 0000000..d79e326
--- /dev/null
@@ -0,0 +1,119 @@
+From 778c2ab142c625a8a8afa570e0f9b7873f445d99 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sat, 18 Apr 2026 11:49:27 -0400
+Subject: scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd()
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 778c2ab142c625a8a8afa570e0f9b7873f445d99 upstream.
+
+Two latent bugs in the Text-phase handler, both present since the
+original LIO integration in commit e48354ce078c ("iscsi-target: Add
+iSCSI fabric support for target v4.1"):
+
+1) DataDigest CRC buffer overread (4 bytes past text_in).
+
+   text_in is kzalloc()'d at ALIGN(payload_length, 4).  rx_size is then
+   incremented by ISCSI_CRC_LEN to make room for the received DataDigest
+   in the iovec, but the same (now-bumped) rx_size is passed as the
+   buffer length to iscsit_crc_buf():
+
+       if (conn->conn_ops->DataDigest) {
+               ...
+               rx_size += ISCSI_CRC_LEN;
+       }
+       ...
+       if (conn->conn_ops->DataDigest) {
+               data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL);
+
+   iscsit_crc_buf() walks rx_size bytes of text_in with crc32c(), so
+   when DataDigest is negotiated it reads 4 bytes past the end of the
+   text_in allocation.  KASAN reproduces this directly on the unpatched
+   mainline tree as slab-out-of-bounds in crc32c() called from the Text
+   PDU path.  The OOB bytes feed crc32c() and are then compared against
+   the initiator-supplied checksum, so the value does not flow back to
+   the attacker, but the kernel does read past the buffer on every Text
+   PDU with DataDigest=CRC32C.
+
+   Fix by passing the actual padded payload length
+   (ALIGN(payload_length, 4)) that was used for the kzalloc().
+
+2) Stale cmd->text_in_ptr re-free (double-free) on ERL>0 bad DataDigest
+   drop.
+
+   On DataDigest mismatch with ErrorRecoveryLevel > 0 the handler
+   silently drops the PDU and lets the initiator plug the CmdSN gap:
+
+               kfree(text_in);
+               return 0;
+
+   cmd->text_in_ptr still points at the freed buffer.  The next Text
+   Request on the same ITT re-enters iscsit_setup_text_cmd(), which
+   unconditionally does
+
+       kfree(cmd->text_in_ptr);
+       cmd->text_in_ptr = NULL;
+
+   freeing the same pointer a second time.  Session teardown via
+   iscsit_release_cmd() has the same shape and hits the same double-free
+   if the connection is dropped before a second Text Request arrives.
+
+   On an unmodified mainline tree the bug-1 CRC overread fires first on
+   the initial valid Text Request and perturbs the subsequent state, so
+   #4 was isolated by building a kernel with only the bug-1 hunk of this
+   patch applied plus temporary printk() observability around the three
+   relevant kfree() sites.  The observability prints are not part of
+   this patch.  On that build, a three-PDU Text Request sequence after
+   login produces two back-to-back splats:
+
+       BUG: KASAN: double-free in iscsit_setup_text_cmd+0x??
+       BUG: KASAN: double-free in iscsit_release_cmd+0x??
+
+   showing the same pointer freed in the ERL>0 drop path and again in
+   iscsit_setup_text_cmd() (next Text Request on the same ITT) and once
+   more in iscsit_release_cmd() (session teardown).  On distro kernels
+   with CONFIG_SLAB_FREELIST_HARDENED=y (default) the double-free
+   becomes a remote kernel BUG(); on non-hardened kernels it corrupts
+   the slab freelist.
+
+   Fix by clearing cmd->text_in_ptr after the kfree() in the ERL>0 drop
+   path.  With both hunks applied #4 is directly observable on the stock
+   tree without observability printks; fixing bug-1 alone would mask #4
+   less, not more, so the hunks are submitted together.
+
+Both fixes are one-liners.  The Text PDU state machine is unchanged and
+the wire protocol is unaffected.
+
+Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Tested-by: John Garry <john.g.garry@oracle.com>
+Reviewed-by: John Garry <john.g.garry@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/target/iscsi/iscsi_target.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -2281,7 +2281,9 @@ iscsit_handle_text_cmd(struct iscsit_con
+                       goto reject;
+               if (conn->conn_ops->DataDigest) {
+-                      data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL);
++                      data_crc = iscsit_crc_buf(text_in,
++                                                ALIGN(payload_length, 4),
++                                                0, NULL);
+                       if (checksum != data_crc) {
+                               pr_err("Text data CRC32C DataDigest"
+                                       " 0x%08x does not match computed"
+@@ -2300,6 +2302,7 @@ iscsit_handle_text_cmd(struct iscsit_con
+                                       " Command CmdSN: 0x%08x due to"
+                                       " DataCRC error.\n", hdr->cmdsn);
+                                       kfree(text_in);
++                                      cmd->text_in_ptr = NULL;
+                                       return 0;
+                               }
+                       } else {
diff --git a/queue-6.18/scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch b/queue-6.18/scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch
new file mode 100644 (file)
index 0000000..cd37d41
--- /dev/null
@@ -0,0 +1,92 @@
+From 85db7391310b1304d2dc8ae3b0b12105a9567147 Mon Sep 17 00:00:00 2001
+From: Alexandru Hossu <hossu.alexandru@gmail.com>
+Date: Thu, 21 May 2026 17:11:21 +0200
+Subject: scsi: target: iscsi: Validate CHAP_R length before base64 decode
+
+From: Alexandru Hossu <hossu.alexandru@gmail.com>
+
+commit 85db7391310b1304d2dc8ae3b0b12105a9567147 upstream.
+
+chap_server_compute_hash() allocates client_digest as
+kzalloc(chap->digest_size) and then, for BASE64-encoded responses,
+passes chap_r directly to chap_base64_decode() without checking whether
+the input length could produce more than digest_size bytes of output.
+
+chap_base64_decode() writes to the destination unconditionally as long
+as there is input to consume. With MAX_RESPONSE_LENGTH set to 128 and
+the "0b" prefix stripped by extract_param(), up to 127 base64 characters
+can reach the decoder. 127 characters decode to 95 bytes. For SHA-256
+(digest_size=32) this overflows client_digest by 63 bytes; for MD5
+(digest_size=16) the overflow is 79 bytes.
+
+The length check at line 344 fires after the write has already happened.
+
+The HEX branch in the same switch statement already validates the length
+up front. Apply the same approach to the BASE64 branch: strip trailing
+base64 padding characters, then reject any input whose data length
+exceeds DIV_ROUND_UP(digest_size * 4, 3) before calling the decoder.
+
+Stripping trailing '=' before the comparison handles both padded and
+unpadded encodings. chap_base64_decode() already returns early on '=',
+so the full original string is still passed to the decoder unchanged.
+
+The mutual CHAP path decodes CHAP_C into initiatorchg_binhex, which is
+kzalloc(CHAP_CHALLENGE_STR_LEN). extract_param() caps initiatorchg at
+CHAP_CHALLENGE_STR_LEN characters, so at most CHAP_CHALLENGE_STR_LEN-1
+base64 characters reach the decoder. The maximum decoded size,
+DIV_ROUND_UP((CHAP_CHALLENGE_STR_LEN-1) * 3, 4), is less than
+CHAP_CHALLENGE_STR_LEN, so no overflow is possible there. A comment is
+added at the call site to document this.
+
+Fixes: 1e5733883421 ("scsi: target: iscsi: Support base64 in CHAP")
+Cc: stable@vger.kernel.org
+Signed-off-by: Alexandru Hossu <hossu.alexandru@gmail.com>
+Reviewed-by: David Disseldorp <ddiss@suse.de>
+Link: https://patch.msgid.link/20260521151121.808477-1-hossu.alexandru@gmail.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/target/iscsi/iscsi_target_auth.c |   19 ++++++++++++++++++-
+ 1 file changed, 18 insertions(+), 1 deletion(-)
+
+--- a/drivers/target/iscsi/iscsi_target_auth.c
++++ b/drivers/target/iscsi/iscsi_target_auth.c
+@@ -339,13 +339,22 @@ static int chap_server_compute_hash(
+                       goto out;
+               }
+               break;
+-      case BASE64:
++      case BASE64: {
++              size_t r_len = strlen(chap_r);
++
++              while (r_len > 0 && chap_r[r_len - 1] == '=')
++                      r_len--;
++              if (r_len > DIV_ROUND_UP(chap->digest_size * 4, 3)) {
++                      pr_err("Malformed CHAP_R: base64 payload too long\n");
++                      goto out;
++              }
+               if (chap_base64_decode(client_digest, chap_r, strlen(chap_r)) !=
+                   chap->digest_size) {
+                       pr_err("Malformed CHAP_R: invalid BASE64\n");
+                       goto out;
+               }
+               break;
++      }
+       default:
+               pr_err("Could not find CHAP_R\n");
+               goto out;
+@@ -472,6 +481,14 @@ static int chap_server_compute_hash(
+               }
+               break;
+       case BASE64:
++              /*
++               * No overflow check needed: initiatorchg_binhex is
++               * CHAP_CHALLENGE_STR_LEN bytes and extract_param() caps
++               * initiatorchg at CHAP_CHALLENGE_STR_LEN characters, so
++               * the decoded output is at most DIV_ROUND_UP(
++               * (CHAP_CHALLENGE_STR_LEN - 1) * 3, 4) bytes, which is
++               * less than CHAP_CHALLENGE_STR_LEN.
++               */
+               initiatorchg_len = chap_base64_decode(initiatorchg_binhex,
+                                                     initiatorchg,
+                                                     strlen(initiatorchg));
diff --git a/queue-6.18/serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch b/queue-6.18/serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch
new file mode 100644 (file)
index 0000000..0641c2b
--- /dev/null
@@ -0,0 +1,78 @@
+From 71f42b2149a1307a97165b409493665579462ea0 Mon Sep 17 00:00:00 2001
+From: Jacques Nilo <jnilo@free.fr>
+Date: Wed, 13 May 2026 15:30:24 +0200
+Subject: serial: 8250: dispatch SysRq character in serial8250_handle_irq()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jacques Nilo <jnilo@free.fr>
+
+commit 71f42b2149a1307a97165b409493665579462ea0 upstream.
+
+serial8250_handle_irq() captures a SysRq character into port->sysrq_ch
+inside serial8250_handle_irq_locked() via uart_prepare_sysrq_char()
+(reached from serial8250_read_char()). Dispatch of that captured
+character to handle_sysrq() is expected to happen at port-unlock time,
+through uart_unlock_and_check_sysrq[_irqrestore]().
+
+After commit 8324a54f604d ("serial: 8250: Add
+serial8250_handle_irq_locked()") the function was reduced to a wrapper
+that takes the port lock via guard(uart_port_lock_irqsave) whose
+destructor is plain uart_port_unlock_irqrestore(). The sysrq-aware
+unlock helper is no longer called, so port->sysrq_ch is captured but
+never dispatched: BREAK + SysRq key is consumed silently.
+
+This was the very condition Johan Hovold's 853a9ae29e978 ("serial:
+8250: fix handle_irq locking", 2021) introduced
+uart_unlock_and_check_sysrq_irqrestore() to address.
+
+Switch to the new guard(uart_port_lock_check_sysrq_irqsave), whose
+destructor is the sysrq-aware unlock helper, restoring the pre-split
+behaviour. Update the Context: comment on serial8250_handle_irq_locked()
+so future HW-specific 8250 wrappers know to use the same guard or the
+explicit sysrq-aware unlock.
+
+Verified on RTL8196E with CONFIG_MAGIC_SYSRQ_SERIAL=y: BREAK + 'h' on
+the console UART produces the SysRq help dump in dmesg and the brk
+counter in /proc/tty/driver/serial increments correctly.
+
+Fixes: 8324a54f604d ("serial: 8250: Add serial8250_handle_irq_locked()")
+Cc: stable@vger.kernel.org
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Jacques Nilo <jnilo@free.fr>
+Link: https://patch.msgid.link/52692ae6c3501f7940347cef364ad7fcacaab7e5.1778675349.git.jnilo@free.fr
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/8250/8250_port.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
+index af78cc02f38e..c66ba714caa5 100644
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -1784,7 +1784,10 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
+ }
+ /*
+- * Context: port's lock must be held by the caller.
++ * Context: port's lock must be held by the caller. The caller must
++ * release it via guard(uart_port_lock_check_sysrq_irqsave) or
++ * uart_unlock_and_check_sysrq_irqrestore(), which captures SysRq
++ * character on unlock.
+  */
+ void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir)
+ {
+@@ -1837,7 +1840,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+       if (iir & UART_IIR_NO_INT)
+               return 0;
+-      guard(uart_port_lock_irqsave)(port);
++      guard(uart_port_lock_check_sysrq_irqsave)(port);
+       serial8250_handle_irq_locked(port, iir);
+       return 1;
+-- 
+2.54.0
+
diff --git a/queue-6.18/serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch b/queue-6.18/serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch
new file mode 100644 (file)
index 0000000..8f502d4
--- /dev/null
@@ -0,0 +1,54 @@
+From 2e211723953f7740e54b53f3d3a0d5e351a5e223 Mon Sep 17 00:00:00 2001
+From: Jacques Nilo <jnilo@free.fr>
+Date: Wed, 13 May 2026 15:30:25 +0200
+Subject: serial: 8250_dw: dispatch SysRq character in dw8250_handle_irq()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jacques Nilo <jnilo@free.fr>
+
+commit 2e211723953f7740e54b53f3d3a0d5e351a5e223 upstream.
+
+dw8250_handle_irq() calls serial8250_handle_irq_locked() with the port
+lock held via guard(uart_port_lock_irqsave). The guard destructor is
+plain uart_port_unlock_irqrestore(), so a SysRq character captured into
+port->sysrq_ch by uart_prepare_sysrq_char() is dropped without ever
+being dispatched to handle_sysrq().
+
+This is the same regression pattern as in serial8250_handle_irq(),
+introduced when 883c5a2bc934 ("serial: 8250_dw: Rework
+dw8250_handle_irq() locking and IIR handling") moved the function to
+the guard()-based locking scheme without using the sysrq-aware unlock
+helper.
+
+Switch to guard(uart_port_lock_check_sysrq_irqsave) so that captured
+sysrq_ch is dispatched on scope exit, matching the fix in
+serial8250_handle_irq().
+
+Fixes: 883c5a2bc934 ("serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling")
+Cc: stable@vger.kernel.org
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Jacques Nilo <jnilo@free.fr>
+Link: https://patch.msgid.link/ed56fcaf4af24e4ed011a7bce206e0182acb761c.1778675349.git.jnilo@free.fr
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/8250/8250_dw.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
+index 94beadb4024d..2af0c4d0ad82 100644
+--- a/drivers/tty/serial/8250/8250_dw.c
++++ b/drivers/tty/serial/8250/8250_dw.c
+@@ -427,7 +427,7 @@ static int dw8250_handle_irq(struct uart_port *p)
+       unsigned int quirks = d->pdata->quirks;
+       unsigned int status;
+-      guard(uart_port_lock_irqsave)(p);
++      guard(uart_port_lock_check_sysrq_irqsave)(p);
+       switch (FIELD_GET(DW_UART_IIR_IID, iir)) {
+       case UART_IIR_NO_INT:
+-- 
+2.54.0
+
diff --git a/queue-6.18/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch b/queue-6.18/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
new file mode 100644 (file)
index 0000000..15a90bf
--- /dev/null
@@ -0,0 +1,54 @@
+From ea66be25f0e934f49d24cd0c5845d13cdba3520b Mon Sep 17 00:00:00 2001
+From: Myeonghun Pak <mhun512@gmail.com>
+Date: Tue, 12 May 2026 15:56:57 +0900
+Subject: serial: altera_jtaguart: handle uart_add_one_port() failures
+
+From: Myeonghun Pak <mhun512@gmail.com>
+
+commit ea66be25f0e934f49d24cd0c5845d13cdba3520b upstream.
+
+altera_jtaguart_probe() maps the register window before registering the
+UART port, but it ignores failures from uart_add_one_port(). If port
+registration fails, probe still returns success and the mapping remains
+live until a later remove path that is not part of probe failure cleanup.
+
+Return the uart_add_one_port() error and unmap the register window on
+that failure path.
+
+This issue was identified during our ongoing static-analysis research while
+reviewing kernel code.
+
+Fixes: 5bcd601049c6 ("serial: Add driver for the Altera JTAG UART")
+Cc: stable <stable@kernel.org>
+Co-developed-by: Ijae Kim <ae878000@gmail.com>
+Signed-off-by: Ijae Kim <ae878000@gmail.com>
+Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
+Link: https://patch.msgid.link/20260512065837.79528-1-mhun512@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/altera_jtaguart.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/altera_jtaguart.c
++++ b/drivers/tty/serial/altera_jtaguart.c
+@@ -379,6 +379,7 @@ static int altera_jtaguart_probe(struct
+       struct resource *res_mem;
+       int i = pdev->id;
+       int irq;
++      int ret;
+       /* -1 emphasizes that the platform must have one port, no .N suffix */
+       if (i == -1)
+@@ -418,7 +419,11 @@ static int altera_jtaguart_probe(struct
+       port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
+-      uart_add_one_port(&altera_jtaguart_driver, port);
++      ret = uart_add_one_port(&altera_jtaguart_driver, port);
++      if (ret) {
++              iounmap(port->membase);
++              return ret;
++      }
+       return 0;
+ }
diff --git a/queue-6.18/serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch b/queue-6.18/serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch
new file mode 100644 (file)
index 0000000..83553bc
--- /dev/null
@@ -0,0 +1,69 @@
+From c3cce2e67bb22a223f5b8ef05db0fcde70994068 Mon Sep 17 00:00:00 2001
+From: Jacques Nilo <jnilo@free.fr>
+Date: Wed, 13 May 2026 15:30:23 +0200
+Subject: serial: core: introduce guard(uart_port_lock_check_sysrq_irqsave)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jacques Nilo <jnilo@free.fr>
+
+commit c3cce2e67bb22a223f5b8ef05db0fcde70994068 upstream.
+
+uart_handle_break() and uart_prepare_sysrq_char() (in
+include/linux/serial_core.h) capture a SysRq character into
+port->sysrq_ch while the port lock is held and rely on the unlock
+helper -- uart_unlock_and_check_sysrq_irqrestore() -- to dispatch the
+captured character to handle_sysrq() on scope exit.
+
+The existing guard(uart_port_lock_irqsave) cannot be used by IRQ
+handlers that process RX, because its destructor calls plain
+uart_port_unlock_irqrestore() and silently drops port->sysrq_ch.
+
+Add a dedicated guard(uart_port_lock_check_sysrq_irqsave) variant
+whose destructor is the sysrq-aware unlock helper. The lock side is
+identical to uart_port_lock_irqsave -- only the unlock-time behaviour
+differs. Callers that may capture SysRq characters must use
+guard(uart_port_lock_check_sysrq_irqsave); the existing
+guard(uart_port_lock_irqsave) keeps its current plain-unlock semantics
+for the many callers that do not process RX.
+
+The new macro is placed after the CONFIG_MAGIC_SYSRQ_SERIAL block so
+both definitions of uart_unlock_and_check_sysrq_irqrestore() (sysrq
+enabled and disabled) are visible at expansion time. When
+CONFIG_MAGIC_SYSRQ_SERIAL=n the destructor degenerates to plain
+uart_port_unlock_irqrestore(), so there is no overhead.
+
+No functional change on its own; users are converted in the following
+patches.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Jacques Nilo <jnilo@free.fr>
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Link: https://patch.msgid.link/3849af4bc55d5d2a424fa850844e94d641b2f8a6.1778675349.git.jnilo@free.fr
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/serial_core.h |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -1275,6 +1275,18 @@ static inline void uart_unlock_and_check
+ #endif        /* CONFIG_MAGIC_SYSRQ_SERIAL */
+ /*
++ * Variant of guard(uart_port_lock_irqsave) for IRQ handlers that may capture
++ * a SysRq character via uart_prepare_sysrq_char(). The destructor uses the
++ * sysrq-aware unlock helper so that a captured port->sysrq_ch is dispatched
++ * to handle_sysrq() on scope exit. The plain guard variant silently drops
++ * sysrq_ch and must not be used by callers that process RX.
++ */
++DEFINE_LOCK_GUARD_1(uart_port_lock_check_sysrq_irqsave, struct uart_port,
++                    uart_port_lock_irqsave(_T->lock, &_T->flags),
++                    uart_unlock_and_check_sysrq_irqrestore(_T->lock, _T->flags),
++                    unsigned long flags);
++
++/*
+  * We do the SysRQ and SAK checking like this...
+  */
+ static inline int uart_handle_break(struct uart_port *port)
diff --git a/queue-6.18/serial-dz-convert-to-use-a-platform-device.patch b/queue-6.18/serial-dz-convert-to-use-a-platform-device.patch
new file mode 100644 (file)
index 0000000..8093a18
--- /dev/null
@@ -0,0 +1,408 @@
+From 5d7a49d60b8fda66da60e240fd7315232fa1754f Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Wed, 6 May 2026 23:42:48 +0100
+Subject: serial: dz: Convert to use a platform device
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 5d7a49d60b8fda66da60e240fd7315232fa1754f upstream.
+
+Prevent a crash from happening as the first serial port is initialised:
+
+  Console: switching to colour frame buffer device 160x64
+  tgafb: SFB+ detected, rev=0x02
+  fb0: Digital ZLX-E1 frame buffer device at 0x1e000000
+  DECstation DZ serial driver version 1.04
+  CPU 0 Unable to handle kernel paging request at virtual address 000000bc, epc == 8048b3a4, ra == 80470a78
+  Oops[#1]:
+  CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.19.0-dirty #35 NONE
+  $ 0   : 00000000 1000ac00 00000004 804707ac
+  $ 4   : 00000000 80e20850 80e20858 81000030
+  $ 8   : 00000000 8072c81c 00000008 fefefeff
+  $12   : 6c616972 00000006 80c5917f 69726420
+  $16   : 80e20800 00000000 808f8968 80e20800
+  $20   : 00000000 807f5a90 808b0094 808d3bc8
+  $24   : 00000018 80479030
+  $28   : 80c2e000 80c2fd70 00000069 80470a78
+  Hi    : 00000004
+  Lo    : 00000000
+  epc   : 8048b3a4 __dev_fwnode+0x0/0xc
+  ra    : 80470a78 serial_base_ctrl_add+0xa0/0x168
+  Status: 1000ac04     IEp
+  Cause : 30000008 (ExcCode 02)
+  BadVA : 000000bc
+  PrId  : 00000220 (R3000)
+  Modules linked in:
+  Process swapper/0 (pid: 1, threadinfo=(ptrval), task=(ptrval), tls=00000000)
+  Stack : 00400044 00400040 8046f4cc 00000000 808a6148 808a0000 808f8968 8086983c
+          808e0000 8046fc84 1000ac01 00000028 80e20700 802ba3f8 80e20700 80d34a94
+          80c1b900 80e20700 80e20700 80e20700 80e20700 80444650 00000000 00000000
+          00000000 807f5a90 808b0094 80447080 00400040 808e0000 80d34a94 808a6148
+          80d34a94 00000004 80e20700 00000000 8076974c 80469810 80c2fe3c 1000ac01
+          ...
+  Call Trace:
+  [<8048b3a4>] __dev_fwnode+0x0/0xc
+  [<80470a78>] serial_base_ctrl_add+0xa0/0x168
+  [<8046fc84>] serial_core_register_port+0x1c8/0x974
+  [<808c6af0>] dz_init+0x74/0xc8
+  [<800470e0>] do_one_initcall+0x44/0x2d4
+  [<808b111c>] kernel_init_freeable+0x258/0x308
+  [<8072e434>] kernel_init+0x20/0x114
+  [<80049cd0>] ret_from_kernel_thread+0x14/0x1c
+
+  Code: 27bd0018  03e00008  2402ffea <8c8200bc> 03e00008  00000000  27bdffc0  afbe0038  afb30024
+
+  ---[ end trace 0000000000000000 ]---
+
+-- where a pointer is dereferenced that has been derived from a null
+pointer to the port's parent device.
+
+Since no device is available with legacy probing and it's not anymore a
+preferable way to discover devices anyway, switch the driver to using a
+platform device and use it as the port's parent device.  Update resource
+handling accordingly and only request the actual span of addresses used
+within the slot, which will have had its resource already requested by
+generic platform device code.
+
+Use platform_driver_probe() not just because the DZ device is fixed with
+solder on board and not straightforward to remove, but foremost because
+the associated TTY's major device number is the same as used by the zs
+driver and the first driver to claim it will prevent the other one from
+using it.  Either one DZ device or some SCC devices will be present in a
+given system but never both at a time, and therefore we want the major
+device number to be claimed by the first driver to actually successfully
+bind to its device and platform_driver_probe() is a way to fulfil that.
+
+An unfortunate consequence of the switch to a platform device is we now
+hand the console over from the bootconsole much later in the bootstrap.
+The firmware console handler appears good enough though to work so late
+and in particular with interrupts enabled.
+
+Conversely only starting the console port so late lets the reset code
+fully utilise our delay handlers, so switch from udelay() to fsleep()
+for transmitter draining so as to avoid busy-waiting for an excessive
+amount of time.
+
+Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Cc: stable@vger.kernel.org # needs to use .remove_new for <= 6.10
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062326540.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/mips/dec/platform.c |   55 +++++++++++++++++++++-
+ drivers/tty/serial/dz.c  |  116 ++++++++++++++++++++++-------------------------
+ 2 files changed, 110 insertions(+), 61 deletions(-)
+
+--- a/arch/mips/dec/platform.c
++++ b/arch/mips/dec/platform.c
+@@ -10,6 +10,13 @@
+ #include <linux/mc146818rtc.h>
+ #include <linux/platform_device.h>
++#include <asm/bootinfo.h>
++
++#include <asm/dec/interrupts.h>
++#include <asm/dec/kn01.h>
++#include <asm/dec/kn02.h>
++#include <asm/dec/system.h>
++
+ static struct resource dec_rtc_resources[] = {
+       {
+               .name = "rtc",
+@@ -30,11 +37,57 @@ static struct platform_device dec_rtc_de
+       .num_resources = ARRAY_SIZE(dec_rtc_resources),
+ };
++static struct resource dec_dz_resources[] = {
++      { .name = "dz", .flags = IORESOURCE_MEM, },
++      { .name = "dz", .flags = IORESOURCE_IRQ, },
++};
++
++static struct platform_device dec_dz_device = {
++      .name = "dz",
++      .id = PLATFORM_DEVID_NONE,
++      .resource = dec_dz_resources,
++      .num_resources = ARRAY_SIZE(dec_dz_resources),
++};
++
++static struct platform_device *dec_dz_devices[] __initdata = {
++      &dec_dz_device,
++};
++
+ static int __init dec_add_devices(void)
+ {
++      int ret1, ret2;
++      int num_dz;
++      int irq, i;
++
+       dec_rtc_resources[0].start = RTC_PORT(0);
+       dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1;
+-      return platform_device_register(&dec_rtc_device);
++
++      i = 0;
++      irq = dec_interrupt[DEC_IRQ_DZ11];
++      if (IS_ENABLED(CONFIG_32BIT) && irq >= 0) {
++              resource_size_t base;
++
++              switch (mips_machtype) {
++              case MACH_DS23100:
++              case MACH_DS5100:
++                      base = dec_kn_slot_base + KN01_DZ11;
++                      break;
++              default:
++                      base = dec_kn_slot_base + KN02_DZ11;
++                      break;
++              }
++              dec_dz_device.resource[0].start = base;
++              dec_dz_device.resource[0].end = base + dec_kn_slot_size - 1;
++              dec_dz_device.resource[1].start = irq;
++              dec_dz_device.resource[1].end = irq;
++              i++;
++      }
++      num_dz = i;
++
++      ret1 = platform_device_register(&dec_rtc_device);
++      ret2 = IS_ENABLED(CONFIG_32BIT) ?
++             platform_add_devices(dec_dz_devices, num_dz) : 0;
++      return ret1 ? ret1 : ret2;
+ }
+ device_initcall(dec_add_devices);
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -40,6 +40,7 @@
+ #include <linux/kernel.h>
+ #include <linux/major.h>
+ #include <linux/module.h>
++#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/sysrq.h>
+@@ -48,14 +49,6 @@
+ #include <linux/atomic.h>
+ #include <linux/io.h>
+-#include <asm/bootinfo.h>
+-
+-#include <asm/dec/interrupts.h>
+-#include <asm/dec/kn01.h>
+-#include <asm/dec/kn02.h>
+-#include <asm/dec/machtype.h>
+-#include <asm/dec/prom.h>
+-#include <asm/dec/system.h>
+ #include "dz.h"
+@@ -65,7 +58,9 @@ MODULE_LICENSE("GPL");
+ static char dz_name[] __initdata = "DECstation DZ serial driver version ";
+-static char dz_version[] __initdata = "1.04";
++static char dz_version[] __initdata = "1.05";
++
++#define DZ_IO_SIZE 0x20                       /* IOMEM space size.  */
+ struct dz_port {
+       struct dz_mux           *mux;
+@@ -81,6 +76,7 @@ struct dz_mux {
+ };
+ static struct dz_mux dz_mux;
++static struct uart_driver dz_reg;
+ static inline struct dz_port *to_dport(struct uart_port *uport)
+ {
+@@ -564,7 +560,7 @@ static void dz_reset(struct dz_port *dpo
+                       iob();
+                       udelay(2);              /* 1.4us TRDY recovery.  */
+               }
+-              udelay(1200);                   /* Transmitter drain.  */
++              fsleep(1200);                   /* Transmitter drain.  */
+       }
+       dz_out(dport, DZ_CSR, DZ_CLR);
+@@ -681,14 +677,13 @@ static void dz_release_port(struct uart_
+       map_guard = atomic_add_return(-1, &mux->map_guard);
+       if (!map_guard)
+-              release_mem_region(uport->mapbase, dec_kn_slot_size);
++              release_mem_region(uport->mapbase, DZ_IO_SIZE);
+ }
+ static int dz_map_port(struct uart_port *uport)
+ {
+       if (!uport->membase)
+-              uport->membase = ioremap(uport->mapbase,
+-                                               dec_kn_slot_size);
++              uport->membase = ioremap(uport->mapbase, DZ_IO_SIZE);
+       if (!uport->membase) {
+               printk(KERN_ERR "dz: Cannot map MMIO\n");
+               return -ENOMEM;
+@@ -704,8 +699,7 @@ static int dz_request_port(struct uart_p
+       map_guard = atomic_add_return(1, &mux->map_guard);
+       if (map_guard == 1) {
+-              if (!request_mem_region(uport->mapbase, dec_kn_slot_size,
+-                                      "dz")) {
++              if (!request_mem_region(uport->mapbase, DZ_IO_SIZE, "dz")) {
+                       atomic_add(-1, &mux->map_guard);
+                       printk(KERN_ERR
+                              "dz: Unable to reserve MMIO resource\n");
+@@ -716,7 +710,7 @@ static int dz_request_port(struct uart_p
+       if (ret) {
+               map_guard = atomic_add_return(-1, &mux->map_guard);
+               if (!map_guard)
+-                      release_mem_region(uport->mapbase, dec_kn_slot_size);
++                      release_mem_region(uport->mapbase, DZ_IO_SIZE);
+               return ret;
+       }
+       return 0;
+@@ -768,20 +762,15 @@ static const struct uart_ops dz_ops = {
+       .verify_port    = dz_verify_port,
+ };
+-static void __init dz_init_ports(void)
++static int __init dz_probe(struct platform_device *pdev)
+ {
+-      static int first = 1;
+-      unsigned long base;
++      struct resource *mem_resource, *irq_resource;
+       int line;
+-      if (!first)
+-              return;
+-      first = 0;
+-
+-      if (mips_machtype == MACH_DS23100 || mips_machtype == MACH_DS5100)
+-              base = dec_kn_slot_base + KN01_DZ11;
+-      else
+-              base = dec_kn_slot_base + KN02_DZ11;
++      mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      irq_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (!mem_resource || !irq_resource)
++              return -ENODEV;
+       for (line = 0; line < DZ_NB_PORT; line++) {
+               struct dz_port *dport = &dz_mux.dport[line];
+@@ -789,14 +778,33 @@ static void __init dz_init_ports(void)
+               dport->mux      = &dz_mux;
+-              uport->irq      = dec_interrupt[DEC_IRQ_DZ11];
++              uport->dev      = &pdev->dev;
++              uport->irq      = irq_resource->start;
+               uport->fifosize = 1;
+               uport->iotype   = UPIO_MEM;
+               uport->flags    = UPF_BOOT_AUTOCONF;
+               uport->ops      = &dz_ops;
+               uport->line     = line;
+-              uport->mapbase  = base;
++              uport->mapbase  = mem_resource->start;
+               uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_DZ_CONSOLE);
++
++              if (uart_add_one_port(&dz_reg, uport))
++                      uport->dev = NULL;
++      }
++
++      return 0;
++}
++
++static void __exit dz_remove(struct platform_device *pdev)
++{
++      int line;
++
++      for (line = DZ_NB_PORT - 1; line >= 0; line--) {
++              struct dz_port *dport = &dz_mux.dport[line];
++              struct uart_port *uport = &dport->port;
++
++              if (uport->dev)
++                      uart_remove_one_port(&dz_reg, uport);
+       }
+ }
+@@ -879,21 +887,14 @@ static int __init dz_console_setup(struc
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+-      int ret;
+-
+-      ret = dz_map_port(uport);
+-      if (ret)
+-              return ret;
+-
+-      dz_reset(dport);
++      if (!dport->mux)
++              return -ENODEV;
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+-
+-      return uart_set_options(&dport->port, co, baud, parity, bits, flow);
++      return uart_set_options(uport, co, baud, parity, bits, flow);
+ }
+-static struct uart_driver dz_reg;
+ static struct console dz_console = {
+       .name   = "ttyS",
+       .write  = dz_console_print,
+@@ -904,18 +905,6 @@ static struct console dz_console = {
+       .data   = &dz_reg,
+ };
+-static int __init dz_serial_console_init(void)
+-{
+-      if (!IOASIC) {
+-              dz_init_ports();
+-              register_console(&dz_console);
+-              return 0;
+-      } else
+-              return -ENXIO;
+-}
+-
+-console_initcall(dz_serial_console_init);
+-
+ #define SERIAL_DZ_CONSOLE     &dz_console
+ #else
+ #define SERIAL_DZ_CONSOLE     NULL
+@@ -931,25 +920,32 @@ static struct uart_driver dz_reg = {
+       .cons                   = SERIAL_DZ_CONSOLE,
+ };
++static struct platform_driver dz_driver = {
++      .remove = __exit_p(dz_remove),
++      .driver = { .name = "dz" },
++};
++
+ static int __init dz_init(void)
+ {
+-      int ret, i;
+-
+-      if (IOASIC)
+-              return -ENXIO;
++      int ret;
+       printk("%s%s\n", dz_name, dz_version);
+-      dz_init_ports();
+-
+       ret = uart_register_driver(&dz_reg);
+       if (ret)
+               return ret;
++      ret = platform_driver_probe(&dz_driver, dz_probe);
++      if (ret)
++              uart_unregister_driver(&dz_reg);
+-      for (i = 0; i < DZ_NB_PORT; i++)
+-              uart_add_one_port(&dz_reg, &dz_mux.dport[i].port);
++      return ret;
++}
+-      return 0;
++static void __exit dz_exit(void)
++{
++      platform_driver_unregister(&dz_driver);
++      uart_unregister_driver(&dz_reg);
+ }
+ module_init(dz_init);
++module_exit(dz_exit);
diff --git a/queue-6.18/serial-dz-fix-bootconsole-handover-lockup.patch b/queue-6.18/serial-dz-fix-bootconsole-handover-lockup.patch
new file mode 100644 (file)
index 0000000..486de1b
--- /dev/null
@@ -0,0 +1,98 @@
+From 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Wed, 6 May 2026 23:42:35 +0100
+Subject: serial: dz: Fix bootconsole handover lockup
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 upstream.
+
+Calling dz_reset() in the course of setting up the serial device causes
+line parameters to be reset and the transmitter disabled.  We've been
+lucky in that no message is usually produced to the kernel log between
+this call and the later call to uart_set_options() in the course of
+console setup done by dz_serial_console_init(), or the system would hang
+as the console output handler in the firmware tried to access a port the
+transmitter of which has been disabled and line parameters messed up.
+
+This will change with the next change to the driver, so fix dz_reset()
+such that line parameters are set for 9600n8 console operation as with
+the system firmware and the transmitter re-enabled after reset.  This
+also means dz_pm() serves no purpose anymore, so drop it.
+
+Fixes: e6ee512f5a77 ("dz.c: Resource management")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Cc: stable@vger.kernel.org # v2.6.25+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062302010.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/dz.c |   36 ++++++++++++------------------------
+ 1 file changed, 12 insertions(+), 24 deletions(-)
+
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -571,6 +571,18 @@ static void dz_reset(struct dz_port *dpo
+       while (dz_in(dport, DZ_CSR) & DZ_CLR);
+       iob();
++      /*
++       * Set parameters across all lines such as not to interfere
++       * with the initial PROM-based console.  Otherwise any output
++       * produced before the console handover would cause the system
++       * firmware to produce rubbish.
++       */
++      for (int line = 0; line < DZ_NB_PORT; line++)
++              dz_out(dport, DZ_LPR, DZ_B9600 | DZ_CS8 | line);
++
++      /* Re-enable transmission for the initial PROM-based console.  */
++      dz_out(dport, DZ_TCR, tcr);
++
+       /* Enable scanning.  */
+       dz_out(dport, DZ_CSR, DZ_MSE);
+@@ -654,26 +666,6 @@ static void dz_set_termios(struct uart_p
+       uart_port_unlock_irqrestore(&dport->port, flags);
+ }
+-/*
+- * Hack alert!
+- * Required solely so that the initial PROM-based console
+- * works undisturbed in parallel with this one.
+- */
+-static void dz_pm(struct uart_port *uport, unsigned int state,
+-                unsigned int oldstate)
+-{
+-      struct dz_port *dport = to_dport(uport);
+-      unsigned long flags;
+-
+-      uart_port_lock_irqsave(&dport->port, &flags);
+-      if (state < 3)
+-              dz_start_tx(&dport->port);
+-      else
+-              dz_stop_tx(&dport->port);
+-      uart_port_unlock_irqrestore(&dport->port, flags);
+-}
+-
+-
+ static const char *dz_type(struct uart_port *uport)
+ {
+       return "DZ";
+@@ -769,7 +761,6 @@ static const struct uart_ops dz_ops = {
+       .startup        = dz_startup,
+       .shutdown       = dz_shutdown,
+       .set_termios    = dz_set_termios,
+-      .pm             = dz_pm,
+       .type           = dz_type,
+       .release_port   = dz_release_port,
+       .request_port   = dz_request_port,
+@@ -894,10 +885,7 @@ static int __init dz_console_setup(struc
+       if (ret)
+               return ret;
+-      spin_lock_init(&dport->port.lock);      /* For dz_pm().  */
+-
+       dz_reset(dport);
+-      dz_pm(uport, 0, -1);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
diff --git a/queue-6.18/serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch b/queue-6.18/serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch
new file mode 100644 (file)
index 0000000..285c07c
--- /dev/null
@@ -0,0 +1,71 @@
+From ca904f4b42355287bc5ce8b7550ebe909cda4c2c Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Wed, 6 May 2026 23:42:31 +0100
+Subject: serial: dz: Fix bootconsole message clobbering at chip reset
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit ca904f4b42355287bc5ce8b7550ebe909cda4c2c upstream.
+
+In the DZ interface as implemented by the DC7085 gate array the serial
+transmitters are double buffered, meaning that at the time a transmitter
+is ready to accept the next character there is one in the transmit shift
+register still being sent to the line.  Issuing a master clear at this
+time causes this character to be lost, so wait an extra amount of time
+sufficient for the transmit shift register to drain at 9600bps, which is
+the baud rate setting used by the firmware console.
+
+Mind the specified 1.4us TRDY recovery time in the course and continue
+using iob() as the completion barrier, since the platforms involved use
+a write buffer that can delay and combine writes, and reorder them with
+respect to reads regardless of the MMIO locations accessed and we still
+lack a platform-independent handler for that.
+
+When called from dz_serial_console_init() this is too early for fsleep()
+to work and even before lpj has been calculated and therefore the delay
+is actually not sufficient for the transmitter to drain and is merely a
+placeholder now.  This will be addressed in a follow-up change.
+
+Fixes: e6ee512f5a77 ("dz.c: Resource management")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Cc: stable@vger.kernel.org # v2.6.25+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062259080.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/dz.c |   21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+--- a/drivers/tty/serial/dz.c
++++ b/drivers/tty/serial/dz.c
+@@ -542,10 +542,31 @@ static int dz_encode_baud_rate(unsigned
+ static void dz_reset(struct dz_port *dport)
+ {
+       struct dz_mux *mux = dport->mux;
++      unsigned short tcr;
++      int loops = 10000;
+       if (mux->initialised)
+               return;
++      tcr = dz_in(dport, DZ_TCR);
++
++      /* Do not disturb any ongoing transmissions.  */
++      if (dz_in(dport, DZ_CSR) & DZ_MSE) {
++              unsigned short csr, mask;
++
++              mask = tcr;
++              while ((mask & DZ_LNENB) && loops--) {
++                      csr = dz_in(dport, DZ_CSR);
++                      if (!(csr & DZ_TRDY))
++                              continue;
++                      mask &= ~(1 << ((csr & DZ_TLINE) >> 8));
++                      dz_out(dport, DZ_TCR, mask);
++                      iob();
++                      udelay(2);              /* 1.4us TRDY recovery.  */
++              }
++              udelay(1200);                   /* Transmitter drain.  */
++      }
++
+       dz_out(dport, DZ_CSR, DZ_CLR);
+       while (dz_in(dport, DZ_CSR) & DZ_CLR);
+       iob();
diff --git a/queue-6.18/serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch b/queue-6.18/serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch
new file mode 100644 (file)
index 0000000..7e99982
--- /dev/null
@@ -0,0 +1,90 @@
+From 9a9254c4a2a3ca2b3da16d173f3b0dd01f397ff6 Mon Sep 17 00:00:00 2001
+From: Shitalkumar Gandhi <shital.gandhi45@gmail.com>
+Date: Mon, 20 Apr 2026 19:29:03 +0530
+Subject: serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma
+
+From: Shitalkumar Gandhi <shital.gandhi45@gmail.com>
+
+commit 9a9254c4a2a3ca2b3da16d173f3b0dd01f397ff6 upstream.
+
+lpuart_start_rx_dma() allocates sport->rx_ring.buf with kzalloc() and
+then maps a scatterlist via dma_map_sg().  On three subsequent error
+paths the function returns directly without releasing those resources:
+
+  - when dma_map_sg() returns 0 (-EINVAL):
+      ring->buf is leaked.
+  - when dmaengine_slave_config() fails:
+      ring->buf and the DMA mapping are leaked.
+  - when dmaengine_prep_dma_cyclic() returns NULL:
+      ring->buf and the DMA mapping are leaked.
+
+The sole cleanup path, lpuart_dma_rx_free(), is only reached when
+lpuart_dma_rx_use is set, and the caller lpuart_rx_dma_startup() clears
+that flag on failure of lpuart_start_rx_dma().  So these resources are
+permanently leaked on every failure in this function.  Repeated port
+open/close or termios changes under error conditions will slowly consume
+memory and leave stale streaming DMA mappings behind.
+
+Fix it by introducing two error labels that unmap the scatterlist and
+free the ring buffer as appropriate.  While here, replace the misleading
+-EFAULT (bad userspace pointer) returned when dmaengine_prep_dma_cyclic()
+fails with the more accurate -ENOMEM, matching how other dmaengine users
+in the tree treat this failure.
+
+No functional change on the success path.
+
+Fixes: 5887ad43ee02 ("tty: serial: fsl_lpuart: Use cyclic DMA for Rx")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Shitalkumar Gandhi <shitalkumar.gandhi@cambiumnetworks.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Link: https://patch.msgid.link/20260420135903.2062024-1-shitalkumar.gandhi@cambiumnetworks.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/fsl_lpuart.c |   15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -1379,7 +1379,8 @@ static inline int lpuart_start_rx_dma(st
+       if (!nent) {
+               dev_err(sport->port.dev, "DMA Rx mapping error\n");
+-              return -EINVAL;
++              ret = -EINVAL;
++              goto err_free_buf;
+       }
+       dma_rx_sconfig.src_addr = lpuart_dma_datareg_addr(sport);
+@@ -1391,7 +1392,7 @@ static inline int lpuart_start_rx_dma(st
+       if (ret < 0) {
+               dev_err(sport->port.dev,
+                               "DMA Rx slave config failed, err = %d\n", ret);
+-              return ret;
++              goto err_unmap_sg;
+       }
+       sport->dma_rx_desc = dmaengine_prep_dma_cyclic(chan,
+@@ -1402,7 +1403,8 @@ static inline int lpuart_start_rx_dma(st
+                                DMA_PREP_INTERRUPT);
+       if (!sport->dma_rx_desc) {
+               dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
+-              return -EFAULT;
++              ret = -ENOMEM;
++              goto err_unmap_sg;
+       }
+       sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+@@ -1426,6 +1428,13 @@ static inline int lpuart_start_rx_dma(st
+       }
+       return 0;
++
++err_unmap_sg:
++      dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
++err_free_buf:
++      kfree(ring->buf);
++      ring->buf = NULL;
++      return ret;
+ }
+ static void lpuart_dma_rx_free(struct uart_port *port)
diff --git a/queue-6.18/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch b/queue-6.18/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
new file mode 100644 (file)
index 0000000..bc8a0e6
--- /dev/null
@@ -0,0 +1,37 @@
+From ca2584d841b69391ffc4144840563d2e1a0018df Mon Sep 17 00:00:00 2001
+From: Prasanna S <prasanna.s@oss.qualcomm.com>
+Date: Tue, 28 Apr 2026 09:56:13 +0530
+Subject: serial: qcom-geni: fix UART_RX_PAR_EN bit position
+
+From: Prasanna S <prasanna.s@oss.qualcomm.com>
+
+commit ca2584d841b69391ffc4144840563d2e1a0018df upstream.
+
+UART_RX_PAR_EN is incorrectly defined as bit 3, which triggers false
+framing errors (S_GP_IRQ_1_EN) and causes received data to be dropped
+when parity is enabled and the parity bit is 0.
+
+Define UART_RX_PAR_EN as bit 4 of the SE_UART_RX_TRANS_CFG register, as
+specified in the reference manual.
+
+Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Prasanna S <prasanna.s@oss.qualcomm.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260428-serial-bit-correct-v1-1-9131ad5b97d8@oss.qualcomm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -49,7 +49,7 @@
+ #define TX_STOP_BIT_LEN_2             2
+ /* SE_UART_RX_TRANS_CFG */
+-#define UART_RX_PAR_EN                        BIT(3)
++#define UART_RX_PAR_EN                        BIT(4)
+ /* SE_UART_RX_WORD_LEN */
+ #define RX_WORD_LEN_MASK              GENMASK(9, 0)
diff --git a/queue-6.18/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch b/queue-6.18/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch
new file mode 100644 (file)
index 0000000..4eb0932
--- /dev/null
@@ -0,0 +1,64 @@
+From 452d6fa37ae9b021f4f6d397dbae077f7296f6f4 Mon Sep 17 00:00:00 2001
+From: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
+Date: Wed, 6 May 2026 10:15:21 +0530
+Subject: serial: qcom_geni: fix kfifo underflow when flush precedes DMA completion IRQ
+
+From: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
+
+commit 452d6fa37ae9b021f4f6d397dbae077f7296f6f4 upstream.
+
+When uart_flush_buffer() runs before the DMA completion IRQ is delivered,
+the following race can occur (all steps serialized by uart_port_lock):
+
+  1. DMA starts: tx_remaining = N, kfifo contains N bytes
+  2. DMA completes in hardware; IRQ is pending but not yet delivered
+  3. uart_flush_buffer() acquires the port lock and calls kfifo_reset(),
+     making kfifo_len() = 0 while tx_remaining remains N
+  4. uart_flush_buffer() releases the port lock
+  5. DMA IRQ fires; handle_tx_dma() acquires the port lock and calls
+     uart_xmit_advance(uport, tx_remaining) on an empty kfifo
+
+uart_xmit_advance() increments kfifo->out by tx_remaining. Since
+kfifo_reset() already set both in and out to 0, out wraps past in,
+causing kfifo_len() to return UART_XMIT_SIZE - tx_remaining. The next
+start_tx_dma() call then submits a DMA transfer of stale buffer data.
+
+Fix this by snapshotting kfifo_len() at the start of handle_tx_dma()
+and skipping uart_xmit_advance() when fifo_len < tx_remaining, which
+indicates the kfifo was reset by a preceding flush.
+
+Fixes: 2aaa43c70778 ("tty: serial: qcom-geni-serial: add support for serial engine DMA")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
+Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Link: https://patch.msgid.link/20260506-serial-dma-stale-tx-buf-v1-1-e3ccb360d719@oss.qualcomm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c |   14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -1022,8 +1022,20 @@ static void qcom_geni_serial_handle_tx_d
+ {
+       struct qcom_geni_serial_port *port = to_dev_port(uport);
+       struct tty_port *tport = &uport->state->port;
++      unsigned int fifo_len = kfifo_len(&tport->xmit_fifo);
++
++      /*
++       * Only advance the kfifo if it still contains the bytes that were
++       * transferred. uart_flush_buffer() may have run before this IRQ
++       * fired: it calls kfifo_reset() under the port lock, making
++       * fifo_len = 0 while tx_remaining remains non-zero. Calling
++       * uart_xmit_advance() in that case would underflow kfifo->out past
++       * kfifo->in, making kfifo_len() wrap to UART_XMIT_SIZE - tx_remaining
++       * and triggering a spurious large DMA transfer of stale data.
++       */
++      if (fifo_len >= port->tx_remaining)
++              uart_xmit_advance(uport, port->tx_remaining);
+-      uart_xmit_advance(uport, port->tx_remaining);
+       geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining);
+       port->tx_dma_addr = 0;
+       port->tx_remaining = 0;
diff --git a/queue-6.18/serial-sh-sci-fix-memory-region-release-in-error-path.patch b/queue-6.18/serial-sh-sci-fix-memory-region-release-in-error-path.patch
new file mode 100644 (file)
index 0000000..112a2e0
--- /dev/null
@@ -0,0 +1,40 @@
+From 92b1ea22454b08a39baef3a7290fb3ec50366616 Mon Sep 17 00:00:00 2001
+From: Hongling Zeng <zenghongling@kylinos.cn>
+Date: Tue, 21 Apr 2026 14:57:37 +0800
+Subject: serial: sh-sci: fix memory region release in error path
+
+From: Hongling Zeng <zenghongling@kylinos.cn>
+
+commit 92b1ea22454b08a39baef3a7290fb3ec50366616 upstream.
+
+The sci_request_port() function uses request_mem_region() to reserve
+I/O memory, but in the error path when sci_remap_port() fails, it
+incorrectly calls release_resource() instead of release_mem_region().
+
+This mismatch can cause resource accounting issues. Fix it by using
+the correct release function, consistent with sci_release_port().
+
+Fixes: e2651647080930a1 ("serial: sh-sci: Handle port memory region reservations.")
+Cc: stable <stable@kernel.org>
+Reported-by: kernel test robot <lkp@intel.com>
+Reported-by: Dan Carpenter <error27@gmail.com>
+Closes: https://lore.kernel.org/r/202604032356.SzEjYkBC-lkp@intel.com/
+Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Link: https://patch.msgid.link/20260421065737.724187-1-zenghongling@kylinos.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/sh-sci.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/serial/sh-sci.c
++++ b/drivers/tty/serial/sh-sci.c
+@@ -2845,7 +2845,7 @@ int sci_request_port(struct uart_port *p
+       ret = sci_remap_port(port);
+       if (unlikely(ret != 0)) {
+-              release_resource(res);
++              release_mem_region(port->mapbase, sport->reg_size);
+               return ret;
+       }
diff --git a/queue-6.18/serial-zs-convert-to-use-a-platform-device.patch b/queue-6.18/serial-zs-convert-to-use-a-platform-device.patch
new file mode 100644 (file)
index 0000000..4e5863b
--- /dev/null
@@ -0,0 +1,478 @@
+From 7cac59d08a73cb866ec51a483a6f3fe0f531947c Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Wed, 6 May 2026 23:42:52 +0100
+Subject: serial: zs: Convert to use a platform device
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 7cac59d08a73cb866ec51a483a6f3fe0f531947c upstream.
+
+Prevent a crash from happening as the first serial port is initialised:
+
+  Console: switching to mono frame buffer device 160x64
+  fb0: PMAG-AA frame buffer device at tc0
+  DECstation Z85C30 serial driver version 0.10
+  CPU 0 Unable to handle kernel paging request at virtual address 0000002c, epc == 803ab00c, ra == 803aafe0
+  Oops[#1]:
+  CPU: 0 PID: 1 Comm: swapper Not tainted 6.4.0-rc3-00031-g84a9582fd203-dirty #57
+  $ 0   : 00000000 10012c00 803aaeb0 00000000
+  $ 4   : 80e12f60 80e12f50 80e12f58 81000030
+  $ 8   : 00000000 805ff37c 00000000 33433538
+  $12   : 65732030 00000006 80c2915d 6c616972
+  $16   : 80e12f00 807b7630 00000000 00000000
+  $20   : 00000004 00000348 000001a0 807623b8
+  $24   : 00000018 00000000
+  $28   : 80c24000 80c25d60 8078b148 803aafe0
+  Hi    : 00000000
+  Lo    : 00000000
+  epc   : 803ab00c serial_base_ctrl_add+0x78/0xf4
+  ra    : 803aafe0 serial_base_ctrl_add+0x4c/0xf4
+  Status: 10012c03     KERNEL EXL IE
+  Cause : 00000008 (ExcCode 02)
+  BadVA : 0000002c
+  PrId  : 00000440 (R4400SC)
+  Modules linked in:
+  Process swapper (pid: 1, threadinfo=(ptrval), task=(ptrval), tls=00000000)
+  Stack : 80760000 00000cc0 00400044 00400040 803aa02c 80d61ab8 00000000 807b7630
+          80760000 807623b8 807b7628 803aa644 80386998 00000000 80e17780 80220f68
+          80e17780 80d61ab8 80c17d80 80e17780 80e17780 8063c798 80e17780 80383fa0
+          00000010 80e17780 00000000 80386998 807a0000 00000000 00400040 8038f848
+          807623b8 80d61ab8 00000004 80e17780 00000000 803a68e4 80c25e2c 803bb884
+          ...
+  Call Trace:
+  [<803ab00c>] serial_base_ctrl_add+0x78/0xf4
+  [<803aa644>] serial_core_register_port+0x174/0x69c
+  [<8077e9ac>] zs_init+0xc8/0xfc
+  [<800404d4>] do_one_initcall+0x40/0x2ac
+  [<8076cecc>] kernel_init_freeable+0x1e4/0x270
+  [<80605bec>] kernel_init+0x20/0x108
+  [<800431e8>] ret_from_kernel_thread+0x14/0x1c
+
+  Code: 2442aeb0  ae120024  ae0200d0 <8c67002c> 50e00001  8c670000  3c06806e  3c05806e  afb30010
+
+  ---[ end trace 0000000000000000 ]---
+
+(report at the offending commit) -- where a pointer is dereferenced that
+has been derived from a null pointer to the port's parent device.
+
+Since no device is available with legacy probing and it's not anymore a
+preferable way to discover devices anyway, switch the driver to using a
+platform device and use it as the port's parent device.  Update resource
+handling accordingly and only request the actual span of addresses used
+within the slot, which will have had its resource already requested by
+generic platform device code.
+
+Use platform_driver_probe() not just because SCC devices are fixed with
+solder on board and not straightforward to remove, but foremost because
+the associated TTY's major device number is the same as used by the dz
+driver and the first driver to claim it will prevent the other one from
+using it.  Either one DZ device or some SCC devices will be present in a
+given system but never both at a time, and therefore we want the major
+device number to be claimed by the first driver to actually successfully
+bind to its device and platform_driver_probe() is a way to fulfil that.
+
+An unfortunate consequence of the switch to a platform device is we now
+hand the console over from the bootconsole much later in the bootstrap.
+The firmware console handler appears good enough though to work so late
+and in particular with interrupts enabled.
+
+Since there is one way only remaining to reach zs_reset() now, remove
+the port initialisation marker as no longer needed and go through the
+channel reset unconditionally.
+
+Fixes: 84a9582fd203 ("serial: core: Start managing serial controllers to enable runtime PM")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Cc: stable@vger.kernel.org # needs to use .remove_new for <= 6.10
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062328480.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/mips/dec/platform.c |   60 ++++++++++++++
+ drivers/tty/serial/zs.c  |  190 +++++++++++++++++------------------------------
+ drivers/tty/serial/zs.h  |    1 
+ 3 files changed, 128 insertions(+), 123 deletions(-)
+
+--- a/arch/mips/dec/platform.c
++++ b/arch/mips/dec/platform.c
+@@ -13,6 +13,7 @@
+ #include <asm/bootinfo.h>
+ #include <asm/dec/interrupts.h>
++#include <asm/dec/ioasic_addrs.h>
+ #include <asm/dec/kn01.h>
+ #include <asm/dec/kn02.h>
+ #include <asm/dec/system.h>
+@@ -53,10 +54,37 @@ static struct platform_device *dec_dz_de
+       &dec_dz_device,
+ };
++static struct resource dec_zs_resources[][2] = {
++      {
++              { .name = "scc0", .flags = IORESOURCE_MEM, },
++              { .name = "scc0", .flags = IORESOURCE_IRQ, },
++      },
++      {
++              { .name = "scc1", .flags = IORESOURCE_MEM, },
++              { .name = "scc1", .flags = IORESOURCE_IRQ, },
++      },
++};
++
++static struct platform_device dec_zs_device[] = {
++      {
++              .name = "zs",
++              .id = 0,
++              .resource = dec_zs_resources[0],
++              .num_resources = ARRAY_SIZE(dec_zs_resources[0]),
++      },
++      {
++              .name = "zs",
++              .id = 1,
++              .resource = dec_zs_resources[1],
++              .num_resources = ARRAY_SIZE(dec_zs_resources[1]),
++      },
++};
++
+ static int __init dec_add_devices(void)
+ {
+-      int ret1, ret2;
+-      int num_dz;
++      struct platform_device *dec_zs_devices[ARRAY_SIZE(dec_zs_device)];
++      int ret1, ret2, ret3;
++      int num_dz, num_zs;
+       int irq, i;
+       dec_rtc_resources[0].start = RTC_PORT(0);
+@@ -84,10 +112,36 @@ static int __init dec_add_devices(void)
+       }
+       num_dz = i;
++      i = 0;
++      irq = dec_interrupt[DEC_IRQ_SCC0];
++      if (irq >= 0) {
++              resource_size_t base = dec_kn_slot_base + IOASIC_SCC0;
++
++              dec_zs_device[i].resource[0].start = base;
++              dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
++              dec_zs_device[i].resource[1].start = irq;
++              dec_zs_device[i].resource[1].end = irq;
++              dec_zs_devices[i] = &dec_zs_device[i];
++              i++;
++      }
++      irq = dec_interrupt[DEC_IRQ_SCC1];
++      if (irq >= 0) {
++              resource_size_t base = dec_kn_slot_base + IOASIC_SCC1;
++
++              dec_zs_device[i].resource[0].start = base;
++              dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
++              dec_zs_device[i].resource[1].start = irq;
++              dec_zs_device[i].resource[1].end = irq;
++              dec_zs_devices[i] = &dec_zs_device[i];
++              i++;
++      }
++      num_zs = i;
++
+       ret1 = platform_device_register(&dec_rtc_device);
+       ret2 = IS_ENABLED(CONFIG_32BIT) ?
+              platform_add_devices(dec_dz_devices, num_dz) : 0;
+-      return ret1 ? ret1 : ret2;
++      ret3 = platform_add_devices(dec_zs_devices, num_zs);
++      return ret1 ? ret1 : ret2 ? ret2 : ret3;
+ }
+ device_initcall(dec_add_devices);
+--- a/drivers/tty/serial/zs.c
++++ b/drivers/tty/serial/zs.c
+@@ -56,6 +56,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/major.h>
++#include <linux/platform_device.h>
+ #include <linux/serial.h>
+ #include <linux/serial_core.h>
+ #include <linux/spinlock.h>
+@@ -66,10 +67,6 @@
+ #include <linux/atomic.h>
+-#include <asm/dec/interrupts.h>
+-#include <asm/dec/ioasic_addrs.h>
+-#include <asm/dec/system.h>
+-
+ #include "zs.h"
+@@ -79,7 +76,7 @@ MODULE_LICENSE("GPL");
+ static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+-static char zs_version[] __initdata = "0.10";
++static char zs_version[] __initdata = "0.11";
+ /*
+  * It would be nice to dynamically allocate everything that
+@@ -98,12 +95,8 @@ static char zs_version[] __initdata = "0
+ #define to_zport(uport) container_of(uport, struct zs_port, port)
+-struct zs_parms {
+-      resource_size_t scc[ZS_NUM_SCCS];
+-      int irq[ZS_NUM_SCCS];
+-};
+-
+ static struct zs_scc zs_sccs[ZS_NUM_SCCS];
++static struct uart_driver zs_reg;
+ /*
+  * Set parameters in WR5, WR12, WR13 such as not to interfere
+@@ -839,16 +832,15 @@ static void zs_reset(struct zs_port *zpo
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+-      if (!zport->initialised) {
+-              /* Reset the pointer first, just in case...  */
+-              read_zsreg(zport, R0);
+-              /* And let the current transmission finish.  */
+-              zs_line_drain(zport, irq);
+-              write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB);
+-              udelay(10);
+-              write_zsreg(zport, R9, 0);
+-              zport->initialised = 1;
+-      }
++
++      /* Reset the pointer first, just in case...  */
++      read_zsreg(zport, R0);
++      /* And let the current transmission finish.  */
++      zs_line_drain(zport, irq);
++      write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB);
++      udelay(10);
++      write_zsreg(zport, R9, 0);
++
+       load_zsregs(zport, zport->regs, irq);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+ }
+@@ -1055,63 +1047,62 @@ static const struct uart_ops zs_ops = {
+ /*
+  * Initialize Z85C30 port structures.
+  */
+-static int __init zs_probe_sccs(void)
++static int __init zs_probe(struct platform_device *pdev)
+ {
+-      static int probed;
+-      struct zs_parms zs_parms;
+-      int chip, side, irq;
+-      int n_chips = 0;
++      struct resource *mem_resource, *irq_resource;
++      int chip, side;
+       int i;
+-      if (probed)
+-              return 0;
++      mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      irq_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (!mem_resource || !irq_resource)
++              return -ENODEV;
++
++      chip = pdev->id;
++      spin_lock_init(&zs_sccs[chip].zlock);
++      for (side = 0; side < ZS_NUM_CHAN; side++) {
++              struct zs_port *zport = &zs_sccs[chip].zport[side];
++              struct uart_port *uport = &zport->port;
+-      irq = dec_interrupt[DEC_IRQ_SCC0];
+-      if (irq >= 0) {
+-              zs_parms.scc[n_chips] = IOASIC_SCC0;
+-              zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+-              n_chips++;
+-      }
+-      irq = dec_interrupt[DEC_IRQ_SCC1];
+-      if (irq >= 0) {
+-              zs_parms.scc[n_chips] = IOASIC_SCC1;
+-              zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+-              n_chips++;
+-      }
+-      if (!n_chips)
+-              return -ENXIO;
+-
+-      probed = 1;
+-
+-      for (chip = 0; chip < n_chips; chip++) {
+-              spin_lock_init(&zs_sccs[chip].zlock);
+-              for (side = 0; side < ZS_NUM_CHAN; side++) {
+-                      struct zs_port *zport = &zs_sccs[chip].zport[side];
+-                      struct uart_port *uport = &zport->port;
+-
+-                      zport->scc      = &zs_sccs[chip];
+-                      zport->clk_mode = 16;
+-
+-                      uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_ZS_CONSOLE);
+-                      uport->irq      = zs_parms.irq[chip];
+-                      uport->uartclk  = ZS_CLOCK;
+-                      uport->fifosize = 1;
+-                      uport->iotype   = UPIO_MEM;
+-                      uport->flags    = UPF_BOOT_AUTOCONF;
+-                      uport->ops      = &zs_ops;
+-                      uport->line     = chip * ZS_NUM_CHAN + side;
+-                      uport->mapbase  = dec_kn_slot_base +
+-                                        zs_parms.scc[chip] +
+-                                        (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
++              zport->scc      = &zs_sccs[chip];
++              zport->clk_mode = 16;
+-                      for (i = 0; i < ZS_NUM_REGS; i++)
+-                              zport->regs[i] = zs_init_regs[i];
+-              }
++              uport->dev      = &pdev->dev;
++              uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_ZS_CONSOLE);
++              uport->irq      = irq_resource->start;
++              uport->uartclk  = ZS_CLOCK;
++              uport->fifosize = 1;
++              uport->iotype   = UPIO_MEM;
++              uport->flags    = UPF_BOOT_AUTOCONF;
++              uport->ops      = &zs_ops;
++              uport->line     = chip * ZS_NUM_CHAN + side;
++              uport->mapbase  = mem_resource->start +
++                                (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
++
++              for (i = 0; i < ZS_NUM_REGS; i++)
++                      zport->regs[i] = zs_init_regs[i];
++
++              if (uart_add_one_port(&zs_reg, uport))
++                      uport->dev = NULL;
+       }
+       return 0;
+ }
++static void __exit zs_remove(struct platform_device *pdev)
++{
++      int chip, side;
++
++      chip = pdev->id;
++      for (side = ZS_NUM_CHAN - 1; side >= 0; side--) {
++              struct zs_port *zport = &zs_sccs[chip].zport[side];
++              struct uart_port *uport = &zport->port;
++
++              if (uport->dev)
++                      uart_remove_one_port(&zs_reg, uport);
++      }
++}
++
+ #ifdef CONFIG_SERIAL_ZS_CONSOLE
+ static void zs_console_putchar(struct uart_port *uport, unsigned char ch)
+@@ -1192,20 +1183,14 @@ static int __init zs_console_setup(struc
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+-      int ret;
+-
+-      ret = zs_map_port(uport);
+-      if (ret)
+-              return ret;
+-
+-      zs_reset(zport);
++      if (!zport->scc)
++              return -ENODEV;
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       return uart_set_options(uport, co, baud, parity, bits, flow);
+ }
+-static struct uart_driver zs_reg;
+ static struct console zs_console = {
+       .name   = "ttyS",
+       .write  = zs_console_write,
+@@ -1216,23 +1201,6 @@ static struct console zs_console = {
+       .data   = &zs_reg,
+ };
+-/*
+- *    Register console.
+- */
+-static int __init zs_serial_console_init(void)
+-{
+-      int ret;
+-
+-      ret = zs_probe_sccs();
+-      if (ret)
+-              return ret;
+-      register_console(&zs_console);
+-
+-      return 0;
+-}
+-
+-console_initcall(zs_serial_console_init);
+-
+ #define SERIAL_ZS_CONSOLE     &zs_console
+ #else
+ #define SERIAL_ZS_CONSOLE     NULL
+@@ -1248,47 +1216,31 @@ static struct uart_driver zs_reg = {
+       .cons                   = SERIAL_ZS_CONSOLE,
+ };
++static struct platform_driver zs_driver = {
++      .remove = __exit_p(zs_remove),
++      .driver = { .name = "zs" },
++};
++
+ /* zs_init inits the driver. */
+ static int __init zs_init(void)
+ {
+-      int i, ret;
++      int ret;
+       pr_info("%s%s\n", zs_name, zs_version);
+-      /* Find out how many Z85C30 SCCs we have.  */
+-      ret = zs_probe_sccs();
+-      if (ret)
+-              return ret;
+-
+       ret = uart_register_driver(&zs_reg);
+       if (ret)
+               return ret;
++      ret = platform_driver_probe(&zs_driver, zs_probe);
++      if (ret)
++              uart_unregister_driver(&zs_reg);
+-      for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+-              struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+-              struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+-              struct uart_port *uport = &zport->port;
+-
+-              if (zport->scc)
+-                      uart_add_one_port(&zs_reg, uport);
+-      }
+-
+-      return 0;
++      return ret;
+ }
+ static void __exit zs_exit(void)
+ {
+-      int i;
+-
+-      for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+-              struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+-              struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+-              struct uart_port *uport = &zport->port;
+-
+-              if (zport->scc)
+-                      uart_remove_one_port(&zs_reg, uport);
+-      }
+-
++      platform_driver_unregister(&zs_driver);
+       uart_unregister_driver(&zs_reg);
+ }
+--- a/drivers/tty/serial/zs.h
++++ b/drivers/tty/serial/zs.h
+@@ -22,7 +22,6 @@
+ struct zs_port {
+       struct zs_scc   *scc;                   /* Containing SCC.  */
+       struct uart_port port;                  /* Underlying UART.  */
+-      int             initialised;            /* For the console port.  */
+       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
diff --git a/queue-6.18/serial-zs-fix-bootconsole-handover-lockup.patch b/queue-6.18/serial-zs-fix-bootconsole-handover-lockup.patch
new file mode 100644 (file)
index 0000000..2ad049a
--- /dev/null
@@ -0,0 +1,100 @@
+From 6c05cf72e13314ce9b770b5951695dc5a2152920 Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Wed, 6 May 2026 23:42:39 +0100
+Subject: serial: zs: Fix bootconsole handover lockup
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 6c05cf72e13314ce9b770b5951695dc5a2152920 upstream.
+
+Calling zs_reset() in the course of setting up the serial device causes
+line parameters to be reset and the transmitter disabled.  We've been
+lucky in that no message is usually produced to the kernel log between
+this call and the later call to uart_set_options() in the course of
+console setup done by zs_serial_console_init(), or the system would hang
+as the console output handler in the firmware tried to access a port the
+transmitter of which has been disabled and line parameters messed up.
+
+This will change with the next change to the driver, so fix zs_reset()
+such that line parameters are set for 9600n8 console operation as with
+the system firmware and the transmitter re-enabled after reset.  This
+also means zs_pm() serves no purpose anymore, so drop it.
+
+Fixes: 8b4a40809e53 ("zs: move to the serial subsystem")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Cc: stable@vger.kernel.org # v2.6.23+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062308040.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/zs.c |   29 ++++++++---------------------
+ 1 file changed, 8 insertions(+), 21 deletions(-)
+
+--- a/drivers/tty/serial/zs.c
++++ b/drivers/tty/serial/zs.c
+@@ -105,18 +105,24 @@ struct zs_parms {
+ static struct zs_scc zs_sccs[ZS_NUM_SCCS];
++/*
++ * Set parameters in WR5, WR12, WR13 such as not to interfere
++ * with the initial PROM-based console.  Otherwise any output
++ * produced before the console handover would cause the system
++ * firmware to hang (TxENAB) or produce rubbish (Tx8, B9600).
++ */
+ static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+       0,                              /* write 0 */
+       PAR_SPEC,                       /* write 1 */
+       0,                              /* write 2 */
+       0,                              /* write 3 */
+       X16CLK | SB1,                   /* write 4 */
+-      0,                              /* write 5 */
++      Tx8 | TxENAB,                   /* write 5 */
+       0, 0, 0,                        /* write 6, 7, 8 */
+       MIE | DLC | NV,                 /* write 9 */
+       NRZ,                            /* write 10 */
+       TCBR | RCBR,                    /* write 11 */
+-      0, 0,                           /* BRG time constant, write 12 + 13 */
++      0x16, 0x00,                     /* BRG time constant, write 12 + 13 */
+       BRSRC | BRENABL,                /* write 14 */
+       0,                              /* write 15 */
+ };
+@@ -956,23 +962,6 @@ static void zs_set_termios(struct uart_p
+       spin_unlock_irqrestore(&scc->zlock, flags);
+ }
+-/*
+- * Hack alert!
+- * Required solely so that the initial PROM-based console
+- * works undisturbed in parallel with this one.
+- */
+-static void zs_pm(struct uart_port *uport, unsigned int state,
+-                unsigned int oldstate)
+-{
+-      struct zs_port *zport = to_zport(uport);
+-
+-      if (state < 3)
+-              zport->regs[5] |= TxENAB;
+-      else
+-              zport->regs[5] &= ~TxENAB;
+-      write_zsreg(zport, R5, zport->regs[5]);
+-}
+-
+ static const char *zs_type(struct uart_port *uport)
+ {
+@@ -1055,7 +1044,6 @@ static const struct uart_ops zs_ops = {
+       .startup        = zs_startup,
+       .shutdown       = zs_shutdown,
+       .set_termios    = zs_set_termios,
+-      .pm             = zs_pm,
+       .type           = zs_type,
+       .release_port   = zs_release_port,
+       .request_port   = zs_request_port,
+@@ -1210,7 +1198,6 @@ static int __init zs_console_setup(struc
+               return ret;
+       zs_reset(zport);
+-      zs_pm(uport, 0, -1);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
diff --git a/queue-6.18/serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch b/queue-6.18/serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch
new file mode 100644 (file)
index 0000000..f6d3c3e
--- /dev/null
@@ -0,0 +1,36 @@
+From d15cd40cb1858f75846eaafa9a6bca841b790a92 Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Fri, 10 Apr 2026 18:19:31 +0100
+Subject: serial: zs: Fix swapped RI/DSR modem line transition counting
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit d15cd40cb1858f75846eaafa9a6bca841b790a92 upstream.
+
+Fix a thinko in the status interrupt handler that has caused counters
+for the RI and DSR modem line transitions to be used for the other line
+each.
+
+Fixes: 8b4a40809e53 ("zs: move to the serial subsystem")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Link: https://patch.msgid.link/alpine.DEB.2.21.2604101747110.29980@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/zs.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/serial/zs.c
++++ b/drivers/tty/serial/zs.c
+@@ -680,9 +680,9 @@ static void zs_status_handle(struct zs_p
+                       uart_handle_dcd_change(uport,
+                                              zport->mctrl & TIOCM_CAR);
+               if (delta & TIOCM_RNG)
+-                      uport->icount.dsr++;
+-              if (delta & TIOCM_DSR)
+                       uport->icount.rng++;
++              if (delta & TIOCM_DSR)
++                      uport->icount.dsr++;
+               if (delta)
+                       wake_up_interruptible(&uport->state->port.delta_msr_wait);
diff --git a/queue-6.18/serial-zs-switch-to-using-channel-reset.patch b/queue-6.18/serial-zs-switch-to-using-channel-reset.patch
new file mode 100644 (file)
index 0000000..b043904
--- /dev/null
@@ -0,0 +1,89 @@
+From 8572955630f30948837088aa98bcbe0532d1ceac Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Wed, 6 May 2026 23:42:43 +0100
+Subject: serial: zs: Switch to using channel reset
+
+From: Maciej W. Rozycki <macro@orcam.me.uk>
+
+commit 8572955630f30948837088aa98bcbe0532d1ceac upstream.
+
+Switch the driver to using the channel reset rather than hardware reset,
+simplifying handling by removing an interference between channels that
+causes the other channel to become uninitialised afterwards.
+
+There is little difference between the two kinds of reset in terms of
+register settings that result, and we initialise the whole register set
+right away anyway.  However this prevents a hang from happening should
+the console output handler in the firmware try to access the other port
+whose transmitter has been disabled and line parameters messed up.
+
+For example this will happen if the keyboard port (port A) is chosen for
+the system console, unusually but not insanely for a headless system, as
+the port is wired to a standard DA-15 connector and an adapter can be
+easily made.  Or with the next change in place this would happen for the
+regular console port (port B), since the keyboard port (port A) will be
+initialised first.
+
+Just remove the unnecessary complication then, a channel reset is good
+enough.  We still need the initialisation marker, now per channel rather
+than per SCC, as for the console port zs_reset() will be called twice:
+once early on via zs_serial_console_init() for the console setup only,
+and then again via zs_config_port() as the port is associated with a TTY
+device.
+
+Fixes: 8b4a40809e53 ("zs: move to the serial subsystem")
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Cc: stable@vger.kernel.org # v2.6.23+
+Link: https://patch.msgid.link/alpine.DEB.2.21.2605062323430.46195@angie.orcam.me.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/zs.c |    7 ++++---
+ drivers/tty/serial/zs.h |    2 +-
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/tty/serial/zs.c
++++ b/drivers/tty/serial/zs.c
+@@ -832,21 +832,22 @@ static void zs_shutdown(struct uart_port
+ static void zs_reset(struct zs_port *zport)
+ {
++      struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+       struct zs_scc *scc = zport->scc;
+       int irq;
+       unsigned long flags;
+       spin_lock_irqsave(&scc->zlock, flags);
+       irq = !irqs_disabled_flags(flags);
+-      if (!scc->initialised) {
++      if (!zport->initialised) {
+               /* Reset the pointer first, just in case...  */
+               read_zsreg(zport, R0);
+               /* And let the current transmission finish.  */
+               zs_line_drain(zport, irq);
+-              write_zsreg(zport, R9, FHWRES);
++              write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB);
+               udelay(10);
+               write_zsreg(zport, R9, 0);
+-              scc->initialised = 1;
++              zport->initialised = 1;
+       }
+       load_zsregs(zport, zport->regs, irq);
+       spin_unlock_irqrestore(&scc->zlock, flags);
+--- a/drivers/tty/serial/zs.h
++++ b/drivers/tty/serial/zs.h
+@@ -22,6 +22,7 @@
+ struct zs_port {
+       struct zs_scc   *scc;                   /* Containing SCC.  */
+       struct uart_port port;                  /* Underlying UART.  */
++      int             initialised;            /* For the console port.  */
+       int             clk_mode;               /* May be 1, 16, 32, or 64.  */
+@@ -41,7 +42,6 @@ struct zs_scc {
+       struct zs_port  zport[2];
+       spinlock_t      zlock;
+       atomic_t        irq_guard;
+-      int             initialised;
+ };
+ #endif /* __KERNEL__ */
index 110c3f9225ae5092eadadf75e5b55494fdf38eea..411ce56f3fc26eeb10a703e5017e910bb2b2eaa1 100644 (file)
@@ -207,3 +207,75 @@ asoc-qcom-q6asm-dai-close-stream-only-when-running.patch
 asoc-qcom-q6asm-dai-do-not-set-stream-state-in-event-and-trigger-callbacks.patch
 xfrm-esp-restore-combined-single-frag-length-gate.patch
 alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch
+input-xpad-add-nova-2-lite-from-gamesir.patch
+input-xpad-add-support-for-asus-rog-raikiri-ii.patch
+ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch
+misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch
+input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch
+input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch
+gpib-cb7210-fix-region-leak-when-request_irq-fails.patch
+comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch
+comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch
+counter-fix-refcount-leak-in-counter_alloc-error-path.patch
+tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch
+tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch
+usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch
+usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch
+usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch
+usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch
+usb-storage-add-quirks-for-pny-elite-portable-ssd.patch
+usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch
+usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch
+usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch
+usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch
+usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch
+usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
+usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch
+usb-serial-option-add-meig-srm813q.patch
+usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch
+usb-serial-belkin_sa-validate-interrupt-status-length.patch
+usb-serial-cypress_m8-validate-interrupt-packet-headers.patch
+usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch
+usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch
+usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch
+usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch
+usb-gadget-net2280-fix-double-free-in-probe-error-path.patch
+usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch
+usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch
+usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch
+usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch
+usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch
+thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch
+thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch
+scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch
+scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch
+scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch
+scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch
+scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch
+drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch
+drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch
+drm-gem-fix-race-between-change_handle-and-handle_delete.patch
+drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch
+drm-i915-fix-potential-uaf-in-ttm-object-purge.patch
+drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch
+serial-altera_jtaguart-handle-uart_add_one_port-failures.patch
+serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch
+serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch
+serial-sh-sci-fix-memory-region-release-in-error-path.patch
+serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch
+serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch
+drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch
+drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch
+drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch
+drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch
+drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch
+drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch
+serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch
+serial-dz-fix-bootconsole-handover-lockup.patch
+serial-dz-convert-to-use-a-platform-device.patch
+serial-zs-fix-bootconsole-handover-lockup.patch
+serial-zs-switch-to-using-channel-reset.patch
+serial-zs-convert-to-use-a-platform-device.patch
+serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch
+serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch
+serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch
diff --git a/queue-6.18/thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch b/queue-6.18/thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch
new file mode 100644 (file)
index 0000000..7305c18
--- /dev/null
@@ -0,0 +1,75 @@
+From de21b59c29e31c5108ddc04210631bbfab81b997 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 10 May 2026 19:16:57 -0400
+Subject: thunderbolt: property: Reject dir_len < 4 to prevent size_t underflow
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit de21b59c29e31c5108ddc04210631bbfab81b997 upstream.
+
+On the non-root path, __tb_property_parse_dir() takes dir_len from
+entry->length (u16 widened to size_t).  Two distinct OOB conditions
+follow when entry->length < 4:
+
+1. The non-root path begins with kmemdup(&block[dir_offset],
+   sizeof(*dir->uuid), ...) which always reads 4 dwords from
+   dir_offset.  tb_property_entry_valid() only enforces
+   dir_offset + entry->length <= block_len, so a crafted entry
+   with dir_offset close to the end of the property block and
+   entry->length in 0..3 passes that gate but lets the UUID copy
+   run off the block (e.g. dir_offset = 497, dir_len = 3 in a
+   500-dword block reads block[497..501]).
+
+2. After the kmemdup, content_len = dir_len - 4 underflows size_t
+   to ~SIZE_MAX, nentries becomes SIZE_MAX / 4, and the entry
+   walk runs OOB on each iteration until an entry fails
+   validation or the kernel oopses on an unmapped page.
+
+Reject dir_len < 4 on the non-root path *before* the UUID kmemdup,
+which closes both holes.
+
+Also move INIT_LIST_HEAD(&dir->properties) up to immediately after
+the dir allocation so the new error-return path (and the existing
+uuid-alloc failure path) calling tb_property_free_dir() sees a
+walkable list rather than the zero-initialized NULL next/prev that
+list_for_each_entry_safe() would oops on.
+
+Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/property.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/thunderbolt/property.c
++++ b/drivers/thunderbolt/property.c
+@@ -174,10 +174,16 @@ static struct tb_property_dir *__tb_prop
+       if (!dir)
+               return NULL;
++      INIT_LIST_HEAD(&dir->properties);
++
+       if (is_root) {
+               content_offset = dir_offset + 2;
+               content_len = dir_len;
+       } else {
++              if (dir_len < 4) {
++                      tb_property_free_dir(dir);
++                      return NULL;
++              }
+               dir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid),
+                                   GFP_KERNEL);
+               if (!dir->uuid) {
+@@ -191,8 +197,6 @@ static struct tb_property_dir *__tb_prop
+       entries = (const struct tb_property_entry *)&block[content_offset];
+       nentries = content_len / (sizeof(*entries) / 4);
+-      INIT_LIST_HEAD(&dir->properties);
+-
+       for (i = 0; i < nentries; i++) {
+               struct tb_property *property;
diff --git a/queue-6.18/thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch b/queue-6.18/thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch
new file mode 100644 (file)
index 0000000..d6089b7
--- /dev/null
@@ -0,0 +1,65 @@
+From 01deda0152066c6c955f0619114ea6afa070aaec Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 10 May 2026 19:16:56 -0400
+Subject: thunderbolt: property: Reject u32 wrap in tb_property_entry_valid()
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 01deda0152066c6c955f0619114ea6afa070aaec upstream.
+
+entry->value is u32 and entry->length is u16; the sum is performed in
+u32 and wraps.  A malicious XDomain peer can pick
+value = 0xffffff00, length = 0x100 so the sum 0x100000000 wraps to 0
+and passes the > block_len check.  tb_property_parse() then passes
+entry->value to parse_dwdata() as a dword offset into the property
+block, reading attacker-directed memory far past the allocation.
+
+For TEXT-typed entries with the "deviceid" or "vendorid" keys this
+lands in xd->device_name / xd->vendor_name and is readable back via
+the per-XDomain device_name / vendor_name sysfs attributes; the leak
+is NUL-bounded (kstrdup() stops at the first zero byte) and
+untargeted (the attacker picks a delta, not an absolute address).
+DATA-typed entries are parsed into property->value.data but not
+generically surfaced to userspace.
+
+Use check_add_overflow() so a wrapped sum is rejected.
+
+Fixes: cdae7c07e3e3 ("thunderbolt: Add support for XDomain properties")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-6
+Assisted-by: Codex:gpt-5-4
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/property.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/thunderbolt/property.c
++++ b/drivers/thunderbolt/property.c
+@@ -8,6 +8,7 @@
+  */
+ #include <linux/err.h>
++#include <linux/overflow.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
+ #include <linux/uuid.h>
+@@ -52,13 +53,16 @@ static inline void format_dwdata(void *d
+ static bool tb_property_entry_valid(const struct tb_property_entry *entry,
+                                 size_t block_len)
+ {
++      u32 end;
++
+       switch (entry->type) {
+       case TB_PROPERTY_TYPE_DIRECTORY:
+       case TB_PROPERTY_TYPE_DATA:
+       case TB_PROPERTY_TYPE_TEXT:
+               if (entry->length > block_len)
+                       return false;
+-              if (entry->value + entry->length > block_len)
++              if (check_add_overflow(entry->value, entry->length, &end) ||
++                  end > block_len)
+                       return false;
+               break;
diff --git a/queue-6.18/tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch b/queue-6.18/tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch
new file mode 100644 (file)
index 0000000..3f993c6
--- /dev/null
@@ -0,0 +1,68 @@
+From 6fe472c1bbbe238e91141f7cabc1226e96a60d43 Mon Sep 17 00:00:00 2001
+From: Zhaoyang Yu <2426767509@qq.com>
+Date: Thu, 9 Apr 2026 13:41:58 +0800
+Subject: tty: serial: pch_uart: add check for dma_alloc_coherent()
+
+From: Zhaoyang Yu <2426767509@qq.com>
+
+commit 6fe472c1bbbe238e91141f7cabc1226e96a60d43 upstream.
+
+Add a check for dma_alloc_coherent() failure to prevent a potential
+NULL pointer dereference in dma_handle_rx(). Properly release DMA
+channels and the PCI device reference using a goto ladder if the
+allocation fails.
+
+Fixes: 3c6a483275f4 ("Serial: EG20T: add PCH_UART driver")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Zhaoyang Yu <2426767509@qq.com>
+Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://patch.msgid.link/tencent_E328416B7CFD436F6029F2DF02AD7ED89C08@qq.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/pch_uart.c |   19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/drivers/tty/serial/pch_uart.c
++++ b/drivers/tty/serial/pch_uart.c
+@@ -689,8 +689,7 @@ static void pch_request_dma(struct uart_
+       if (!chan) {
+               dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n",
+                       __func__);
+-              pci_dev_put(dma_dev);
+-              return;
++              goto err_pci_get;
+       }
+       priv->chan_tx = chan;
+@@ -704,18 +703,26 @@ static void pch_request_dma(struct uart_
+       if (!chan) {
+               dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n",
+                       __func__);
+-              dma_release_channel(priv->chan_tx);
+-              priv->chan_tx = NULL;
+-              pci_dev_put(dma_dev);
+-              return;
++              goto err_req_tx;
+       }
+       /* Get Consistent memory for DMA */
+       priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
+                                   &priv->rx_buf_dma, GFP_KERNEL);
++      if (!priv->rx_buf_virt)
++              goto err_req_rx;
+       priv->chan_rx = chan;
+       pci_dev_put(dma_dev);
++      return;
++
++err_req_rx:
++      dma_release_channel(chan);
++err_req_tx:
++      dma_release_channel(priv->chan_tx);
++      priv->chan_tx = NULL;
++err_pci_get:
++      pci_dev_put(dma_dev);
+ }
+ static void pch_dma_rx_complete(void *arg)
diff --git a/queue-6.18/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch b/queue-6.18/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch
new file mode 100644 (file)
index 0000000..661b652
--- /dev/null
@@ -0,0 +1,81 @@
+From a3bb136bff5e6a5e48cdd813246c9c4686feaaa9 Mon Sep 17 00:00:00 2001
+From: Tudor Ambarus <tudor.ambarus@linaro.org>
+Date: Fri, 15 May 2026 12:41:21 +0000
+Subject: tty: serial: samsung: Remove redundant port lock acquisition in rx helpers
+
+From: Tudor Ambarus <tudor.ambarus@linaro.org>
+
+commit a3bb136bff5e6a5e48cdd813246c9c4686feaaa9 upstream.
+
+Sashiko identified a deadlock when the console flow is engaged [1].
+
+When console flow control is enabled (UPF_CONS_FLOW),
+s3c24xx_serial_stop_tx() calls s3c24xx_serial_rx_enable() and
+s3c24xx_serial_start_tx() calls s3c24xx_serial_rx_disable().
+
+The serial core framework invokes the .stop_tx() and .start_tx()
+callbacks with the port->lock spinlock already held. Furthermore, all
+internal driver paths that invoke stop_tx (such as the DMA TX
+completion handler s3c24xx_serial_tx_dma_complete() or the PIO TX IRQ
+handler s3c24xx_serial_tx_irq()) also acquire port->lock prior to
+calling it. (Note that s3c24xx_serial_start_tx() is only invoked by the
+serial core).
+
+However, s3c24xx_serial_rx_enable() and s3c24xx_serial_rx_disable()
+unconditionally attempt to acquire port->lock again using
+uart_port_lock_irqsave(). Since spinlocks are not recursive, this
+causes a deadlock on the same CPU when console flow control is engaged.
+
+Remove the redundant lock acquisition from both rx helper functions.
+
+Cc: stable <stable@kernel.org>
+Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers")
+Reported-by: John Ogness <john.ogness@linutronix.de>
+Closes: https://sashiko.dev/#/patchset/20260506121606.5805-1-john.ogness%40linutronix.de [1]
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Link: https://patch.msgid.link/20260515-samsung-tty-flow-control-deadlock-v1-1-93255edbc9bc@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/samsung_tty.c |    8 --------
+ 1 file changed, 8 deletions(-)
+
+--- a/drivers/tty/serial/samsung_tty.c
++++ b/drivers/tty/serial/samsung_tty.c
+@@ -245,12 +245,9 @@ static bool s3c24xx_serial_txempty_nofif
+ static void s3c24xx_serial_rx_enable(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+-      unsigned long flags;
+       int count = 10000;
+       u32 ucon, ufcon;
+-      uart_port_lock_irqsave(port, &flags);
+-
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+@@ -263,23 +260,18 @@ static void s3c24xx_serial_rx_enable(str
+       wr_regl(port, S3C2410_UCON, ucon);
+       ourport->rx_enabled = 1;
+-      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c24xx_serial_rx_disable(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+-      unsigned long flags;
+       u32 ucon;
+-      uart_port_lock_irqsave(port, &flags);
+-
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+       ourport->rx_enabled = 0;
+-      uart_port_unlock_irqrestore(port, flags);
+ }
+ static void s3c24xx_serial_stop_tx(struct uart_port *port)
diff --git a/queue-6.18/usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch b/queue-6.18/usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch
new file mode 100644 (file)
index 0000000..ea01955
--- /dev/null
@@ -0,0 +1,77 @@
+From 8f6aa392653e52a45858cff5c063df550028836b Mon Sep 17 00:00:00 2001
+From: Xu Yang <xu.yang_2@nxp.com>
+Date: Mon, 27 Apr 2026 15:57:55 +0800
+Subject: usb: chipidea: core: convert ci_role_switch to local variable
+
+From: Xu Yang <xu.yang_2@nxp.com>
+
+commit 8f6aa392653e52a45858cff5c063df550028836b upstream.
+
+When a system contains multiple USB controllers, the global ci_role_switch
+variable may be overwritten by subsequent driver initialization code.
+
+This can cause issues in the following cases:
+ - The 2nd ci_hdrc_probe() sees ci_role_switch.fwnode as non-NULL even
+   though the "usb-role-switch" property is not present for the controller.
+ - When the ci_hdrc device is unbound and bound again, ci_role_switch
+   fwnode will not be reassigned, and the old value will be used instead.
+
+Convert ci_role_switch to a local variable to fix these issues.
+
+Fixes: 05559f10ed79 ("usb: chipidea: add role switch class support")
+Cc: stable <stable@kernel.org>
+Acked-by: Peter Chen <peter.chen@kernel.org>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
+Link: https://patch.msgid.link/20260427075755.3611217-1-xu.yang_2@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/chipidea/core.c |   16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+--- a/drivers/usb/chipidea/core.c
++++ b/drivers/usb/chipidea/core.c
+@@ -669,12 +669,6 @@ static enum ci_role ci_get_role(struct c
+       return role;
+ }
+-static struct usb_role_switch_desc ci_role_switch = {
+-      .set = ci_usb_role_switch_set,
+-      .get = ci_usb_role_switch_get,
+-      .allow_userspace_control = true,
+-};
+-
+ static int ci_get_platdata(struct device *dev,
+               struct ci_hdrc_platform_data *platdata)
+ {
+@@ -801,9 +795,6 @@ static int ci_get_platdata(struct device
+                       cable->connected = false;
+       }
+-      if (device_property_read_bool(dev, "usb-role-switch"))
+-              ci_role_switch.fwnode = dev->fwnode;
+-
+       platdata->pctl = devm_pinctrl_get(dev);
+       if (!IS_ERR(platdata->pctl)) {
+               struct pinctrl_state *p;
+@@ -1045,6 +1036,7 @@ ATTRIBUTE_GROUPS(ci);
+ static int ci_hdrc_probe(struct platform_device *pdev)
+ {
++      struct usb_role_switch_desc ci_role_switch = {};
+       struct device   *dev = &pdev->dev;
+       struct ci_hdrc  *ci;
+       struct resource *res;
+@@ -1191,7 +1183,11 @@ static int ci_hdrc_probe(struct platform
+               }
+       }
+-      if (ci_role_switch.fwnode) {
++      if (device_property_read_bool(dev, "usb-role-switch")) {
++              ci_role_switch.set = ci_usb_role_switch_set;
++              ci_role_switch.get = ci_usb_role_switch_get;
++              ci_role_switch.allow_userspace_control = true;
++              ci_role_switch.fwnode = dev_fwnode(dev);
+               ci_role_switch.driver_data = ci;
+               ci->role_switch = usb_role_switch_register(dev,
+                                       &ci_role_switch);
diff --git a/queue-6.18/usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch b/queue-6.18/usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch
new file mode 100644 (file)
index 0000000..ee40e6b
--- /dev/null
@@ -0,0 +1,65 @@
+From 727d045d064b7c9a24db3bce9c0485a382cb768b Mon Sep 17 00:00:00 2001
+From: Michal Pecio <michal.pecio@gmail.com>
+Date: Mon, 18 May 2026 07:32:07 +0200
+Subject: usb: core: Fix up Interrupt IN endpoints with bogus wBytesPerInterval
+
+From: Michal Pecio <michal.pecio@gmail.com>
+
+commit 727d045d064b7c9a24db3bce9c0485a382cb768b upstream.
+
+Tao Xue found that some common devices violate USB 3.x section 9.6.7
+by reporting wBytesPerInterval lower than the size of packets they
+actually send. I confirmed that AX88179 may set it to 0 and RTL8153
+CDC configuration sets it to 8 but sends both 8 and 16 byte packets:
+
+S Ii:11:007:3 -115:128 16 <
+C Ii:11:007:3 0:128 8 = a1000000 01000000
+S Ii:11:007:3 -115:128 16 <
+C Ii:11:007:3 0:128 16 = a12a0000 01000800 00000000 00000000
+
+Most xHCI host controllers neglect interrupt bandwidth reservations
+and let such devices exceed theirs, some fail the URB with EOVERFLOW.
+
+Assume that wBytesPerInterval lower than wMaxPacketSize is bogus and
+increase it to the worst case maximum on interrupt IN endpoints. This
+solves xHCI problems and appears to have no other effect. Interrupt
+transfers are not limited to one interval and drivers submit URBs of
+class defined size without looking at wBytesPerInterval. Any multi-
+interval transfer is considered terminated by a packet shorter than
+wMaxPacketSize regardless of wBytesPerInterval - see USB3 8.10.3.
+
+Stay in spec on OUT endpoints and isochronous. No buggy devices are
+known and we don't want to risk sending more data than the device
+is prepared to handle or confusing isoc drivers regarding altsetting
+capacities guaranteed by the device itself. And don't complain when
+wMaxPacketSize <= wBytesPerInterval < wMaxPacketSize * (bMaxBurst+1)
+because enabling this seems to be the exact goal of the spec.
+
+Reported-and-tested-by: Tao Xue <xuetao09@huawei.com>
+Closes: https://lore.kernel.org/linux-usb/20260402021400.28853-1-xuetao09@huawei.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
+Link: https://patch.msgid.link/20260518073207.5b7d26e7.michal.pecio@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/core/config.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/core/config.c
++++ b/drivers/usb/core/config.c
+@@ -191,7 +191,14 @@ static void usb_parse_ss_endpoint_compan
+                       (desc->bMaxBurst + 1);
+       else
+               max_tx = 999999;
+-      if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
++      /*
++       * wBytesPerInterval > max_tx is bogus, but USB3 spec doesn't forbid the opposite.
++       * Experience shows that wBytesPerInterval < wMaxPacketSize on common interrupt IN
++       * endpoints is usually bogus too, and recent HCs enforce interrupt BW limits.
++       */
++      if (le16_to_cpu(desc->wBytesPerInterval) > max_tx ||
++          (le16_to_cpu(desc->wBytesPerInterval) < usb_endpoint_maxp(&ep->desc) &&
++           usb_endpoint_is_int_in(&ep->desc))) {
+               dev_notice(ddev, "%s endpoint with wBytesPerInterval of %d in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to %d\n",
diff --git a/queue-6.18/usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch b/queue-6.18/usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch
new file mode 100644 (file)
index 0000000..ceb857d
--- /dev/null
@@ -0,0 +1,62 @@
+From 6c5dbc104dadd79fc2923497c20bae759a18758c Mon Sep 17 00:00:00 2001
+From: Jeremy Erazo <mendozayt13@gmail.com>
+Date: Tue, 12 May 2026 16:05:30 +0000
+Subject: usb: gadget: composite: fix integer underflow in WebUSB GET_URL handling
+
+From: Jeremy Erazo <mendozayt13@gmail.com>
+
+commit 6c5dbc104dadd79fc2923497c20bae759a18758c upstream.
+
+The WebUSB GET_URL handler in composite_setup() narrows
+landing_page_length to fit the host-supplied wLength using
+
+       landing_page_length = w_length
+               - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset;
+
+If wLength is smaller than WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH the
+unsigned subtraction wraps, and the subsequent
+
+       memcpy(url_descriptor->URL,
+              cdev->landing_page + landing_page_offset,
+              landing_page_length - landing_page_offset);
+
+ends up copying close to UINT_MAX bytes from cdev->landing_page into
+cdev->req->buf.  KASAN reports a slab-out-of-bounds in composite_setup
+on the kmalloc-2k gadget_info allocation, and FORTIFY_SOURCE traps the
+memcpy as a 4294967293-byte field-spanning write into
+url_descriptor->URL (size 252).
+
+A USB host can reach this from a single SETUP packet against any
+gadget that has webusb/use=1 and a landingPage configured.
+
+Handle the small-wLength case before the math: when the host requested
+fewer bytes than the URL descriptor header, only the header is
+meaningful and no URL bytes need to be copied.  Setting
+landing_page_length to landing_page_offset makes the existing memcpy a
+no-op and leaves the descriptor returned to the host unchanged for all
+larger wLength values.
+
+Fixes: 93c473948c58 ("usb: gadget: add WebUSB landing page support")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Jeremy Erazo <mendozayt13@gmail.com>
+Link: https://patch.msgid.link/20260512160530.352318-1-mendozayt13@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/composite.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/composite.c
++++ b/drivers/usb/gadget/composite.c
+@@ -2172,7 +2172,10 @@ unknown:
+                               sizeof(url_descriptor->URL)
+                               - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset);
+-                      if (w_length < WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_length)
++                      if (w_length < WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH)
++                              landing_page_length = landing_page_offset;
++                      else if (w_length <
++                               WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_length)
+                               landing_page_length = w_length
+                               - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset;
diff --git a/queue-6.18/usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch b/queue-6.18/usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch
new file mode 100644 (file)
index 0000000..4c1e599
--- /dev/null
@@ -0,0 +1,50 @@
+From 7d9633528dd40e33964d2dc74a5abbf5c4d116ce Mon Sep 17 00:00:00 2001
+From: Seungjin Bae <eeodqql09@gmail.com>
+Date: Mon, 18 May 2026 19:43:14 -0400
+Subject: usb: gadget: dummy_hcd: Reject hub port requests for non-existent ports
+
+From: Seungjin Bae <eeodqql09@gmail.com>
+
+commit 7d9633528dd40e33964d2dc74a5abbf5c4d116ce upstream.
+
+The `dummy_hub_control()` function handles USB hub class requests
+to the virtual root hub. The `GetPortStatus` case returns -EPIPE for
+requests with `wIndex != 1`, since the virtual root hub has only a
+single port. However, the `ClearPortFeature` and `SetPortFeature`
+cases lack the same check.
+
+Fix this by extending the `wIndex != 1` rejection to both cases,
+matching the existing behavior of `GetPortStatus`.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable <stable@kernel.org>
+Suggested-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Seungjin Bae <eeodqql09@gmail.com>
+Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://patch.msgid.link/20260518234314.1889396-1-eeodqql09@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -2134,6 +2134,8 @@ static int dummy_hub_control(
+       case ClearHubFeature:
+               break;
+       case ClearPortFeature:
++              if (wIndex != 1)
++                      goto error;
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       if (hcd->speed == HCD_USB3) {
+@@ -2248,6 +2250,8 @@ static int dummy_hub_control(
+               retval = -EPIPE;
+               break;
+       case SetPortFeature:
++              if (wIndex != 1)
++                      goto error;
+               switch (wValue) {
+               case USB_PORT_FEAT_LINK_STATE:
+                       if (hcd->speed != HCD_USB3) {
diff --git a/queue-6.18/usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch b/queue-6.18/usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch
new file mode 100644 (file)
index 0000000..99aa754
--- /dev/null
@@ -0,0 +1,79 @@
+From 4e036c10e7f4df5d951c69cc3697bc8e209c6d02 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 19 Apr 2026 12:03:59 -0400
+Subject: usb: gadget: f_fs: copy only received bytes on short ep0 read
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 4e036c10e7f4df5d951c69cc3697bc8e209c6d02 upstream.
+
+ffs_ep0_read() allocates its control-OUT data buffer with
+kmalloc() (not kzalloc) at the Length value from the Setup
+packet, then copies that full len to userspace regardless of
+how many bytes were actually received:
+
+    data = kmalloc(len, GFP_KERNEL);
+    ...
+    ret = __ffs_ep0_queue_wait(ffs, data, len);
+    if ((ret > 0) && (copy_to_user(buf, data, len)))
+            ret = -EFAULT;
+
+__ffs_ep0_queue_wait() returns req->actual, which on a short
+control OUT transfer is strictly less than len.  The
+copy_to_user() call still copies len bytes, so on a short OUT
+the last (len - ret) bytes of the kmalloc() buffer --
+uninitialised slab residue -- are delivered to the FunctionFS
+daemon.
+
+Short ep0 OUT completions are specified USB control-transfer
+behavior and are produced by in-tree UDCs:
+
+  * dwc2 continues on req->actual < req->length for ep0 DATA OUT
+    (short-not-ok is the only ep0-OUT stall path).
+  * aspeed_udc ends ep0 OUT on rx_len < ep->ep.maxpacket.
+  * renesas_usbf logs "ep0 short packet" and completes the
+    request.
+  * dwc3 stalls on short IN but not on short OUT.
+
+A short ep0 OUT is therefore not evidence of a broken UDC; it is
+a normal condition f_fs has to cope with.  The sibling gadgetfs
+implementation in drivers/usb/gadget/legacy/inode.c already does
+this correctly via min(len, dev->req->actual) before
+copy_to_user().  This patch brings f_fs.c to the same safe
+pattern rather than trimming at a defensive layer.
+
+The bug is reached from the FunctionFS device node, which in
+real deployments is owned by the privileged gadget daemon
+(adbd, UMS, composite gadget services, etc.); it is not
+reachable from unprivileged userspace.  Linux host stacks
+normally reject short-wLength control OUTs before they reach
+the gadget, so reproducing this required a build that
+bypasses that host-side check.  With the bypass in place, a
+1-byte payload on a 64-byte Setup produces 63 bytes of
+non-canary slab residue in the daemon's read buffer.
+
+Fix by copying only ret (actually received) bytes to
+userspace.
+
+Fixes: ddf8abd25994 ("USB: f_fs: the FunctionFS driver")
+Cc: stable <stable@kernel.org>
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Link: https://patch.msgid.link/20260419160359.1577270-1-michael.bommarito@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_fs.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/function/f_fs.c
++++ b/drivers/usb/gadget/function/f_fs.c
+@@ -622,7 +622,7 @@ static ssize_t ffs_ep0_read(struct file
+               /* unlocks spinlock */
+               ret = __ffs_ep0_queue_wait(ffs, data, len);
+-              if ((ret > 0) && (copy_to_user(buf, data, len)))
++              if ((ret > 0) && (copy_to_user(buf, data, ret)))
+                       ret = -EFAULT;
+               goto done_mutex;
diff --git a/queue-6.18/usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch b/queue-6.18/usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch
new file mode 100644 (file)
index 0000000..47d6259
--- /dev/null
@@ -0,0 +1,162 @@
+From 2796646f6d892c1eb6818c7ca41fdfa12568e8d1 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Sun, 19 Apr 2026 12:12:27 -0400
+Subject: usb: gadget: f_fs: serialize DMABUF cancel against request completion
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit 2796646f6d892c1eb6818c7ca41fdfa12568e8d1 upstream.
+
+ffs_epfile_dmabuf_io_complete() calls usb_ep_free_request() on the
+completed request but leaves priv->req, the back-pointer that
+ffs_dmabuf_transfer() set on submission, pointing at the freed
+memory.  A later FUNCTIONFS_DMABUF_DETACH ioctl or
+ffs_epfile_release() on the close path still sees priv->req
+non-NULL under ffs->eps_lock:
+
+    if (priv->ep && priv->req)
+            usb_ep_dequeue(priv->ep, priv->req);
+
+so usb_ep_dequeue() is called on a freed usb_request.
+
+On dummy_hcd the dequeue path only walks a live queue and
+pointer-compares, so the freed pointer reads without faulting and
+KASAN requires an explicit check at the FunctionFS call site to
+surface the use-after-free.  On SG-capable in-tree UDCs the
+dequeue path dereferences the supplied request immediately:
+
+  * chipidea's ep_dequeue() does
+    container_of(req, struct ci_hw_req, req) and reads
+    hwreq->req.status before acquiring its own lock.
+  * cdnsp's cdnsp_gadget_ep_dequeue() reads request->status first.
+
+The narrower option of clearing priv->req via cmpxchg() in the
+completion does not close the race: the completion runs without
+eps_lock, so a cancel path holding eps_lock can still observe
+priv->req non-NULL, race a concurrent completion that clears and
+frees, and pass the freed pointer to usb_ep_dequeue().  A slightly
+longer fix that moves the free into the cleanup work is needed.
+
+Same class of lifetime race as the recent usbip-vudc timer fix [1].
+
+Take eps_lock in the sole place that mutates priv->req from the
+callback direction by moving usb_ep_free_request() out of the
+completion into ffs_dmabuf_cleanup(), the existing work handler
+scheduled by ffs_dmabuf_signal_done() on
+ffs->io_completion_wq.  Clear priv->req there under eps_lock
+before freeing, and only clear if priv->req still names our
+request (a subsequent ffs_dmabuf_transfer() on the same
+attachment may have queued a new one).
+
+This keeps the existing dummy_hcd sync-dequeue invariant: the
+completion callback is still invoked by the UDC without
+eps_lock held (dummy_hcd drops its own lock before calling the
+callback), and the callback now takes no f_fs lock at all.
+Serialization against the cancel path happens in cleanup, which
+runs from the workqueue with no f_fs lock held on entry.
+
+The priv ref count protects the containing ffs_dmabuf_priv:
+ffs_dmabuf_transfer() takes a ref via ffs_dmabuf_get(), cleanup
+drops it via ffs_dmabuf_put(), so priv stays live for the
+cleanup even after the cancel path's list_del + ffs_dmabuf_put.
+
+The ffs_dmabuf_transfer() error path no longer frees usb_req
+inline: fence->req and fence->ep are set before usb_ep_queue(),
+so ffs_dmabuf_cleanup() (scheduled by the error-path
+ffs_dmabuf_signal_done()) owns the free regardless of whether
+the queue succeeded.
+
+Reproduced under KASAN on both detach and close paths against
+dummy_hcd with an observability hook
+(kasan_check_byte(priv->req) immediately before usb_ep_dequeue)
+at the two FunctionFS cancel sites to surface the stale-pointer
+access; the hook is not part of this patch.  The KASAN
+allocator / free stacks in the captured splats identify the
+same request: alloc in dummy_alloc_request, free in
+dummy_timer, fault reached from ffs_epfile_release (close) and
+from the FUNCTIONFS_DMABUF_DETACH ioctl (detach).  With the
+patch applied, both paths are silent under the same hook.
+
+The bug is reached from the FunctionFS device node, which in
+real deployments is owned by the privileged gadget daemon
+(adbd, UMS, composite gadget services, etc.); it is not
+reachable from unprivileged userspace or from a USB host on the
+cable.  FunctionFS mounts default to GLOBAL_ROOT_UID, but the
+filesystem supports uid=, gid=, and fmode= delegation to a
+non-root gadget daemon, so on real deployments the attacker may
+be a less-privileged service rather than root.
+
+Fixes: 7b07a2a7ca02 ("usb: gadget: functionfs: Add DMABUF import interface")
+Link: https://lore.kernel.org/all/20260417163552.807548-1-michael.bommarito@gmail.com/ [1]
+Cc: stable <stable@kernel.org>
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Link: https://patch.msgid.link/20260419161227.1587668-1-michael.bommarito@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_fs.c |   24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_fs.c
++++ b/drivers/usb/gadget/function/f_fs.c
+@@ -151,6 +151,8 @@ struct ffs_dma_fence {
+       struct dma_fence base;
+       struct ffs_dmabuf_priv *priv;
+       struct work_struct work;
++      struct usb_ep *ep;
++      struct usb_request *req;
+ };
+ struct ffs_epfile {
+@@ -1365,6 +1367,21 @@ static void ffs_dmabuf_cleanup(struct wo
+       struct ffs_dmabuf_priv *priv = dma_fence->priv;
+       struct dma_buf_attachment *attach = priv->attach;
+       struct dma_fence *fence = &dma_fence->base;
++      struct usb_request *req = dma_fence->req;
++      struct usb_ep *ep = dma_fence->ep;
++
++      /*
++       * eps_lock pairs with the cancel paths so they cannot pass a freed
++       * req to usb_ep_dequeue().  Only clear if priv->req still names ours;
++       * a re-queue on the same attachment may have taken that slot.
++       */
++      spin_lock_irq(&priv->ffs->eps_lock);
++      if (priv->req == req)
++              priv->req = NULL;
++      spin_unlock_irq(&priv->ffs->eps_lock);
++
++      if (ep && req)
++              usb_ep_free_request(ep, req);
+       ffs_dmabuf_put(attach);
+       dma_fence_put(fence);
+@@ -1394,8 +1411,8 @@ static void ffs_epfile_dmabuf_io_complet
+                                         struct usb_request *req)
+ {
+       pr_vdebug("FFS: DMABUF transfer complete, status=%d\n", req->status);
++      /* req is freed by ffs_dmabuf_cleanup() under eps_lock. */
+       ffs_dmabuf_signal_done(req->context, req->status);
+-      usb_ep_free_request(ep, req);
+ }
+ static const char *ffs_dmabuf_get_driver_name(struct dma_fence *fence)
+@@ -1679,6 +1696,10 @@ static int ffs_dmabuf_transfer(struct fi
+       usb_req->context  = fence;
+       usb_req->complete = ffs_epfile_dmabuf_io_complete;
++      /* ffs_dmabuf_cleanup() frees usb_req via these two fields. */
++      fence->req = usb_req;
++      fence->ep = ep->ep;
++
+       cookie = dma_fence_begin_signalling();
+       ret = usb_ep_queue(ep->ep, usb_req, GFP_ATOMIC);
+       dma_fence_end_signalling(cookie);
+@@ -1688,7 +1709,6 @@ static int ffs_dmabuf_transfer(struct fi
+       } else {
+               pr_warn("FFS: Failed to queue DMABUF: %d\n", ret);
+               ffs_dmabuf_signal_done(fence, ret);
+-              usb_ep_free_request(ep->ep, usb_req);
+       }
+       spin_unlock_irq(&epfile->ffs->eps_lock);
diff --git a/queue-6.18/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch b/queue-6.18/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch
new file mode 100644 (file)
index 0000000..1e625f6
--- /dev/null
@@ -0,0 +1,53 @@
+From 4f88d65def6f3c90121601b4f62a4c967f3063a6 Mon Sep 17 00:00:00 2001
+From: Guangshuo Li <lgs201920130244@gmail.com>
+Date: Mon, 13 Apr 2026 22:21:19 +0800
+Subject: usb: gadget: f_hid: fix device reference leak in hidg_alloc()
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+commit 4f88d65def6f3c90121601b4f62a4c967f3063a6 upstream.
+
+hidg_alloc() initializes hidg->dev with device_initialize() before
+calling dev_set_name(). If dev_set_name() fails, the function currently
+jumps to err_unlock and returns without calling put_device().
+
+This leaves the device reference unbalanced and prevents hidg_release()
+from being called. Calling put_device() here is also safe, since
+hidg_release() only frees resources owned by hidg.
+
+The issue was identified by a static analysis tool I developed and
+confirmed by manual review.
+
+Route the dev_set_name() failure path through err_put_device so the
+device reference is dropped properly.
+
+Fixes: 89ff3dfac604 ("usb: gadget: f_hid: fix f_hidg lifetime vs cdev")
+Cc: stable <stable@kernel.org>
+Reviewed-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Reviewed-by: Johan Hovold johan@kernel.org
+Link: https://patch.msgid.link/20260413142119.2977716-1-lgs201920130244@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_hid.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -1621,7 +1621,7 @@ static struct usb_function *hidg_alloc(s
+       hidg->dev.devt = MKDEV(major, opts->minor);
+       ret = dev_set_name(&hidg->dev, "hidg%d", opts->minor);
+       if (ret)
+-              goto err_unlock;
++              goto err_put_device;
+       hidg->bInterfaceSubClass = opts->subclass;
+       hidg->bInterfaceProtocol = opts->protocol;
+@@ -1658,7 +1658,6 @@ static struct usb_function *hidg_alloc(s
+ err_put_device:
+       put_device(&hidg->dev);
+-err_unlock:
+       mutex_unlock(&opts->lock);
+       return ERR_PTR(ret);
+ }
diff --git a/queue-6.18/usb-gadget-net2280-fix-double-free-in-probe-error-path.patch b/queue-6.18/usb-gadget-net2280-fix-double-free-in-probe-error-path.patch
new file mode 100644 (file)
index 0000000..a9d21a8
--- /dev/null
@@ -0,0 +1,48 @@
+From c8547c74988e0b5f4cbb1b895e2a57aae084f070 Mon Sep 17 00:00:00 2001
+From: Guangshuo Li <lgs201920130244@gmail.com>
+Date: Mon, 27 Apr 2026 23:36:51 +0800
+Subject: usb: gadget: net2280: Fix double free in probe error path
+
+From: Guangshuo Li <lgs201920130244@gmail.com>
+
+commit c8547c74988e0b5f4cbb1b895e2a57aae084f070 upstream.
+
+usb_initialize_gadget() installs gadget_release() as the release
+callback for the embedded gadget device.  The struct net2280 instance is
+therefore released through gadget_release() when the gadget device's last
+reference is dropped.
+
+The probe error path calls net2280_remove(), which tears down the
+partially initialized device and drops the gadget reference with
+usb_put_gadget().  Calling kfree(dev) afterwards can free the same object
+again.
+
+Drop the explicit kfree() and let the gadget device release callback
+handle the final free.  This issue was found by a static analysis tool
+I am developing.
+
+Fixes: f770fbec4165 ("USB: UDC: net2280: Fix memory leaks")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
+Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://patch.msgid.link/20260427153651.337846-1-lgs201920130244@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/net2280.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/usb/gadget/udc/net2280.c
++++ b/drivers/usb/gadget/udc/net2280.c
+@@ -3790,10 +3790,8 @@ static int net2280_probe(struct pci_dev
+       return 0;
+ done:
+-      if (dev) {
++      if (dev)
+               net2280_remove(pdev);
+-              kfree(dev);
+-      }
+       return retval;
+ }
diff --git a/queue-6.18/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch b/queue-6.18/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch
new file mode 100644 (file)
index 0000000..152f9a9
--- /dev/null
@@ -0,0 +1,137 @@
+From 68aa70648b625fa684bc0b71bbfd905f4943ca20 Mon Sep 17 00:00:00 2001
+From: Kai Aizen <kai.aizen.dev@gmail.com>
+Date: Thu, 30 Apr 2026 20:56:43 +0300
+Subject: usb: gadget: uvc: hold opts->lock across XU walks in uvc_function_bind
+
+From: Kai Aizen <kai.aizen.dev@gmail.com>
+
+commit 68aa70648b625fa684bc0b71bbfd905f4943ca20 upstream.
+
+uvc_function_bind() walks &opts->extension_units twice without holding
+opts->lock:
+
+  - directly, for the iExtension string-descriptor fixup loop;
+  - indirectly, four times via uvc_copy_descriptors() (once per speed),
+    where the helper iterates uvc->desc.extension_units (which aliases
+    &opts->extension_units) to size and emit XU descriptors.
+
+The configfs side (uvcg_extension_make / uvcg_extension_drop, in
+drivers/usb/gadget/function/uvc_configfs.c) takes opts->lock around its
+list_add_tail / list_del operations.  A privileged userspace process
+that holds the configfs subtree open and writes the gadget UDC name
+to bind the function while concurrently rmdir()'ing an extensions
+subdir can race uvcg_extension_drop() against the bind-time list walks
+and dereference a freed struct uvcg_extension.
+
+Hold opts->lock from the start of the XU string-descriptor fixup
+through the last uvc_copy_descriptors() call, releasing on the
+descriptor-error path via a new error_unlock label that drops the
+lock before falling through to the existing error label.  This
+matches the locking discipline of the configfs callbacks and removes
+the only remaining unsynchronised reader of the XU list during bind.
+
+Reachability: only privileged processes that can mount configfs and
+write to gadget UDC files can trigger the race, so this is a
+correctness fix rather than a security boundary.
+
+Fixes: 0525210c9840 ("usb: gadget: uvc: Allow definition of XUs in configfs")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kai Aizen <kai.aizen.dev@gmail.com>
+Link: https://patch.msgid.link/20260430175643.67120-1-kai.aizen.dev@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/f_uvc.c |   28 +++++++++++++++++++++-------
+ 1 file changed, 21 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_uvc.c
++++ b/drivers/usb/gadget/function/f_uvc.c
+@@ -769,6 +769,16 @@ uvc_function_bind(struct usb_configurati
+       uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+       /*
++       * Hold opts->lock across both the XU string-descriptor fixup below and
++       * the descriptor-copy block further down.  Without this, configfs
++       * uvcg_extension_drop() (which takes opts->lock) can race with the
++       * list_for_each_entry() walks here and inside uvc_copy_descriptors(),
++       * leading to a UAF on a freed struct uvcg_extension.  See
++       * drivers/usb/gadget/function/uvc_configfs.c::uvcg_extension_drop().
++       */
++      mutex_lock(&opts->lock);
++
++      /*
+        * XUs can have an arbitrary string descriptor describing them. If they
+        * have one pick up the ID.
+        */
+@@ -785,7 +795,7 @@ uvc_function_bind(struct usb_configurati
+                                ARRAY_SIZE(uvc_en_us_strings));
+       if (IS_ERR(us)) {
+               ret = PTR_ERR(us);
+-              goto error;
++              goto error_unlock;
+       }
+       uvc_iad.iFunction = opts->iad_index ? cdev->usb_strings[opts->iad_index].id :
+@@ -799,14 +809,14 @@ uvc_function_bind(struct usb_configurati
+       /* Allocate interface IDs. */
+       if ((ret = usb_interface_id(c, f)) < 0)
+-              goto error;
++              goto error_unlock;
+       uvc_iad.bFirstInterface = ret;
+       uvc_control_intf.bInterfaceNumber = ret;
+       uvc->control_intf = ret;
+       opts->control_interface = ret;
+       if ((ret = usb_interface_id(c, f)) < 0)
+-              goto error;
++              goto error_unlock;
+       uvc_streaming_intf_alt0.bInterfaceNumber = ret;
+       uvc_streaming_intf_alt1.bInterfaceNumber = ret;
+       uvc->streaming_intf = ret;
+@@ -817,30 +827,32 @@ uvc_function_bind(struct usb_configurati
+       if (IS_ERR(f->fs_descriptors)) {
+               ret = PTR_ERR(f->fs_descriptors);
+               f->fs_descriptors = NULL;
+-              goto error;
++              goto error_unlock;
+       }
+       f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
+       if (IS_ERR(f->hs_descriptors)) {
+               ret = PTR_ERR(f->hs_descriptors);
+               f->hs_descriptors = NULL;
+-              goto error;
++              goto error_unlock;
+       }
+       f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
+       if (IS_ERR(f->ss_descriptors)) {
+               ret = PTR_ERR(f->ss_descriptors);
+               f->ss_descriptors = NULL;
+-              goto error;
++              goto error_unlock;
+       }
+       f->ssp_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER_PLUS);
+       if (IS_ERR(f->ssp_descriptors)) {
+               ret = PTR_ERR(f->ssp_descriptors);
+               f->ssp_descriptors = NULL;
+-              goto error;
++              goto error_unlock;
+       }
++      mutex_unlock(&opts->lock);
++
+       /* Preallocate control endpoint request. */
+       uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
+       uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
+@@ -872,6 +884,8 @@ uvc_function_bind(struct usb_configurati
+       return 0;
++error_unlock:
++      mutex_unlock(&opts->lock);
+ v4l2_error:
+       v4l2_device_unregister(&uvc->v4l2_dev);
+ error:
diff --git a/queue-6.18/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch b/queue-6.18/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch
new file mode 100644 (file)
index 0000000..5d31c80
--- /dev/null
@@ -0,0 +1,49 @@
+From e194ce048f5a6c549b3a23a8c568c6470f40f772 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+Date: Thu, 9 Apr 2026 10:11:04 +0000
+Subject: usb: musb: omap2430: Fix use-after-free in omap2430_probe()
+
+From: Wentao Liang <vulab@iscas.ac.cn>
+
+commit e194ce048f5a6c549b3a23a8c568c6470f40f772 upstream.
+
+In omap2430_probe(), of_node_put(np) is called prematurely before the
+last access to np, leading to a use-after-free if the node's reference
+count drops to zero. Move the of_node_put() calls after the last use of
+np in both the success and error paths.
+
+Fixes: ffbe2feac59b ("usb: musb: omap2430: Fix probe regression for missing resources")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
+Link: https://patch.msgid.link/20260409101104.480623-1-vulab@iscas.ac.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/musb/omap2430.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/musb/omap2430.c
++++ b/drivers/usb/musb/omap2430.c
+@@ -338,7 +338,6 @@ static int omap2430_probe(struct platfor
+       } else {
+               device_set_of_node_from_dev(&musb->dev, &pdev->dev);
+       }
+-      of_node_put(np);
+       glue->dev                       = &pdev->dev;
+       glue->musb                      = musb;
+@@ -456,6 +455,7 @@ static int omap2430_probe(struct platfor
+               dev_err(&pdev->dev, "failed to register musb device\n");
+               goto err_disable_rpm;
+       }
++      of_node_put(np);
+       return 0;
+@@ -465,6 +465,7 @@ err_put_control_otghs:
+       if (!IS_ERR(glue->control_otghs))
+               put_device(glue->control_otghs);
+ err_put_musb:
++      of_node_put(np);
+       platform_device_put(musb);
+       return ret;
diff --git a/queue-6.18/usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch b/queue-6.18/usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch
new file mode 100644 (file)
index 0000000..768e4c6
--- /dev/null
@@ -0,0 +1,40 @@
+From 9ddb9c0deca48d2c2a22ebf4d2f35c925a520328 Mon Sep 17 00:00:00 2001
+From: "Stephen J. Fuhry" <fuhrysteve@gmail.com>
+Date: Wed, 13 May 2026 13:14:19 -0400
+Subject: USB: quirks: add NO_LPM for Lenovo ThinkPad USB-C Dock Gen2 hub controllers
+
+From: Stephen J. Fuhry <fuhrysteve@gmail.com>
+
+commit 9ddb9c0deca48d2c2a22ebf4d2f35c925a520328 upstream.
+
+The Lenovo ThinkPad USB-C Dock Gen2 (17ef:a391, 17ef:a392) hub
+controllers exhibit link instability when USB Link Power Management
+is enabled, similar to the dock's Ethernet adapter (17ef:a387) which
+already carries USB_QUIRK_NO_LPM.
+
+When the dock reconnects after a transient disconnect, the hub
+controllers enter LPM states between re-enumeration retries, causing
+repeated disconnect/reconnect cycles lasting up to two minutes.
+Disabling LPM for these devices restores stable enumeration.
+
+Signed-off-by: Stephen J. Fuhry <fuhrysteve@gmail.com>
+Cc: stable <stable@kernel.org>
+Link: https://patch.msgid.link/20260513171419.44849-1-fuhrysteve@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/core/quirks.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -514,6 +514,10 @@ static const struct usb_device_id usb_qu
+       /* Lenovo ThinkPad USB-C Dock Gen2 Ethernet (RTL8153 GigE) */
+       { USB_DEVICE(0x17ef, 0xa387), .driver_info = USB_QUIRK_NO_LPM },
++      /* Lenovo ThinkPad USB-C Dock Gen2 USB 3.1 and USB 2.0 hub controllers */
++      { USB_DEVICE(0x17ef, 0xa391), .driver_info = USB_QUIRK_NO_LPM },
++      { USB_DEVICE(0x17ef, 0xa392), .driver_info = USB_QUIRK_NO_LPM },
++
+       /* BUILDWIN Photo Frame */
+       { USB_DEVICE(0x1908, 0x1315), .driver_info =
+                       USB_QUIRK_HONOR_BNUMINTERFACES },
diff --git a/queue-6.18/usb-serial-belkin_sa-validate-interrupt-status-length.patch b/queue-6.18/usb-serial-belkin_sa-validate-interrupt-status-length.patch
new file mode 100644 (file)
index 0000000..f25e550
--- /dev/null
@@ -0,0 +1,50 @@
+From 4ce058df2ee02cc2a0f0fd5cd64ce6f1482a0b65 Mon Sep 17 00:00:00 2001
+From: Zhang Cen <rollkingzzc@gmail.com>
+Date: Tue, 19 May 2026 19:11:50 +0800
+Subject: USB: serial: belkin_sa: validate interrupt status length
+
+From: Zhang Cen <rollkingzzc@gmail.com>
+
+commit 4ce058df2ee02cc2a0f0fd5cd64ce6f1482a0b65 upstream.
+
+The Belkin interrupt callback treats interrupt data as a four-byte
+status report and reads LSR/MSR fields at offsets 2 and 3. The
+interrupt-in buffer length is derived from endpoint wMaxPacketSize, and
+short interrupt transfers may complete successfully with a smaller
+actual_length.
+
+Check the completed interrupt packet length before parsing status
+fields so short interrupt endpoints and short successful packets are
+ignored instead of causing out-of-bounds or stale status-byte reads.
+
+KASAN report as below:
+
+BUG: KASAN: slab-out-of-bounds in belkin_sa_read_int_callback()
+Read of size 1
+Call trace:
+  belkin_sa_read_int_callback() (drivers/usb/serial/belkin_sa.c:202)
+  __usb_hcd_giveback_urb() (drivers/usb/core/hcd.c:1630)
+  dummy_timer() (?:?)
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/belkin_sa.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/usb/serial/belkin_sa.c
++++ b/drivers/usb/serial/belkin_sa.c
+@@ -194,6 +194,9 @@ static void belkin_sa_read_int_callback(
+       usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
++      if (urb->actual_length < BELKIN_SA_MSR_INDEX + 1)
++              goto exit;
++
+       /* Handle known interrupt data */
+       /* ignore data[0] and data[1] */
diff --git a/queue-6.18/usb-serial-cypress_m8-validate-interrupt-packet-headers.patch b/queue-6.18/usb-serial-cypress_m8-validate-interrupt-packet-headers.patch
new file mode 100644 (file)
index 0000000..89c6879
--- /dev/null
@@ -0,0 +1,86 @@
+From 9f9bfc80c67f35a275820da7e83a35dface08281 Mon Sep 17 00:00:00 2001
+From: Zhang Cen <rollkingzzc@gmail.com>
+Date: Fri, 22 May 2026 22:54:42 +0800
+Subject: USB: serial: cypress_m8: validate interrupt packet headers
+
+From: Zhang Cen <rollkingzzc@gmail.com>
+
+commit 9f9bfc80c67f35a275820da7e83a35dface08281 upstream.
+
+cypress_read_int_callback() parses the interrupt-in buffer according to
+the selected Cypress packet format. Format 1 has a two-byte status/count
+header and format 2 has a one-byte combined status/count header. The
+usb-serial core sizes the interrupt-in buffer from the endpoint
+descriptor's wMaxPacketSize, and successful interrupt transfers can
+complete short when URB_SHORT_NOT_OK is not set.
+
+Check that the completed packet contains the selected header before
+reading it. Malformed short reports are ignored and the interrupt URB is
+resubmitted through the existing retry path, preventing out-of-bounds
+header-byte reads.
+
+KASAN report as below:
+KASAN slab-out-of-bounds in cypress_read_int_callback+0x240/0x7f0
+Read of size 1
+Call trace:
+  cypress_read_int_callback() (drivers/usb/serial/cypress_m8.c:1009)
+  __usb_hcd_giveback_urb()
+  dummy_timer()
+
+Fixes: 3416eaa1f8f8 ("USB: cypress_m8: Packet format is separate from characteristic size")
+Assisted-by: Codex:gpt-5.5
+Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>
+Fixes: 3416eaa1f8f8 ("USB: cypress_m8: Packet format is separate from characteristic size")
+Cc: stable@vger.kernel.org     # 2.6.26
+[ johan: use constants in header length sanity checks ]
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/cypress_m8.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -1017,8 +1017,8 @@ static void cypress_read_int_callback(st
+       char tty_flag = TTY_NORMAL;
+       int bytes = 0;
+       int result;
+-      int i = 0;
+       int status = urb->status;
++      int i;
+       switch (status) {
+       case 0: /* success */
+@@ -1056,22 +1056,32 @@ static void cypress_read_int_callback(st
+       spin_lock_irqsave(&priv->lock, flags);
+       result = urb->actual_length;
++      i = 0;
+       switch (priv->pkt_fmt) {
+       default:
+       case packet_format_1:
+               /* This is for the CY7C64013... */
++              if (result < 2)
++                      break;
+               priv->current_status = data[0] & 0xF8;
+               bytes = data[1] + 2;
+               i = 2;
+               break;
+       case packet_format_2:
+               /* This is for the CY7C63743... */
++              if (result < 1)
++                      break;
+               priv->current_status = data[0] & 0xF8;
+               bytes = (data[0] & 0x07) + 1;
+               i = 1;
+               break;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
++      if (i == 0) {
++              dev_dbg(dev, "%s - short packet received: %d bytes\n",
++                      __func__, result);
++              goto continue_read;
++      }
+       if (result < bytes) {
+               dev_dbg(dev,
+                       "%s - wrong packet size - received %d bytes but packet said %d bytes\n",
diff --git a/queue-6.18/usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch b/queue-6.18/usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch
new file mode 100644 (file)
index 0000000..d47521a
--- /dev/null
@@ -0,0 +1,34 @@
+From ab8336a7e414f018430aa1af3a46944032f7ff96 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Wed, 20 May 2026 16:26:48 +0200
+Subject: USB: serial: keyspan: fix missing indat transfer sanity check
+
+From: Johan Hovold <johan@kernel.org>
+
+commit ab8336a7e414f018430aa1af3a46944032f7ff96 upstream.
+
+Add the missing sanity check on the size of usa49wg indat transfers to
+avoid parsing stale or uninitialised slab data.
+
+Fixes: 0ca1268e109a ("USB Serial Keyspan: add support for USA-49WG & USA-28XG")
+Cc: stable@vger.kernel.org     # 2.6.23
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/keyspan.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/usb/serial/keyspan.c
++++ b/drivers/usb/serial/keyspan.c
+@@ -1187,6 +1187,10 @@ static void usa49wg_indat_callback(struc
+       len = 0;
+       while (i < urb->actual_length) {
++              if (urb->actual_length - i < 3) {
++                      dev_warn_ratelimited(&urb->dev->dev, "malformed indat packet\n");
++                      break;
++              }
+               /* Check port number from message */
+               if (data[i] >= serial->num_ports) {
diff --git a/queue-6.18/usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch b/queue-6.18/usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch
new file mode 100644 (file)
index 0000000..6e49089
--- /dev/null
@@ -0,0 +1,36 @@
+From 245aba83e3c288e176ed037a1f6b618b09e92ed8 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Wed, 20 May 2026 16:27:10 +0200
+Subject: USB: serial: mct_u232: fix missing interrupt-in transfer sanity check
+
+From: Johan Hovold <johan@kernel.org>
+
+commit 245aba83e3c288e176ed037a1f6b618b09e92ed8 upstream.
+
+Add the missing sanity check on the size of interrupt-in transfers to
+avoid parsing stale or uninitialised slab data (and leaking it to user
+space).
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@vger.kernel.org
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/mct_u232.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/usb/serial/mct_u232.c
++++ b/drivers/usb/serial/mct_u232.c
+@@ -543,6 +543,11 @@ static void mct_u232_read_int_callback(s
+               goto exit;
+       }
++      if (urb->actual_length < 2) {
++              dev_warn_ratelimited(&port->dev, "short interrupt-in packet\n");
++              goto exit;
++      }
++
+       /*
+        * The interrupt-in pipe signals exceptional conditions (modem line
+        * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
diff --git a/queue-6.18/usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch b/queue-6.18/usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch
new file mode 100644 (file)
index 0000000..556573c
--- /dev/null
@@ -0,0 +1,40 @@
+From 4085f0dbb1ce2251c9a5938d693de6593f0ab2bd Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Fri, 22 May 2026 16:19:50 +0200
+Subject: USB: serial: mxuport: fix memory corruption with small endpoint
+
+From: Johan Hovold <johan@kernel.org>
+
+commit 4085f0dbb1ce2251c9a5938d693de6593f0ab2bd upstream.
+
+Make sure that the bulk-out endpoint max packet size is at least eight
+bytes to avoid user-controlled slab corruption should a malicious device
+report a smaller size.
+
+Fixes: ee467a1f2066 ("USB: serial: add Moxa UPORT 12XX/14XX/16XX driver")
+Cc: stable@vger.kernel.org     # 3.14
+Cc: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/mxuport.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/usb/serial/mxuport.c
++++ b/drivers/usb/serial/mxuport.c
+@@ -962,6 +962,14 @@ static int mxuport_calc_num_ports(struct
+        */
+       BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < 16);
++      /*
++       * The bulk-out buffers must be large enough for the four-byte header
++       * (and following data), but assume anything smaller than eight bytes
++       * is broken.
++       */
++      if (usb_endpoint_maxp(epds->bulk_out[0]) < 8)
++              return -EINVAL;
++
+       for (i = 1; i < num_ports; ++i)
+               epds->bulk_out[i] = epds->bulk_out[0];
diff --git a/queue-6.18/usb-serial-option-add-meig-srm813q.patch b/queue-6.18/usb-serial-option-add-meig-srm813q.patch
new file mode 100644 (file)
index 0000000..cefd008
--- /dev/null
@@ -0,0 +1,94 @@
+From 7d2b37d3e42d19071b62f4ddbee6e16e905efbf1 Mon Sep 17 00:00:00 2001
+From: Jan Volckaert <janvolck@gmail.com>
+Date: Sun, 17 May 2026 17:32:37 +0200
+Subject: USB: serial: option: add MeiG SRM813Q
+
+From: Jan Volckaert <janvolck@gmail.com>
+
+commit 7d2b37d3e42d19071b62f4ddbee6e16e905efbf1 upstream.
+
+Add support for the Qualcomm Technology Snapdragon X35-based MeiG
+SRM813Q module.
+
+The module can be put in different modes via AT commands to
+enable/disable GPS functionality:
+
+MODEM - PPP mode(2dee:4d63): AT+SER=1,1
+
+If#= 0: RMNET
+If#= 1: DIAG/ADB
+If#= 2: MODEM
+If#= 3: AT
+
+P:  Vendor=2dee ProdID=4d63 Rev=05.15
+S:  Manufacturer=MEIG
+S:  Product=LTE-A Module
+S:  SerialNumber=1bd51f0e
+C:  #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=500mA
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan
+E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=82(I) Atr=03(Int.) MxPS=   8 Ivl=32ms
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:  If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option
+E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=85(I) Atr=03(Int.) MxPS=  10 Ivl=32ms
+I:  If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option
+E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=87(I) Atr=03(Int.) MxPS=  10 Ivl=32ms
+
+NMEA mode(2dee:4d64): AT+SER=51,1
+
+If#= 0: RMNET
+If#= 1: DIAG/ADB
+If#= 2: NMEA
+If#= 3: AT
+
+P:  Vendor=2dee ProdID=4d64 Rev=05.15
+S:  Manufacturer=MEIG
+S:  Product=LTE-A Module
+S:  SerialNumber=1bd51f0e
+C:  #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=500mA
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan
+E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=82(I) Atr=03(Int.) MxPS=   8 Ivl=32ms
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:  If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option
+E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=85(I) Atr=03(Int.) MxPS=  10 Ivl=32ms
+I:  If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option
+E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=87(I) Atr=03(Int.) MxPS=  10 Ivl=32ms
+
+Signed-off-by: Jan Volckaert <janvolck@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/option.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -2450,6 +2450,12 @@ static const struct usb_device_id option
+       { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) },    /* MeiG Smart SRM825WN (Diag) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) },    /* MeiG Smart SRM825WN (AT) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) },    /* MeiG Smart SRM825WN (NMEA) */
++      { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d63, 0xff, 0xff, 0x30) },    /* MeiG SRM813Q (Diag) */
++      { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d63, 0xff, 0xff, 0x40) },    /* MeiG SRM813Q (AT) */
++      { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x30) },    /* MeiG SRM813Q (Diag) */
++      { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x40) },    /* MeiG SRM813Q (AT) */
++      { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x60) },    /* MeiG SRM813Q (NMEA) */
++
+       { USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) },                   /* LongSung M5710 */
+       { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) },                   /* GosunCn GM500 RNDIS */
+       { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) },                   /* GosunCn GM500 MBIM */
diff --git a/queue-6.18/usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch b/queue-6.18/usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch
new file mode 100644 (file)
index 0000000..4da87da
--- /dev/null
@@ -0,0 +1,132 @@
+From 689f2facc689c8add11d7ff69fbbad17d65ee596 Mon Sep 17 00:00:00 2001
+From: Wanquan Zhong <wanquan.zhong@fibocom.com>
+Date: Wed, 20 May 2026 19:32:45 +0800
+Subject: USB: serial: option: add missing RSVD(5) flag for Rolling RW135R-GL
+
+From: Wanquan Zhong <wanquan.zhong@fibocom.com>
+
+commit 689f2facc689c8add11d7ff69fbbad17d65ee596 upstream.
+
+The RW135R-GL entry added in commit 01e8d0f74222 ("USB: serial: option:
+add support for Rolling Wireless RW135R-GL") was missing the
+.driver_info = RSVD(5) flag used by other Rolling Wireless MBIM laptop
+modules (e.g. RW135-GL and RW350-GL).
+
+Without this flag, the option driver incorrectly binds to the reserved
+ADB interface (If#5) in multi-interface USB modes, causing AT/MBIM
+communication failures after mode switching. This matches the handling
+of other Rolling Wireless MBIM devices.
+
+- VID:PID 33f8:1003, RW135R-GL for laptop debug M.2 cards (with MBIM
+  interface for Linux/Chrome OS)
+
+  0x1003: mbim, diag, AT, pipe
+
+  Here are the outputs of usb-devices:
+
+T:  Bus=03 Lev=01 Prnt=01 Port=04 Cnt=02 Dev#=  8 Spd=480  MxCh= 0
+D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+P:  Vendor=33f8 ProdID=1003 Rev= 5.15
+S:  Manufacturer=Rolling Wireless S.a.r.l.
+S:  Product=Rolling RW135R-GL Module
+S:  SerialNumber=12345678
+C:* #Ifs= 5 Cfg#= 1 Atr=a0 MxPwr=500mA
+A:  FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0e Prot=00
+I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0e Prot=00 Driver=cdc_mbim
+E:  Ad=82(I) Atr=03(Int.) MxPS=  64 Ivl=32ms
+I:  If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim
+I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option
+E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option
+E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option
+E:  Ad=86(I) Atr=03(Int.) MxPS=  10 Ivl=32ms
+E:  Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+- VID:PID 33f8:1003, RW135R-GL for laptop debug M.2 cards (with MBIM
+  interface for Linux/Chrome OS)
+
+  0x1003: mbim, diag, AT, ADB, pipe
+
+  Here are the outputs of usb-devices:
+
+T:  Bus=03 Lev=01 Prnt=01 Port=04 Cnt=02 Dev#=  7 Spd=480  MxCh= 0
+D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+P:  Vendor=33f8 ProdID=1003 Rev= 5.15
+S:  Manufacturer=Rolling Wireless S.a.r.l.
+S:  Product=Rolling RW135R-GL Module
+S:  SerialNumber=12345678
+C:* #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA
+A:  FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0e Prot=00
+I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0e Prot=00 Driver=cdc_mbim
+E:  Ad=82(I) Atr=03(Int.) MxPS=  64 Ivl=32ms
+I:  If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim
+I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option
+E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option
+E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option
+E:  Ad=86(I) Atr=03(Int.) MxPS=  10 Ivl=32ms
+E:  Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none)
+E:  Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+- VID:PID 33f8:1003, RW135R-GL for laptop debug M.2 cards (with MBIM
+  interface for Linux/Chrome OS)
+
+  0x1003: mbim, pipe
+
+  Here are the outputs of usb-devices:
+
+T:  Bus=03 Lev=01 Prnt=01 Port=04 Cnt=02 Dev#=  9 Spd=480  MxCh= 0
+D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+P:  Vendor=33f8 ProdID=1003 Rev= 5.15
+S:  Manufacturer=Rolling Wireless S.a.r.l.
+S:  Product=Rolling RW135R-GL Module
+S:  SerialNumber=12345678
+C:* #Ifs= 3 Cfg#= 1 Atr=a0 MxPwr=500mA
+A:  FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=0e Prot=00
+I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0e Prot=00 Driver=cdc_mbim
+E:  Ad=82(I) Atr=03(Int.) MxPS=  64 Ivl=32ms
+I:  If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim
+I:* If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option
+E:  Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+Fixes: 01e8d0f74222 ("USB: serial: option: add support for Rolling Wireless RW135R-GL")
+Signed-off-by: Wanquan Zhong <wanquan.zhong@fibocom.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/option.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -2476,7 +2476,8 @@ static const struct usb_device_id option
+       { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) },                   /* Rolling RW101R-GL (laptop MBIM) */
+       { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff),                     /* Rolling RW350-GL (laptop MBIM) */
+         .driver_info = RSVD(5) },
+-      { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff) },                   /* Rolling RW135R-GL (laptop MBIM) */
++      { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff),                     /* Rolling RW135R-GL (laptop MBIM) */
++        .driver_info = RSVD(5) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) },    /* NetPrisma LCUK54-WWD for Global */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
diff --git a/queue-6.18/usb-storage-add-quirks-for-pny-elite-portable-ssd.patch b/queue-6.18/usb-storage-add-quirks-for-pny-elite-portable-ssd.patch
new file mode 100644 (file)
index 0000000..94606da
--- /dev/null
@@ -0,0 +1,69 @@
+From b53ebb811e00be50a779ce4e7aee604178b4a825 Mon Sep 17 00:00:00 2001
+From: Sam Burkels <sam@1a38.nl>
+Date: Fri, 1 May 2026 15:23:46 +0200
+Subject: usb: storage: Add quirks for PNY Elite Portable SSD
+
+From: Sam Burkels <sam@1a38.nl>
+
+commit b53ebb811e00be50a779ce4e7aee604178b4a825 upstream.
+
+The PNY Elite Portable SSD (USB ID 154b:f009) is a sibling of the
+already-quirked PNY Pro Elite SSDs (154b:f00b and 154b:f00d). Like its
+siblings, it uses a Phison-based USB-SATA bridge that exhibits
+firmware bugs when bound to the uas driver.
+
+Without quirks, the device fails to complete READ CAPACITY commands
+when accessed over UAS on a SuperSpeed (USB 3) port. The device
+enumerates and reports as a SCSI direct-access device, but reports
+zero logical blocks and never finishes spin-up:
+
+    usb 2-3: new SuperSpeed USB device number 8 using xhci_hcd
+    usb 2-3: New USB device found, idVendor=154b, idProduct=f009
+    usb 2-3: Product: PNY ELITE PSSD
+    usb 2-3: Manufacturer: PNY
+    scsi host0: uas
+    scsi 0:0:0:0: Direct-Access     PNY      PNY ELITE PSSD   0
+    sd 0:0:0:0: [sda] Spinning up disk...
+    [...10+ seconds of polling, no progress...]
+    sd 0:0:0:0: [sda] Read Capacity(16) failed: hostbyte=DID_ERROR
+    sd 0:0:0:0: [sda] Read Capacity(10) failed: hostbyte=DID_ERROR
+    sd 0:0:0:0: [sda] 0 512-byte logical blocks: (0 B/0 B)
+
+Tested each individual quirk to find the minimum that fixes this:
+  - US_FL_NO_ATA_1X alone: device hangs on spin-up
+  - US_FL_NO_REPORT_OPCODES alone: works on USB 2.0, hangs on USB 3.0
+  - US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES: works on both
+
+With both quirks the device enumerates correctly while still using
+the uas driver, and delivers full UAS throughput (~281 MB/s
+sequential read on a USB 3.0 Gen 1 port).
+
+The existing PNY Pro Elite entries (f00b, f00d) only set NO_ATA_1X,
+but this device additionally chokes on REPORT OPCODES under
+SuperSpeed.
+
+Signed-off-by: Sam Burkels <sam@1a38.nl>
+Acked-by: Oliver Neukum <oneukum@suse.com>
+Cc: stable <stable@kernel.org>
+Link: https://patch.msgid.link/20260501132346.86572-1-sam@1a38.nl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/storage/unusual_uas.h |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/usb/storage/unusual_uas.h
++++ b/drivers/usb/storage/unusual_uas.h
+@@ -132,6 +132,13 @@ UNUSUAL_DEV(0x152d, 0x0583, 0x0000, 0x99
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
++/* Reported-by: Sam Burkels <sam@1a38.nl> */
++UNUSUAL_DEV(0x154b, 0xf009, 0x0000, 0x9999,
++              "PNY",
++              "PNY ELITE PSSD",
++              USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++              US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES),
++
+ /* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
+ UNUSUAL_DEV(0x154b, 0xf00b, 0x0000, 0x9999,
+               "PNY",
diff --git a/queue-6.18/usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch b/queue-6.18/usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch
new file mode 100644 (file)
index 0000000..59e9094
--- /dev/null
@@ -0,0 +1,185 @@
+From c06e6cd488194e37ed4dc29d1488d1ffb760de60 Mon Sep 17 00:00:00 2001
+From: Sebastian Reichel <sebastian.reichel@collabora.com>
+Date: Wed, 29 Apr 2026 18:33:32 +0200
+Subject: usb: typec: tcpm: improve handling of DISCOVER_MODES failures
+
+From: Sebastian Reichel <sebastian.reichel@collabora.com>
+
+commit c06e6cd488194e37ed4dc29d1488d1ffb760de60 upstream.
+
+UGREEN USB-C Multifunction Adapter Model CM512 (AKA "Revodok 107")
+exposes two SVIDs: 0xff01 (DP Alt Mode) and 0x1d5c. The DISCOVER_MODES
+step succeeds for 0xff01 and gets a NAK for 0x1d5c. Currently this
+results in DP Alt Mode not being registered either, since the modes
+are only registered once all of them have been discovered. The NAK
+results in the processing being stopped and thus no Alt modes being
+registered.
+
+Improve the situation by handling the NAK gracefully and continue
+processing the other modes.
+
+Before this change, the TCPM log ends like this:
+
+(more log entries before this)
+[    5.028287] AMS DISCOVER_SVIDS finished
+[    5.028291] cc:=4
+[    5.040040] SVID 1: 0xff01
+[    5.040054] SVID 2: 0x1d5c
+[    5.040082] AMS DISCOVER_MODES start
+[    5.040096] PD TX, header: 0x1b6f
+[    5.050946] PD TX complete, status: 0
+[    5.059609] PD RX, header: 0x264f [1]
+[    5.059626] Rx VDM cmd 0xff018043 type 1 cmd 3 len 2
+[    5.059640] AMS DISCOVER_MODES finished
+[    5.059644] cc:=4
+[    5.069994]  Alternate mode 0: SVID 0xff01, VDO 1: 0x000c0045
+[    5.070029] AMS DISCOVER_MODES start
+[    5.070043] PD TX, header: 0x1d6f
+[    5.081139] PD TX complete, status: 0
+[    5.087498] PD RX, header: 0x184f [1]
+[    5.087515] Rx VDM cmd 0x1d5c8083 type 2 cmd 3 len 1
+[    5.087529] AMS DISCOVER_MODES finished
+[    5.087534] cc:=4
+(no further log entries after this point)
+
+After this patch the TCPM log looks exactly the same, but then
+continues like this:
+
+[    5.100222] Skip SVID 0x1d5c (failed to discover mode)
+[    5.101699] AMS DFP_TO_UFP_ENTER_MODE start
+(log goes on as the system initializes DP AltMode)
+
+Cc: stable <stable@kernel.org>
+Fixes: 41d9d75344d9 ("usb: typec: tcpm: add discover svids and discover modes support for sop'")
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Reviewed-by: RD Babiera <rdbabiera@google.com>
+Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
+Link: https://patch.msgid.link/20260429-tcpm-discover-modes-nak-fix-v4-1-75945d0ed30f@collabora.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/tcpm/tcpm.c |   97 ++++++++++++++++++++++++++----------------
+ 1 file changed, 61 insertions(+), 36 deletions(-)
+
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -1989,6 +1989,55 @@ static bool tcpm_cable_vdm_supported(str
+              tcpm_can_communicate_sop_prime(port);
+ }
++static int tcpm_handle_discover_mode(struct tcpm_port *port, u32 *response,
++                                   enum tcpm_transmit_type rx_sop_type,
++                                   enum tcpm_transmit_type *response_tx_sop_type)
++{
++      struct typec_port *typec = port->typec_port;
++      struct pd_mode_data *modep;
++
++      if (rx_sop_type == TCPC_TX_SOP) {
++              modep = &port->mode_data;
++              modep->svid_index++;
++
++              if (modep->svid_index < modep->nsvids) {
++                      u16 svid = modep->svids[modep->svid_index];
++                      *response_tx_sop_type = TCPC_TX_SOP;
++                      response[0] = VDO(svid, 1,
++                                        typec_get_negotiated_svdm_version(typec),
++                                        CMD_DISCOVER_MODES);
++                      return 1;
++              }
++
++              if (tcpm_cable_vdm_supported(port)) {
++                      *response_tx_sop_type = TCPC_TX_SOP_PRIME;
++                      response[0] = VDO(USB_SID_PD, 1,
++                                        typec_get_cable_svdm_version(typec),
++                                        CMD_DISCOVER_SVID);
++                      return 1;
++              }
++
++              tcpm_register_partner_altmodes(port);
++      } else if (rx_sop_type == TCPC_TX_SOP_PRIME) {
++              modep = &port->mode_data_prime;
++              modep->svid_index++;
++
++              if (modep->svid_index < modep->nsvids) {
++                      u16 svid = modep->svids[modep->svid_index];
++                      *response_tx_sop_type = TCPC_TX_SOP_PRIME;
++                      response[0] = VDO(svid, 1,
++                                        typec_get_cable_svdm_version(typec),
++                                        CMD_DISCOVER_MODES);
++                      return 1;
++              }
++
++              tcpm_register_plug_altmodes(port);
++              tcpm_register_partner_altmodes(port);
++      }
++
++      return 0;
++}
++
+ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
+                       const u32 *p, int cnt, u32 *response,
+                       enum adev_actions *adev_action,
+@@ -2246,41 +2295,11 @@ static int tcpm_pd_svdm(struct tcpm_port
+                       }
+                       break;
+               case CMD_DISCOVER_MODES:
+-                      if (rx_sop_type == TCPC_TX_SOP) {
+-                              /* 6.4.4.3.3 */
+-                              svdm_consume_modes(port, p, cnt, rx_sop_type);
+-                              modep->svid_index++;
+-                              if (modep->svid_index < modep->nsvids) {
+-                                      u16 svid = modep->svids[modep->svid_index];
+-                                      *response_tx_sop_type = TCPC_TX_SOP;
+-                                      response[0] = VDO(svid, 1, svdm_version,
+-                                                        CMD_DISCOVER_MODES);
+-                                      rlen = 1;
+-                              } else if (tcpm_cable_vdm_supported(port)) {
+-                                      *response_tx_sop_type = TCPC_TX_SOP_PRIME;
+-                                      response[0] = VDO(USB_SID_PD, 1,
+-                                                        typec_get_cable_svdm_version(typec),
+-                                                        CMD_DISCOVER_SVID);
+-                                      rlen = 1;
+-                              } else {
+-                                      tcpm_register_partner_altmodes(port);
+-                              }
+-                      } else if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+-                              /* 6.4.4.3.3 */
+-                              svdm_consume_modes(port, p, cnt, rx_sop_type);
+-                              modep_prime->svid_index++;
+-                              if (modep_prime->svid_index < modep_prime->nsvids) {
+-                                      u16 svid = modep_prime->svids[modep_prime->svid_index];
+-                                      *response_tx_sop_type = TCPC_TX_SOP_PRIME;
+-                                      response[0] = VDO(svid, 1,
+-                                                        typec_get_cable_svdm_version(typec),
+-                                                        CMD_DISCOVER_MODES);
+-                                      rlen = 1;
+-                              } else {
+-                                      tcpm_register_plug_altmodes(port);
+-                                      tcpm_register_partner_altmodes(port);
+-                              }
+-                      }
++                      /* 6.4.4.3.3 */
++                      svdm_consume_modes(port, p, cnt, rx_sop_type);
++                      rlen = tcpm_handle_discover_mode(port, response,
++                                                       rx_sop_type,
++                                                       response_tx_sop_type);
+                       break;
+               case CMD_ENTER_MODE:
+                       *response_tx_sop_type = rx_sop_type;
+@@ -2323,9 +2342,15 @@ static int tcpm_pd_svdm(struct tcpm_port
+               switch (cmd) {
+               case CMD_DISCOVER_IDENT:
+               case CMD_DISCOVER_SVID:
+-              case CMD_DISCOVER_MODES:
+               case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15):
+                       break;
++              case CMD_DISCOVER_MODES:
++                      tcpm_log(port, "Skip SVID 0x%04x (failed to discover mode)",
++                               PD_VDO_SVID_SVID0(p[0]));
++                      rlen = tcpm_handle_discover_mode(port, response,
++                                                       rx_sop_type,
++                                                       response_tx_sop_type);
++                      break;
+               case CMD_ENTER_MODE:
+                       /* Back to USB Operation */
+                       *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
diff --git a/queue-6.18/usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch b/queue-6.18/usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch
new file mode 100644 (file)
index 0000000..1201064
--- /dev/null
@@ -0,0 +1,33 @@
+From b02900c85a6423cf9b3dcc6b47bf060c85075e69 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <error27@gmail.com>
+Date: Tue, 12 May 2026 13:14:59 +0300
+Subject: usb: typec: tipd: Fix error code in tps6598x_probe()
+
+From: Dan Carpenter <error27@gmail.com>
+
+commit b02900c85a6423cf9b3dcc6b47bf060c85075e69 upstream.
+
+Set the error code on these two error paths.  The existing code returns
+success.
+
+Fixes: 77ed2f4538da ("usb: typec: tipd: Use read_power_status function in probe")
+Fixes: 04041fd7d6ec ("usb: typec: tipd: Read data status in probe and cache its value")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/agL9o7wUK1dOVBTy@stanley.mountain
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/tipd/core.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/typec/tipd/core.c
++++ b/drivers/usb/typec/tipd/core.c
+@@ -1828,6 +1828,7 @@ static int tps6598x_probe(struct i2c_cli
+               goto err_role_put;
+       if (status & TPS_STATUS_PLUG_PRESENT) {
++              ret = -EINVAL;
+               if (!tps6598x_read_power_status(tps))
+                       goto err_unregister_port;
+               if (!tps->data->read_data_status(tps))
diff --git a/queue-6.18/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch b/queue-6.18/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch
new file mode 100644 (file)
index 0000000..1d6c618
--- /dev/null
@@ -0,0 +1,63 @@
+From b80e7d34c7ea6a564525119d6138fbb577a23dba Mon Sep 17 00:00:00 2001
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Date: Tue, 19 May 2026 18:41:39 +0700
+Subject: usb: typec: ucsi: Check if power role change actually happened before handling
+
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+
+commit b80e7d34c7ea6a564525119d6138fbb577a23dba upstream.
+
+The CrOS EC may send a connector status change event with the power
+direction changed flag set even if the power direction hasn't actually
+changed after initiating a SET_PDR command internally [1]. In practice
+this happens on every system suspend due to other changes performed by
+the EC [2][3][4], causing suspend to fail.
+
+Fix this by checking if the power role change actually happened before
+handling it.
+
+[1]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=1689;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+[2]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=3923;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+[3]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=5094;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+[4]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/ec/zephyr/subsys/pd_controller/pdc_power_mgmt.c;l=2229;drc=2d5a1cffce4e5ac8a39442cb3b764d2d5e1cf794
+
+Cc: stable <stable@kernel.org>
+Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change")
+Signed-off-by: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Reported-and-tested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1224,7 +1224,7 @@ static void ucsi_handle_connector_change
+                                                 work);
+       struct ucsi *ucsi = con->ucsi;
+       u8 curr_scale, volt_scale;
+-      enum typec_role role;
++      enum typec_role role, prev_role;
+       u16 change;
+       int ret;
+       u32 val;
+@@ -1235,6 +1235,8 @@ static void ucsi_handle_connector_change
+               dev_err_once(ucsi->dev, "%s entered without EVENT_PENDING\n",
+                            __func__);
++      prev_role = UCSI_CONSTAT(con, PWR_DIR);
++
+       ret = ucsi_get_connector_status(con, true);
+       if (ret) {
+               dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
+@@ -1251,7 +1253,7 @@ static void ucsi_handle_connector_change
+       change = UCSI_CONSTAT(con, CHANGE);
+       role = UCSI_CONSTAT(con, PWR_DIR);
+-      if (change & UCSI_CONSTAT_POWER_DIR_CHANGE) {
++      if ((change & UCSI_CONSTAT_POWER_DIR_CHANGE) && role != prev_role) {
+               typec_set_pwr_role(con->port, role);
+               ucsi_port_psy_changed(con);
diff --git a/queue-6.18/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch b/queue-6.18/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch
new file mode 100644 (file)
index 0000000..f50af92
--- /dev/null
@@ -0,0 +1,39 @@
+From d98d413ca65d0790a8f3695d0a5845538958ab84 Mon Sep 17 00:00:00 2001
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Date: Tue, 19 May 2026 18:41:40 +0700
+Subject: usb: typec: ucsi: Don't update power_supply on power role change if not connected
+
+From: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+
+commit d98d413ca65d0790a8f3695d0a5845538958ab84 upstream.
+
+We only need to update the power_supply on power role change if the port
+is connected, because otherwise the online status should be the same for
+both cases.
+
+Cc: stable <stable@kernel.org>
+Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change")
+Signed-off-by: Myrrh Periwinkle <myrrhperiwinkle@qtmlabs.xyz>
+Reported-and-tested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
+Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-2-6f1239535187@qtmlabs.xyz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1255,7 +1255,12 @@ static void ucsi_handle_connector_change
+       if ((change & UCSI_CONSTAT_POWER_DIR_CHANGE) && role != prev_role) {
+               typec_set_pwr_role(con->port, role);
+-              ucsi_port_psy_changed(con);
++
++              /* Some power_supply properties vary depending on the power direction when
++               * connected
++               */
++              if (UCSI_CONSTAT(con, CONNECTED))
++                      ucsi_port_psy_changed(con);
+               /* Complete pending power role swap */
+               if (!completion_done(&con->complete))
diff --git a/queue-6.18/usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch b/queue-6.18/usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch
new file mode 100644 (file)
index 0000000..fda50a7
--- /dev/null
@@ -0,0 +1,49 @@
+From 52f2ad3f7e5eb3b5908e1d685d4342519dc9cfcd Mon Sep 17 00:00:00 2001
+From: Heitor Alves de Siqueira <halves@igalia.com>
+Date: Tue, 5 May 2026 15:56:03 -0300
+Subject: usb: usbtmc: check URB actual_length for interrupt-IN notifications
+
+From: Heitor Alves de Siqueira <halves@igalia.com>
+
+commit 52f2ad3f7e5eb3b5908e1d685d4342519dc9cfcd upstream.
+
+USBTMC devices can use an optional interrupt endpoint for notification
+messages. These typically contain two-byte headers indicating the
+payload format, but the driver does not check if these headers are
+present before accessing the data buffers. In cases where the URB
+actual_length is not enough to fit these headers, the driver will either
+cause an out-of-bounds read, or consume stale leftover data from a
+previous notification.
+
+Fix by checking if actual_data contains enough bytes for the headers,
+otherwise resubmit URB to the interrupt endpoint.
+
+Fixes: dbf3e7f654c0 ("Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation.")
+Reported-by: syzbot+abbfd103085885cf16a2@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=abbfd103085885cf16a2
+Cc: stable <stable@kernel.org>
+Suggested-by: Michal Pecio <michal.pecio@gmail.com>
+Signed-off-by: Heitor Alves de Siqueira <halves@igalia.com>
+Link: https://patch.msgid.link/20260505-usbtmc-iin-size-v3-1-a36113f62db7@igalia.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/class/usbtmc.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/usb/class/usbtmc.c
++++ b/drivers/usb/class/usbtmc.c
+@@ -2310,6 +2310,14 @@ static void usbtmc_interrupt(struct urb
+       switch (status) {
+       case 0: /* SUCCESS */
++              /* ensure at least two bytes of headers were transferred */
++              if (urb->actual_length < 2) {
++                      dev_warn(dev,
++                              "actual length %d not sufficient for interrupt headers\n",
++                              urb->actual_length);
++                      goto exit;
++              }
++
+               /* check for valid STB notification */
+               if (data->iin_buffer[0] > 0x81) {
+                       data->bNotify1 = data->iin_buffer[0];
diff --git a/queue-6.18/usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch b/queue-6.18/usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch
new file mode 100644 (file)
index 0000000..d0eaa64
--- /dev/null
@@ -0,0 +1,41 @@
+From 121d2f682ba912b1427cddca7cf84840f41cc620 Mon Sep 17 00:00:00 2001
+From: Heitor Alves de Siqueira <halves@igalia.com>
+Date: Tue, 5 May 2026 15:56:04 -0300
+Subject: usb: usbtmc: reject interrupt endpoints with small wMaxPacketSize
+
+From: Heitor Alves de Siqueira <halves@igalia.com>
+
+commit 121d2f682ba912b1427cddca7cf84840f41cc620 upstream.
+
+The USB488 subclass specification requires interrupt wMaxPacketSize to
+be 0x02, unless the device sends vendor-specific notifications.
+Endpoints that advertise less than 2 bytes for wMaxPacketSize are
+unlikely to work with the current driver, as URBs will not have enough
+space for interrupt headers. Considering that any notification URBs will
+be ignored by the driver, reject these endpoints early during probe.
+
+Fixes: 041370cce889 ("USB: usbtmc: refactor endpoint retrieval")
+Cc: stable <stable@kernel.org>
+Suggested-by: Michal Pecio <michal.pecio@gmail.com>
+Signed-off-by: Heitor Alves de Siqueira <halves@igalia.com>
+Link: https://patch.msgid.link/20260505-usbtmc-iin-size-v3-2-a36113f62db7@igalia.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/class/usbtmc.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/class/usbtmc.c
++++ b/drivers/usb/class/usbtmc.c
+@@ -2444,6 +2444,12 @@ static int usbtmc_probe(struct usb_inter
+               data->iin_ep = int_in->bEndpointAddress;
+               data->iin_wMaxPacketSize = usb_endpoint_maxp(int_in);
+               data->iin_interval = int_in->bInterval;
++              /* wMaxPacketSize should be 0x02 or more as per USB488 Table 22 */
++              if (iface_desc->desc.bInterfaceProtocol == 1 &&
++                  data->iin_wMaxPacketSize < 2) {
++                      retcode = -EINVAL;
++                      goto err_put;
++              }
+               dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
+                               data->iin_ep);
+       }
diff --git a/queue-6.18/usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch b/queue-6.18/usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch
new file mode 100644 (file)
index 0000000..0b9f306
--- /dev/null
@@ -0,0 +1,77 @@
+From d96209626a29ea64666be98c30b30ac82e5f1be6 Mon Sep 17 00:00:00 2001
+From: Michael Bommarito <michael.bommarito@gmail.com>
+Date: Fri, 17 Apr 2026 12:35:52 -0400
+Subject: usbip: vudc: Fix use after free bug in vudc_remove due to race condition
+
+From: Michael Bommarito <michael.bommarito@gmail.com>
+
+commit d96209626a29ea64666be98c30b30ac82e5f1be6 upstream.
+
+This patch follows up Zheng Wang's 2023 report of a use-after-free in
+vudc_remove(). The original thread stalled on Shuah Khan's request for
+runtime testing of the unplug/unbind path. This patch supplies that
+testing and keeps Zheng's original fix shape.
+
+In vudc_probe(), v_init_timer() binds udc->tr_timer.timer to v_timer().
+usbip_sockfd_store() starts the timer via v_start_timer()/v_kick_timer().
+vudc_remove() can then free the containing struct vudc while the timer is
+still pending or executing.
+
+KASAN confirms the race on an unpatched x86_64 QEMU guest with
+CONFIG_KASAN=y, CONFIG_USBIP_VUDC=y, CONFIG_USB_ZERO=y, and a tight loop
+that repeatedly writes a socket fd to usbip_sockfd, closes the socket
+pair, and unbinds/rebinds usbip-vudc.0:
+
+  BUG: KASAN: slab-use-after-free in __run_timer_base.part.0+0x8ba/0x8e0
+  Write of size 8 at addr ffff888001b80740 by task trigger_and_unb/239
+  Allocated by task 239:
+    vudc_probe+0x4d/0xaa0
+  Freed by task 239:
+    kfree+0x18f/0x520
+    device_release_driver_internal+0x388/0x540
+    unbind_store+0xd9/0x100
+
+This lands in the timer core rather than v_timer() itself because the
+embedded timer_list is being walked after its containing struct vudc has
+already been freed. The underlying lifetime bug is the same one Zheng
+reported.
+
+With v_stop_timer() called from vudc_remove() and the timer deleted
+synchronously, the same harness completed 5000 bind/unbind iterations
+with no KASAN report.
+
+Fixes: b6a0ca111867 ("usbip: vudc: Add UDC specific ops")
+Cc: stable <stable@kernel.org>
+Reported-by: Zheng Wang <zyytlz.wz@163.com>
+Closes: https://lore.kernel.org/linux-usb/20230317100954.2626573-1-zyytlz.wz@163.com/
+Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
+Acked-by: Shuah Khan <skhan@linuxfoundation.org>
+Link: https://patch.msgid.link/20260417163552.807548-1-michael.bommarito@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/usbip/vudc_dev.c      |    1 +
+ drivers/usb/usbip/vudc_transfer.c |    3 ++-
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/usbip/vudc_dev.c
++++ b/drivers/usb/usbip/vudc_dev.c
+@@ -632,6 +632,7 @@ void vudc_remove(struct platform_device
+ {
+       struct vudc *udc = platform_get_drvdata(pdev);
++      v_stop_timer(udc);
+       usb_del_gadget_udc(&udc->gadget);
+       cleanup_vudc_hw(udc);
+       kfree(udc);
+--- a/drivers/usb/usbip/vudc_transfer.c
++++ b/drivers/usb/usbip/vudc_transfer.c
+@@ -490,7 +490,8 @@ void v_stop_timer(struct vudc *udc)
+ {
+       struct transfer_timer *t = &udc->tr_timer;
+-      /* timer itself will take care of stopping */
++      /* Delete the timer synchronously before teardown frees udc. */
+       dev_dbg(&udc->pdev->dev, "timer stop");
++      timer_delete_sync(&t->timer);
+       t->state = VUDC_TR_STOPPED;
+ }