From: Greg Kroah-Hartman Date: Thu, 4 Jun 2026 11:02:13 +0000 (+0200) Subject: 7.0-stable patches X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=cd6066fe45131e81fa3adba84d43b2946efc3b22;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches 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-amdgpu_hmm_range_get_pages.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-color-fix-hdr-pre-csc-lut-programming-loop.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 drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch dt-bindings-usb-fix-eic7700-usb-reset-s-issue.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-cap-recursion-depth-in-__tb_property_parse_dir.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 uio-uio_pci_generic_sva-fix-double-free-of-devm_kzalloc-memory.patch usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.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-digi_acceleport-fix-memory-corruption-with-small-endpoints.patch usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch usb-serial-mct_u232-fix-memory-corruption-with-small-endpoint.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 --- diff --git a/queue-7.0/comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch b/queue-7.0/comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch new file mode 100644 index 0000000000..19eb8ef723 --- /dev/null +++ b/queue-7.0/comedi-comedi_test-fix-check-for-valid-scan_begin_src-in-waveform_ai_cmdtest.patch @@ -0,0 +1,37 @@ +From 542f5248cb481073203e0dadab5bcbd28aeae308 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +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 + +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 +Signed-off-by: Ian Abbott +Link: https://patch.msgid.link/20260422162138.36003-1-abbotti@mev.co.uk +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch b/queue-7.0/comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch new file mode 100644 index 0000000000..b36e941b28 --- /dev/null +++ b/queue-7.0/comedi-comedi_test-fix-limiting-of-convert_arg-in-waveform_ai_cmdtest.patch @@ -0,0 +1,69 @@ +From 8a3bee801d420be8a7a0bae4a26547b353b8fe22 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +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 + +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 +Signed-off-by: Ian Abbott +Link: https://patch.msgid.link/20260422144637.27692-1-abbotti@mev.co.uk +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/counter-fix-refcount-leak-in-counter_alloc-error-path.patch b/queue-7.0/counter-fix-refcount-leak-in-counter_alloc-error-path.patch new file mode 100644 index 0000000000..999f74b368 --- /dev/null +++ b/queue-7.0/counter-fix-refcount-leak-in-counter_alloc-error-path.patch @@ -0,0 +1,47 @@ +From d9eeb0ea0d2de658663bfaa9c26eccdd8fd64440 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Mon, 13 Apr 2026 21:46:04 +0800 +Subject: counter: Fix refcount leak in counter_alloc() error path + +From: Guangshuo Li + +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 +Link: https://lore.kernel.org/r/20260413134604.2861772-1-lgs201920130244@gmail.com +Signed-off-by: William Breathitt Gray +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch b/queue-7.0/drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch new file mode 100644 index 0000000000..63eeeb1e2f --- /dev/null +++ b/queue-7.0/drm-amd-pm-si-disregard-vblank-time-when-no-displays-are-connected.patch @@ -0,0 +1,46 @@ +From dd4f3ee535b3b0ac027f75dbf9dc5fc88733c765 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timur=20Krist=C3=B3f?= +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 + +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 +Tested-by: Jeremy Klarenbeek +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 6d87e0199f7b83735b56e422d59f170a201897a8) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -3076,6 +3076,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-7.0/drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch b/queue-7.0/drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch new file mode 100644 index 0000000000..835955552c --- /dev/null +++ b/queue-7.0/drm-amdgpu-check-num_entries-in-gem_op-get_mapping_info.patch @@ -0,0 +1,44 @@ +From a1ba4594232c87c3b8defd6f89a2e40f8b08395d Mon Sep 17 00:00:00 2001 +From: Ziyi Guo +Date: Sun, 8 Feb 2026 00:02:55 +0000 +Subject: drm/amdgpu: check num_entries in GEM_OP GET_MAPPING_INFO + +From: Ziyi Guo + +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 +Signed-off-by: Alex Deucher +(cherry picked from commit 1fe7bf5457f6efd7be60b17e23163ba54341d73d) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1095,6 +1095,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-7.0/drm-amdgpu-fix-amdgpu_hmm_range_get_pages.patch b/queue-7.0/drm-amdgpu-fix-amdgpu_hmm_range_get_pages.patch new file mode 100644 index 0000000000..860cb6d58a --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-amdgpu_hmm_range_get_pages.patch @@ -0,0 +1,86 @@ +From 962d684b5dc0741dcd93485d41b450de402d5592 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20K=C3=B6nig?= +Date: Wed, 18 Feb 2026 12:53:27 +0100 +Subject: drm/amdgpu: fix amdgpu_hmm_range_get_pages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +commit 962d684b5dc0741dcd93485d41b450de402d5592 upstream. + +The notifier sequence must only be read once or otherwise we could work +with invalid pages. + +While at it also fix the coding style, e.g. drop the pre-initialized +return value and use the common define for 2G range. + +Signed-off-by: Christian König +Reviewed-by: Vitaly Prosyak +Tested-by: Vitaly Prosyak +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit c08972f555945cda57b0adb72272a37910153390) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +@@ -51,8 +51,6 @@ + #include "amdgpu_amdkfd.h" + #include "amdgpu_hmm.h" + +-#define MAX_WALK_BYTE (2UL << 30) +- + /** + * amdgpu_hmm_invalidate_gfx - callback to notify about mm change + * +@@ -171,11 +169,13 @@ int amdgpu_hmm_range_get_pages(struct mm + void *owner, + struct amdgpu_hmm_range *range) + { +- unsigned long end; ++ const u64 max_bytes = SZ_2G; ++ ++ struct hmm_range *hmm_range = &range->hmm_range; + unsigned long timeout; + unsigned long *pfns; +- int r = 0; +- struct hmm_range *hmm_range = &range->hmm_range; ++ unsigned long end; ++ int r; + + pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL); + if (unlikely(!pfns)) { +@@ -192,8 +192,9 @@ int amdgpu_hmm_range_get_pages(struct mm + end = start + npages * PAGE_SIZE; + hmm_range->dev_private_owner = owner; + ++ hmm_range->notifier_seq = mmu_interval_read_begin(notifier); + do { +- hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end); ++ hmm_range->end = min(hmm_range->start + max_bytes, end); + + pr_debug("hmm range: start = 0x%lx, end = 0x%lx", + hmm_range->start, hmm_range->end); +@@ -201,7 +202,6 @@ int amdgpu_hmm_range_get_pages(struct mm + timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT); + + retry: +- hmm_range->notifier_seq = mmu_interval_read_begin(notifier); + r = hmm_range_fault(hmm_range); + if (unlikely(r)) { + if (r == -EBUSY && !time_after(jiffies, timeout)) +@@ -211,7 +211,7 @@ retry: + + if (hmm_range->end == end) + break; +- hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT; ++ hmm_range->hmm_pfns += max_bytes >> PAGE_SHIFT; + hmm_range->start = hmm_range->end; + } while (hmm_range->end < end); + diff --git a/queue-7.0/drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch b/queue-7.0/drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch new file mode 100644 index 0000000000..28da45e12d --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-calling-vm-invalidation-in-amdgpu_hmm_invalidate_gfx.patch @@ -0,0 +1,63 @@ +From 1c824497d8acd3187d585d6187cedc1897dcc871 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20K=C3=B6nig?= +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 + +commit 1c824497d8acd3187d585d6187cedc1897dcc871 upstream. + +Otherwise we don't invalidate page tables on next CS. + +Signed-off-by: Christian König +Reviewed-by: Vitaly Prosyak +Tested-by: Vitaly Prosyak +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit b6444d1bcbc34f6f2a31a3aab3059be082f3683e) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1613,6 +1613,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; + +@@ -1632,11 +1633,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-7.0/drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch b/queue-7.0/drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch new file mode 100644 index 0000000000..aa88e4d02d --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-lock-leak-on-enomem-in-amdgpu_gem_op_get_mapping_info.patch @@ -0,0 +1,72 @@ +From 2e7f55eb408c3f72ee1957a0d0ad11d8648a6379 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +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 + +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 +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Alex Deucher +(cherry picked from commit b69d3256d79de15f54c322986ff4da68f1d65b0a) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1096,8 +1096,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-7.0/drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch b/queue-7.0/drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch new file mode 100644 index 0000000000..4346a2f16d --- /dev/null +++ b/queue-7.0/drm-amdkfd-check-for-pdd-drm-file-first-in-criu-restore-path.patch @@ -0,0 +1,52 @@ +From 6842b6a4b72da9b2906ffc5ca9d846ace2c54c14 Mon Sep 17 00:00:00 2001 +From: David Francis +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 + +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 +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 2bab781dac78916c5cc8de76345a4102449267d7) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -2278,6 +2278,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); +@@ -2287,11 +2292,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-7.0/drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch b/queue-7.0/drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch new file mode 100644 index 0000000000..98f72319b6 --- /dev/null +++ b/queue-7.0/drm-amdkfd-fix-a-vulnerability-of-integer-overflow-in-kfd-debugger.patch @@ -0,0 +1,43 @@ +From 93f5534b35a05ef8a0109c1eefa800062fee810a Mon Sep 17 00:00:00 2001 +From: Eric Huang +Date: Tue, 12 May 2026 10:19:52 -0400 +Subject: drm/amdkfd: fix a vulnerability of integer overflow in kfd debugger + +From: Eric Huang + +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 +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 2d57a0475f085c08b49312dfd8edcb461845f285) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -3296,12 +3296,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-7.0/drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch b/queue-7.0/drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch new file mode 100644 index 0000000000..022669f566 --- /dev/null +++ b/queue-7.0/drm-amdkfd-fix-null-pointer-bug-in-svm_range_set_attr.patch @@ -0,0 +1,34 @@ +From e984d61d92e702096058f0f828f4b2b8563b88ce Mon Sep 17 00:00:00 2001 +From: Eric Huang +Date: Thu, 7 May 2026 15:51:49 -0400 +Subject: drm/amdkfd: fix NULL pointer bug in svm_range_set_attr + +From: Eric Huang + +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 +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 83a26c812e0529eb040d31a76f73e33e637243d4) +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -3718,6 +3718,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-7.0/drm-gem-fix-race-between-change_handle-and-handle_delete.patch b/queue-7.0/drm-gem-fix-race-between-change_handle-and-handle_delete.patch new file mode 100644 index 0000000000..a67a8b67ec --- /dev/null +++ b/queue-7.0/drm-gem-fix-race-between-change_handle-and-handle_delete.patch @@ -0,0 +1,47 @@ +From 7164d78559b0ff29931a366a840a9e5dd53d4b7c Mon Sep 17 00:00:00 2001 +From: Zhenghang Xiao +Date: Tue, 26 May 2026 16:53:13 +0800 +Subject: drm/gem: fix race between change_handle and handle_delete + +From: Zhenghang Xiao + +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 +Cc: stable@vger.kernel.org +Signed-off-by: Dave Airlie +Link: https://patch.msgid.link/20260526085313.26791-1-kipreyyy@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1047,6 +1047,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) { +@@ -1055,6 +1056,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-7.0/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch b/queue-7.0/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch new file mode 100644 index 0000000000..e5cc22ee79 --- /dev/null +++ b/queue-7.0/drm-hyperv-validate-resolution_count-and-fix-win8-fallback.patch @@ -0,0 +1,67 @@ +From 13d33b9ef67066c77c84273fac5a1d3fde3533d1 Mon Sep 17 00:00:00 2001 +From: Berkant Koc +Date: Tue, 19 May 2026 22:08:17 +0200 +Subject: drm/hyperv: validate resolution_count and fix WIN8 fallback + +From: Berkant Koc + +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 +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 +Tested-by: Michael Kelley +Signed-off-by: Hamza Mahfooz +Link: https://patch.msgid.link/6945b22419c7d404b4954a113de2ac9c900dba93.1779542874.git.me@berkoc.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -391,8 +391,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; + } + +@@ -508,9 +511,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-7.0/drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch b/queue-7.0/drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch new file mode 100644 index 0000000000..b792dcb779 --- /dev/null +++ b/queue-7.0/drm-hyperv-validate-vmbus-packet-size-in-receive-callback.patch @@ -0,0 +1,187 @@ +From 7f87763f47a3c22fb50265a00619ef10f2394b18 Mon Sep 17 00:00:00 2001 +From: Berkant Koc +Date: Sat, 23 May 2026 15:27:47 +0200 +Subject: drm/hyperv: validate VMBus packet size in receive callback + +From: Berkant Koc + +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 +Assisted-by: Claude:claude-opus-4-7 berkoc-pipeline +Reviewed-by: Michael Kelley +Tested-by: Michael Kelley +Signed-off-by: Hamza Mahfooz +Link: https://patch.msgid.link/8200dbc199c7a9b75ac7e8af6c748d2189b5ebd5.1779542874.git.me@berkoc.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -420,30 +420,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) +@@ -464,9 +526,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-7.0/drm-i915-color-fix-hdr-pre-csc-lut-programming-loop.patch b/queue-7.0/drm-i915-color-fix-hdr-pre-csc-lut-programming-loop.patch new file mode 100644 index 0000000000..f43b32b3e1 --- /dev/null +++ b/queue-7.0/drm-i915-color-fix-hdr-pre-csc-lut-programming-loop.patch @@ -0,0 +1,44 @@ +From d196136a988051173f68f91de0b5a1bd32122dd7 Mon Sep 17 00:00:00 2001 +From: Pranay Samala +Date: Tue, 19 May 2026 13:23:08 +0530 +Subject: drm/i915/color: Fix HDR pre-CSC LUT programming loop + +From: Pranay Samala + +commit d196136a988051173f68f91de0b5a1bd32122dd7 upstream. + +The integer lut programming loop never executes completely due to +incorrect condition (i++ > 130). + +Fix to properly program 129th+ entries for values > 1.0. + +Cc: #v6.19 +Fixes: 82caa1c8813f ("drm/i915/color: Program Pre-CSC registers") +Signed-off-by: Pranay Samala +Signed-off-by: Chaitanya Kumar Borah +Reviewed-by: Uma Shankar +Signed-off-by: Suraj Kandpal +Link: https://patch.msgid.link/20260519075308.383877-1-pranay.samala@intel.com +(cherry picked from commit f33862ec3e8849ad7c0a3dd46719083b13ade248) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_color.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c +index e7950655434b..6d1cffc6d2be 100644 +--- a/drivers/gpu/drm/i915/display/intel_color.c ++++ b/drivers/gpu/drm/i915/display/intel_color.c +@@ -3976,7 +3976,7 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb, + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), + (1 << 24)); +- } while (i++ > 130); ++ } while (i++ < 130); + } else { + for (i = 0; i < lut_size; i++) { + u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); +-- +2.54.0 + diff --git a/queue-7.0/drm-i915-fix-potential-uaf-in-ttm-object-purge.patch b/queue-7.0/drm-i915-fix-potential-uaf-in-ttm-object-purge.patch new file mode 100644 index 0000000000..d780b71342 --- /dev/null +++ b/queue-7.0/drm-i915-fix-potential-uaf-in-ttm-object-purge.patch @@ -0,0 +1,152 @@ +From 5c4063c87a619e4df954c179d24628636f5db15f Mon Sep 17 00:00:00 2001 +From: Janusz Krzysztofik +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 + +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] +[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 +Cc: stable@vger.kernel.org # v5.17+ +Cc: Matthew Auld +Cc: Thomas Hellström +Cc: Sebastian Brzezinka +Cc: Christian König +Reviewed-by: Andi Shyti +Reviewed-by: Christian König +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260508122612.469227-2-janusz.krzysztofik@linux.intel.com +(cherry picked from commit 4462966a93eb185849b7f174f0d0de53476d00a4) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -419,8 +419,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, +@@ -435,16 +433,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-7.0/drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch b/queue-7.0/drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch new file mode 100644 index 0000000000..e75d4c9eae --- /dev/null +++ b/queue-7.0/drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch @@ -0,0 +1,77 @@ +From 8bb9093df555f9e89fdbe1405118b11384c03e04 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jouni=20H=C3=B6gander?= +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 + +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: # v6.16+ +Signed-off-by: Jouni Högander +Reviewed-by: Michał Grzelak +Link: https://patch.msgid.link/20260520104944.239797-1-jouni.hogander@intel.com +(cherry picked from commit eb5911f990554f7ce947dd53df00c114362e4465) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -4141,32 +4141,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-7.0/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch b/queue-7.0/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch new file mode 100644 index 0000000000..9581a3290d --- /dev/null +++ b/queue-7.0/drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.patch @@ -0,0 +1,139 @@ +From 3549a9649dc7c5fc586ab12f675279283cdcb2a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jouni=20H=C3=B6gander?= +Date: Wed, 20 May 2026 13:49:44 +0300 +Subject: drm/i915/psr: Use DC_OFF wake reference to block DC6 on vblank enable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jouni Högander + +commit 3549a9649dc7c5fc586ab12f675279283cdcb2a7 upstream. + +We are observing following warnings: + +*ERROR* power well DC_off state mismatch (refcount 0/enabled 1) + +gen9_dc_off_power_well_enabled is considering target state DC_STATE_DISABLE +as DC_OFF power well being enabled. Fix this by using wakeref for the +purpose. + +To achieve this we need to modify notification code as well. Currently it +is possible that PSR gets notified vblank enable/disable twice on same +status. This is currently not a problem as it is just triggering call to +intel_display_power_set_target_dc_state with same target state as a +parameter. When using wakeref this becomes a problem due to reference +counting. Fix this storing vbank status on last notification and use that +to ensure there are no more than one notification with same vblank status. + +v2: ensure there is no subsequent notifications with same status + +Fixes: aa451abcffb5 ("drm/i915/display: Prevent DC6 while vblank is enabled for Panel Replay") +Cc: # v6.13+ +Signed-off-by: Jouni Högander +Reviewed-by: Michał Grzelak +Link: https://patch.msgid.link/20260520104944.239797-2-jouni.hogander@intel.com +(cherry picked from commit 35485ac56d878192a3829a58cb26503125ec7104) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/i915/display/intel_display_core.h | 1 + drivers/gpu/drm/i915/display/intel_display_irq.c | 8 +++++-- + drivers/gpu/drm/i915/display/intel_display_types.h | 2 + + drivers/gpu/drm/i915/display/intel_psr.c | 24 +++++++-------------- + 4 files changed, 18 insertions(+), 17 deletions(-) + +--- a/drivers/gpu/drm/i915/display/intel_display_core.h ++++ b/drivers/gpu/drm/i915/display/intel_display_core.h +@@ -494,6 +494,7 @@ struct intel_display { + u8 vblank_enabled; + + int vblank_enable_count; ++ bool vblank_status_last_notified; + + struct work_struct vblank_notify_work; + +--- a/drivers/gpu/drm/i915/display/intel_display_irq.c ++++ b/drivers/gpu/drm/i915/display/intel_display_irq.c +@@ -1773,8 +1773,12 @@ static void intel_display_vblank_notify_ + struct intel_display *display = + container_of(work, typeof(*display), irq.vblank_notify_work); + int vblank_enable_count = READ_ONCE(display->irq.vblank_enable_count); ++ bool vblank_status = !!vblank_enable_count; + +- intel_psr_notify_vblank_enable_disable(display, vblank_enable_count); ++ if (display->irq.vblank_status_last_notified != vblank_status) { ++ intel_psr_notify_vblank_enable_disable(display, vblank_status); ++ display->irq.vblank_status_last_notified = vblank_status; ++ } + } + + int bdw_enable_vblank(struct drm_crtc *_crtc) +@@ -1787,10 +1791,10 @@ int bdw_enable_vblank(struct drm_crtc *_ + if (gen11_dsi_configure_te(crtc, true)) + return 0; + ++ spin_lock_irqsave(&display->irq.lock, irqflags); + if (crtc->vblank_psr_notify && display->irq.vblank_enable_count++ == 0) + schedule_work(&display->irq.vblank_notify_work); + +- spin_lock_irqsave(&display->irq.lock, irqflags); + bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_VBLANK); + spin_unlock_irqrestore(&display->irq.lock, irqflags); + +--- a/drivers/gpu/drm/i915/display/intel_display_types.h ++++ b/drivers/gpu/drm/i915/display/intel_display_types.h +@@ -1785,6 +1785,8 @@ struct intel_psr { + u8 active_non_psr_pipes; + + const char *no_psr_reason; ++ ++ struct ref_tracker *vblank_wakeref; + }; + + struct intel_dp { +--- a/drivers/gpu/drm/i915/display/intel_psr.c ++++ b/drivers/gpu/drm/i915/display/intel_psr.c +@@ -4141,14 +4141,20 @@ 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 (CAN_PANEL_REPLAY(intel_dp)) +- block_dc_states = true; ++ if (CAN_PANEL_REPLAY(intel_dp)) { ++ if (enable) ++ intel_dp->psr.vblank_wakeref = ++ intel_display_power_get(display, ++ POWER_DOMAIN_DC_OFF); ++ else ++ intel_display_power_put(display, POWER_DOMAIN_DC_OFF, ++ intel_dp->psr.vblank_wakeref); ++ } + + if (intel_dp->psr.enabled && !intel_dp->psr.panel_replay_enabled && + intel_dp->psr.pkg_c_latency_used) +@@ -4156,18 +4162,6 @@ void intel_psr_notify_vblank_enable_disa + + mutex_unlock(&intel_dp->psr.lock); + } +- +- /* +- * NOTE: intel_display_power_set_target_dc_state is used +- * 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. +- */ +- 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-7.0/dt-bindings-usb-fix-eic7700-usb-reset-s-issue.patch b/queue-7.0/dt-bindings-usb-fix-eic7700-usb-reset-s-issue.patch new file mode 100644 index 0000000000..d2e89c3ff1 --- /dev/null +++ b/queue-7.0/dt-bindings-usb-fix-eic7700-usb-reset-s-issue.patch @@ -0,0 +1,60 @@ +From f1ecb0e563595d4ba9a3b8e39ed52a3dc2d8e328 Mon Sep 17 00:00:00 2001 +From: Hang Cao +Date: Wed, 15 Apr 2026 14:42:38 +0800 +Subject: dt-bindings: usb: Fix EIC7700 USB reset's issue + +From: Hang Cao + +commit f1ecb0e563595d4ba9a3b8e39ed52a3dc2d8e328 upstream. + +The EIC7700 USB requires a USB PHY reset operation; otherwise, the USB +will not work. The reason why the USB driver that was applied can work +properly is that the USB PHY has already been reset in ESWIN's U-Boot. + +However, the proper functioning of the USB driver should not be dependent +on the bootloader. Therefore, it is necessary to incorporate the USB PHY +reset signal into the DT bindings. + +This patch does not introduce any backward incompatibility since the dts +is not upstream yet. As array of reset operations are used in the driver, +no modifications to the USB controller driver are needed. + +Fixes: c640a4239db5 ("dt-bindings: usb: Add ESWIN EIC7700 USB controller") +Cc: stable +Signed-off-by: Hang Cao +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260415064238.1784-1-caohang@eswincomputing.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/devicetree/bindings/usb/eswin,eic7700-usb.yaml | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/Documentation/devicetree/bindings/usb/eswin,eic7700-usb.yaml ++++ b/Documentation/devicetree/bindings/usb/eswin,eic7700-usb.yaml +@@ -41,12 +41,13 @@ properties: + - const: usb_en + + resets: +- maxItems: 2 ++ maxItems: 3 + + reset-names: + items: + - const: vaux + - const: usb_rst ++ - const: usb_phy + + eswin,hsp-sp-csr: + description: +@@ -85,8 +86,8 @@ examples: + interrupt-parent = <&plic>; + interrupts = <85>; + interrupt-names = "peripheral"; +- resets = <&reset 84>, <&hspcrg 2>; +- reset-names = "vaux", "usb_rst"; ++ resets = <&reset 84>, <&hspcrg 2>, <&hspcrg 4>; ++ reset-names = "vaux", "usb_rst", "usb_phy"; + dr_mode = "peripheral"; + maximum-speed = "high-speed"; + phy_type = "utmi"; diff --git a/queue-7.0/gpib-cb7210-fix-region-leak-when-request_irq-fails.patch b/queue-7.0/gpib-cb7210-fix-region-leak-when-request_irq-fails.patch new file mode 100644 index 0000000000..db475ae02b --- /dev/null +++ b/queue-7.0/gpib-cb7210-fix-region-leak-when-request_irq-fails.patch @@ -0,0 +1,54 @@ +From 2eae90a457baa0048a96ed38ad93090ee38c8b2f Mon Sep 17 00:00:00 2001 +From: Hongling Zeng +Date: Mon, 18 May 2026 10:29:39 +0800 +Subject: gpib: cb7210: Fix region leak when request_irq fails + +From: Hongling Zeng + +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 +Cc: stable +Link: https://patch.msgid.link/20260518022939.16881-1-zenghongling@kylinos.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpib/cb7210/cb7210.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/gpib/cb7210/cb7210.c ++++ b/drivers/gpib/cb7210/cb7210.c +@@ -1049,7 +1049,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); +@@ -1062,11 +1063,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-7.0/input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch b/queue-7.0/input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch new file mode 100644 index 0000000000..1a12fabbe3 --- /dev/null +++ b/queue-7.0/input-atmel_mxt_ts-fix-boundary-check-in-mxt_prepare_cfg_mem.patch @@ -0,0 +1,53 @@ +From baa0210fb6a9dc3882509a9411b6d284d88fe30e Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +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 + +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 +Link: https://patch.msgid.link/20260504185448.4055973-1-dmitry.torokhov@gmail.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch b/queue-7.0/input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch new file mode 100644 index 0000000000..ff3fac97f4 --- /dev/null +++ b/queue-7.0/input-synaptics-add-len2058-to-smbus-passlist-for-thinkpad-e490.patch @@ -0,0 +1,45 @@ +From 16ca52bc209fa4bf9239cd9e5643e95533476b58 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Nicol=C3=A1s=20Bazaes?= +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 + +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 +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/input-xpad-add-nova-2-lite-from-gamesir.patch b/queue-7.0/input-xpad-add-nova-2-lite-from-gamesir.patch new file mode 100644 index 0000000000..bf58d7578f --- /dev/null +++ b/queue-7.0/input-xpad-add-nova-2-lite-from-gamesir.patch @@ -0,0 +1,31 @@ +From 1f6ac0f8441c48c4cc250141e1da8486c13512ba Mon Sep 17 00:00:00 2001 +From: Qbeliw Tanaka +Date: Thu, 30 Apr 2026 21:44:12 -0700 +Subject: Input: xpad - add "Nova 2 Lite" from GameSir + +From: Qbeliw Tanaka + +commit 1f6ac0f8441c48c4cc250141e1da8486c13512ba upstream. + +Add support for the gamepad "Nova 2 Lite" from GameSir, compatible with +the Xbox 360 gamepad. + +Signed-off-by: Qbeliw Tanaka +Link: https://patch.msgid.link/20260429.162040.930225048583399359.q.tanaka@gmx.com +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/input-xpad-add-support-for-asus-rog-raikiri-ii.patch b/queue-7.0/input-xpad-add-support-for-asus-rog-raikiri-ii.patch new file mode 100644 index 0000000000..8c5e02b2a2 --- /dev/null +++ b/queue-7.0/input-xpad-add-support-for-asus-rog-raikiri-ii.patch @@ -0,0 +1,43 @@ +From c897cf120696b94f56ed0f3197ba9a77071a59ec Mon Sep 17 00:00:00 2001 +From: Dmitriy Zharov +Date: Thu, 30 Apr 2026 22:35:22 +0400 +Subject: Input: xpad - add support for ASUS ROG RAIKIRI II + +From: Dmitriy Zharov + +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 +Link: https://patch.msgid.link/20260430183522.122151-1-contact@zharov.dev +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch b/queue-7.0/ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch new file mode 100644 index 0000000000..57b272c9b3 --- /dev/null +++ b/queue-7.0/ksmbd-oob-read-regression-in-smb_check_perm_dacl-ace-walk-loops.patch @@ -0,0 +1,61 @@ +From 0e60dafe97eca61721f3db456f97d97a80c6c8ae Mon Sep 17 00:00:00 2001 +From: Ali Ganiyev +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 + +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 +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + 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 || +@@ -1467,8 +1467,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-7.0/misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch b/queue-7.0/misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch new file mode 100644 index 0000000000..caa02f64fd --- /dev/null +++ b/queue-7.0/misc-rp1-send-iack-on-irq-activate-to-fix-kdump-kexec.patch @@ -0,0 +1,56 @@ +From 36770417153644bc88281c7284730ef1d14d8d3c Mon Sep 17 00:00:00 2001 +From: Xiaolei Wang +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 + +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 +Signed-off-by: Xiaolei Wang +Link: https://patch.msgid.link/20260518073405.2115003-1-xiaolei.wang@windriver.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -143,6 +143,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-7.0/scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch b/queue-7.0/scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch new file mode 100644 index 0000000000..df6bc461fd --- /dev/null +++ b/queue-7.0/scsi-fcoe-reject-fip-descriptors-with-zero-fip_dlen-in-cvl-walker.patch @@ -0,0 +1,53 @@ +From 9eed1bd59937e6828b00d2f2dfef631d964f3636 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +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 + +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 +Reviewed-by: Hannes Reinecke +Link: https://patch.msgid.link/20260518144307.2820961-1-michael.bommarito@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1385,7 +1385,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-7.0/scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch b/queue-7.0/scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch new file mode 100644 index 0000000000..598ad40d4f --- /dev/null +++ b/queue-7.0/scsi-scsi_transport_fc-widen-fpin-pname-walker-counter-to-u32.patch @@ -0,0 +1,163 @@ +From a9a39233ec1fc9f97ea1340a4d09bb7ec2be5153 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 20 May 2026 09:30:15 -0400 +Subject: scsi: scsi_transport_fc: Widen FPIN pname walker counter to u32 + +From: Michael Bommarito + +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 +Reviewed-by: Christoph Hellwig +Reviewed-by: John Garry +Link: https://patch.msgid.link/20260520133015.1018937-1-michael.bommarito@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -737,6 +737,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. +@@ -747,13 +778,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)); +@@ -764,22 +793,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); +@@ -827,13 +845,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)); +@@ -844,22 +860,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-7.0/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch b/queue-7.0/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch new file mode 100644 index 0000000000..57e62ba5f2 --- /dev/null +++ b/queue-7.0/scsi-target-iscsi-bound-iscsi_encode_text_output-appends-to-rsp_buf.patch @@ -0,0 +1,199 @@ +From bf33e01f88388c43e285492a63e539df6ffed64c Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +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 + +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 +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + 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, ¶m_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-7.0/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch b/queue-7.0/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch new file mode 100644 index 0000000000..d79e326d7f --- /dev/null +++ b/queue-7.0/scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.patch @@ -0,0 +1,119 @@ +From 778c2ab142c625a8a8afa570e0f9b7873f445d99 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +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 + +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 +Tested-by: John Garry +Reviewed-by: John Garry +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch b/queue-7.0/scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch new file mode 100644 index 0000000000..8e128cea2c --- /dev/null +++ b/queue-7.0/scsi-target-iscsi-validate-chap_r-length-before-base64-decode.patch @@ -0,0 +1,92 @@ +From 85db7391310b1304d2dc8ae3b0b12105a9567147 Mon Sep 17 00:00:00 2001 +From: Alexandru Hossu +Date: Thu, 21 May 2026 17:11:21 +0200 +Subject: scsi: target: iscsi: Validate CHAP_R length before base64 decode + +From: Alexandru Hossu + +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 +Reviewed-by: David Disseldorp +Link: https://patch.msgid.link/20260521151121.808477-1-hossu.alexandru@gmail.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -340,13 +340,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; +@@ -473,6 +482,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-7.0/serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch b/queue-7.0/serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch new file mode 100644 index 0000000000..19a0c69470 --- /dev/null +++ b/queue-7.0/serial-8250-dispatch-sysrq-character-in-serial8250_handle_irq.patch @@ -0,0 +1,73 @@ +From 71f42b2149a1307a97165b409493665579462ea0 Mon Sep 17 00:00:00 2001 +From: Jacques Nilo +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 + +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 +Signed-off-by: Jacques Nilo +Link: https://patch.msgid.link/52692ae6c3501f7940347cef364ad7fcacaab7e5.1778675349.git.jnilo@free.fr +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/8250/8250_port.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- 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_82 + } + + /* +- * 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_po + 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; diff --git a/queue-7.0/serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch b/queue-7.0/serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch new file mode 100644 index 0000000000..449f63778f --- /dev/null +++ b/queue-7.0/serial-8250_dw-dispatch-sysrq-character-in-dw8250_handle_irq.patch @@ -0,0 +1,49 @@ +From 2e211723953f7740e54b53f3d3a0d5e351a5e223 Mon Sep 17 00:00:00 2001 +From: Jacques Nilo +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 + +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 +Signed-off-by: Jacques Nilo +Link: https://patch.msgid.link/ed56fcaf4af24e4ed011a7bce206e0182acb761c.1778675349.git.jnilo@free.fr +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/8250/8250_dw.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- 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 + 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: diff --git a/queue-7.0/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch b/queue-7.0/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch new file mode 100644 index 0000000000..15a90bfba7 --- /dev/null +++ b/queue-7.0/serial-altera_jtaguart-handle-uart_add_one_port-failures.patch @@ -0,0 +1,54 @@ +From ea66be25f0e934f49d24cd0c5845d13cdba3520b Mon Sep 17 00:00:00 2001 +From: Myeonghun Pak +Date: Tue, 12 May 2026 15:56:57 +0900 +Subject: serial: altera_jtaguart: handle uart_add_one_port() failures + +From: Myeonghun Pak + +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 +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Signed-off-by: Myeonghun Pak +Link: https://patch.msgid.link/20260512065837.79528-1-mhun512@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch b/queue-7.0/serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch new file mode 100644 index 0000000000..83553bcd9f --- /dev/null +++ b/queue-7.0/serial-core-introduce-guard-uart_port_lock_check_sysrq_irqsave.patch @@ -0,0 +1,69 @@ +From c3cce2e67bb22a223f5b8ef05db0fcde70994068 Mon Sep 17 00:00:00 2001 +From: Jacques Nilo +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 + +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 +Reviewed-by: Ilpo Järvinen +Link: https://patch.msgid.link/3849af4bc55d5d2a424fa850844e94d641b2f8a6.1778675349.git.jnilo@free.fr +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/serial-dz-convert-to-use-a-platform-device.patch b/queue-7.0/serial-dz-convert-to-use-a-platform-device.patch new file mode 100644 index 0000000000..8093a18464 --- /dev/null +++ b/queue-7.0/serial-dz-convert-to-use-a-platform-device.patch @@ -0,0 +1,408 @@ +From 5d7a49d60b8fda66da60e240fd7315232fa1754f Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:48 +0100 +Subject: serial: dz: Convert to use a platform device + +From: Maciej W. Rozycki + +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 +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 +--- + 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 + #include + ++#include ++ ++#include ++#include ++#include ++#include ++ + 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 + #include + #include ++#include + #include + #include + #include +@@ -48,14 +49,6 @@ + + #include + #include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include + + #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-7.0/serial-dz-fix-bootconsole-handover-lockup.patch b/queue-7.0/serial-dz-fix-bootconsole-handover-lockup.patch new file mode 100644 index 0000000000..486de1b3cf --- /dev/null +++ b/queue-7.0/serial-dz-fix-bootconsole-handover-lockup.patch @@ -0,0 +1,98 @@ +From 7f127b2208e5e2b817243cad41fe4211a6d5a7a3 Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:35 +0100 +Subject: serial: dz: Fix bootconsole handover lockup + +From: Maciej W. Rozycki + +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 +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 +--- + 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-7.0/serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch b/queue-7.0/serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch new file mode 100644 index 0000000000..285c07c6fe --- /dev/null +++ b/queue-7.0/serial-dz-fix-bootconsole-message-clobbering-at-chip-reset.patch @@ -0,0 +1,71 @@ +From ca904f4b42355287bc5ce8b7550ebe909cda4c2c Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:31 +0100 +Subject: serial: dz: Fix bootconsole message clobbering at chip reset + +From: Maciej W. Rozycki + +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 +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 +--- + 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-7.0/serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch b/queue-7.0/serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch new file mode 100644 index 0000000000..7e9998250b --- /dev/null +++ b/queue-7.0/serial-fsl_lpuart-fix-rx-buffer-and-dma-map-leaks-in-start_rx_dma.patch @@ -0,0 +1,90 @@ +From 9a9254c4a2a3ca2b3da16d173f3b0dd01f397ff6 Mon Sep 17 00:00:00 2001 +From: Shitalkumar Gandhi +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 + +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 +Signed-off-by: Shitalkumar Gandhi +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260420135903.2062024-1-shitalkumar.gandhi@cambiumnetworks.com +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch b/queue-7.0/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch new file mode 100644 index 0000000000..9761fde9db --- /dev/null +++ b/queue-7.0/serial-qcom-geni-fix-uart_rx_par_en-bit-position.patch @@ -0,0 +1,37 @@ +From ca2584d841b69391ffc4144840563d2e1a0018df Mon Sep 17 00:00:00 2001 +From: Prasanna S +Date: Tue, 28 Apr 2026 09:56:13 +0530 +Subject: serial: qcom-geni: fix UART_RX_PAR_EN bit position + +From: Prasanna S + +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 +Signed-off-by: Prasanna S +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260428-serial-bit-correct-v1-1-9131ad5b97d8@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -50,7 +50,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-7.0/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch b/queue-7.0/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch new file mode 100644 index 0000000000..5e424ec5be --- /dev/null +++ b/queue-7.0/serial-qcom_geni-fix-kfifo-underflow-when-flush-precedes-dma-completion-irq.patch @@ -0,0 +1,64 @@ +From 452d6fa37ae9b021f4f6d397dbae077f7296f6f4 Mon Sep 17 00:00:00 2001 +From: Viken Dadhaniya +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 + +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 +Signed-off-by: Viken Dadhaniya +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/20260506-serial-dma-stale-tx-buf-v1-1-e3ccb360d719@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1030,8 +1030,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-7.0/serial-sh-sci-fix-memory-region-release-in-error-path.patch b/queue-7.0/serial-sh-sci-fix-memory-region-release-in-error-path.patch new file mode 100644 index 0000000000..bae23ac3ba --- /dev/null +++ b/queue-7.0/serial-sh-sci-fix-memory-region-release-in-error-path.patch @@ -0,0 +1,40 @@ +From 92b1ea22454b08a39baef3a7290fb3ec50366616 Mon Sep 17 00:00:00 2001 +From: Hongling Zeng +Date: Tue, 21 Apr 2026 14:57:37 +0800 +Subject: serial: sh-sci: fix memory region release in error path + +From: Hongling Zeng + +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 +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604032356.SzEjYkBC-lkp@intel.com/ +Signed-off-by: Hongling Zeng +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260421065737.724187-1-zenghongling@kylinos.cn +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -3024,7 +3024,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-7.0/serial-zs-convert-to-use-a-platform-device.patch b/queue-7.0/serial-zs-convert-to-use-a-platform-device.patch new file mode 100644 index 0000000000..4e5863b661 --- /dev/null +++ b/queue-7.0/serial-zs-convert-to-use-a-platform-device.patch @@ -0,0 +1,478 @@ +From 7cac59d08a73cb866ec51a483a6f3fe0f531947c Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:52 +0100 +Subject: serial: zs: Convert to use a platform device + +From: Maciej W. Rozycki + +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 +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 + + #include ++#include + #include + #include + #include +@@ -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 + #include + #include ++#include + #include + #include + #include +@@ -66,10 +67,6 @@ + + #include + +-#include +-#include +-#include +- + #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-7.0/serial-zs-fix-bootconsole-handover-lockup.patch b/queue-7.0/serial-zs-fix-bootconsole-handover-lockup.patch new file mode 100644 index 0000000000..2ad049a1e5 --- /dev/null +++ b/queue-7.0/serial-zs-fix-bootconsole-handover-lockup.patch @@ -0,0 +1,100 @@ +From 6c05cf72e13314ce9b770b5951695dc5a2152920 Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:39 +0100 +Subject: serial: zs: Fix bootconsole handover lockup + +From: Maciej W. Rozycki + +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 +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 +--- + 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-7.0/serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch b/queue-7.0/serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch new file mode 100644 index 0000000000..f6d3c3e25c --- /dev/null +++ b/queue-7.0/serial-zs-fix-swapped-ri-dsr-modem-line-transition-counting.patch @@ -0,0 +1,36 @@ +From d15cd40cb1858f75846eaafa9a6bca841b790a92 Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Fri, 10 Apr 2026 18:19:31 +0100 +Subject: serial: zs: Fix swapped RI/DSR modem line transition counting + +From: Maciej W. Rozycki + +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 +Signed-off-by: Maciej W. Rozycki +Link: https://patch.msgid.link/alpine.DEB.2.21.2604101747110.29980@angie.orcam.me.uk +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/serial-zs-switch-to-using-channel-reset.patch b/queue-7.0/serial-zs-switch-to-using-channel-reset.patch new file mode 100644 index 0000000000..b04390418a --- /dev/null +++ b/queue-7.0/serial-zs-switch-to-using-channel-reset.patch @@ -0,0 +1,89 @@ +From 8572955630f30948837088aa98bcbe0532d1ceac Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Wed, 6 May 2026 23:42:43 +0100 +Subject: serial: zs: Switch to using channel reset + +From: Maciej W. Rozycki + +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 +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 +--- + 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__ */ diff --git a/queue-7.0/series b/queue-7.0/series index d702f3cbeb..3f8af6ac7c 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -234,3 +234,84 @@ xfrm-esp-restore-combined-single-frag-length-gate.patch alsa-hda-realtek-fix-speaker-output-on-asus-rog-strix-g615lp.patch xfrm-iptfs-reset-runtime-state-when-cloning-sas.patch dma-buf-fix-uaf-in-dma_buf_fd-tracepoint.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 +dt-bindings-usb-fix-eic7700-usb-reset-s-issue.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 +uio-uio_pci_generic_sva-fix-double-free-of-devm_kzalloc-memory.patch +usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch +usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch +usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.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-digi_acceleport-fix-memory-corruption-with-small-endpoints.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-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 +thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.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-color-fix-hdr-pre-csc-lut-programming-loop.patch +drm-i915-psr-block-dc-states-on-vblank-enable-when-panel-replay-supported.patch +drm-i915-psr-use-dc_off-wake-reference-to-block-dc6-on-vblank-enable.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-fix-amdgpu_hmm_range_get_pages.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-7.0/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch b/queue-7.0/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch new file mode 100644 index 0000000000..93a3a15627 --- /dev/null +++ b/queue-7.0/thunderbolt-property-cap-recursion-depth-in-__tb_property_parse_dir.patch @@ -0,0 +1,108 @@ +From 928abe19fbf0127003abcb1ea69cabc1c897d0ab Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 10 May 2026 19:16:58 -0400 +Subject: thunderbolt: property: Cap recursion depth in __tb_property_parse_dir() + +From: Michael Bommarito + +commit 928abe19fbf0127003abcb1ea69cabc1c897d0ab upstream. + +A DIRECTORY entry's value field is used as the dir_offset for a +recursive call into __tb_property_parse_dir() with no depth counter. +A crafted peer that chains DIRECTORY entries into a back-reference +loop drives the parser until the kernel stack is exhausted and the +guard page fires. Any untrusted XDomain peer (cable, dock, in-line +inspector, adjacent host) that reaches the PROPERTIES_REQUEST +control-plane exchange can trigger this without authentication. + +Thread a depth counter through tb_property_parse() and +__tb_property_parse_dir(), and reject blocks that exceed +TB_PROPERTY_MAX_DEPTH = 8. That is comfortably larger than any +observed legitimate XDomain layout. + +Operators who do not need XDomain host-to-host discovery can disable +the path entirely with thunderbolt.xdomain=0 on the kernel command +line. + +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 +Signed-off-by: Mika Westerberg +Signed-off-by: Greg Kroah-Hartman +--- + drivers/thunderbolt/property.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/thunderbolt/property.c ++++ b/drivers/thunderbolt/property.c +@@ -35,10 +35,11 @@ struct tb_property_dir_entry { + }; + + #define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401 ++#define TB_PROPERTY_MAX_DEPTH 8 + + static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, + size_t block_len, unsigned int dir_offset, size_t dir_len, +- bool is_root); ++ bool is_root, unsigned int depth); + + static inline void parse_dwdata(void *dst, const void *src, size_t dwords) + { +@@ -97,7 +98,8 @@ tb_property_alloc(const char *key, enum + } + + static struct tb_property *tb_property_parse(const u32 *block, size_t block_len, +- const struct tb_property_entry *entry) ++ const struct tb_property_entry *entry, ++ unsigned int depth) + { + char key[TB_PROPERTY_KEY_SIZE + 1]; + struct tb_property *property; +@@ -118,7 +120,7 @@ static struct tb_property *tb_property_p + switch (property->type) { + case TB_PROPERTY_TYPE_DIRECTORY: + dir = __tb_property_parse_dir(block, block_len, entry->value, +- entry->length, false); ++ entry->length, false, depth + 1); + if (!dir) { + kfree(property); + return NULL; +@@ -163,13 +165,17 @@ static struct tb_property *tb_property_p + } + + static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, +- size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root) ++ size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root, ++ unsigned int depth) + { + const struct tb_property_entry *entries; + size_t i, content_len, nentries; + unsigned int content_offset; + struct tb_property_dir *dir; + ++ if (depth > TB_PROPERTY_MAX_DEPTH) ++ return NULL; ++ + dir = kzalloc_obj(*dir); + if (!dir) + return NULL; +@@ -200,7 +206,7 @@ static struct tb_property_dir *__tb_prop + for (i = 0; i < nentries; i++) { + struct tb_property *property; + +- property = tb_property_parse(block, block_len, &entries[i]); ++ property = tb_property_parse(block, block_len, &entries[i], depth); + if (!property) { + tb_property_free_dir(dir); + return NULL; +@@ -239,7 +245,7 @@ struct tb_property_dir *tb_property_pars + return NULL; + + return __tb_property_parse_dir(block, block_len, 0, rootdir->length, +- true); ++ true, 0); + } + + /** diff --git a/queue-7.0/thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch b/queue-7.0/thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch new file mode 100644 index 0000000000..7305c1800a --- /dev/null +++ b/queue-7.0/thunderbolt-property-reject-dir_len-4-to-prevent-size_t-underflow.patch @@ -0,0 +1,75 @@ +From de21b59c29e31c5108ddc04210631bbfab81b997 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 10 May 2026 19:16:57 -0400 +Subject: thunderbolt: property: Reject dir_len < 4 to prevent size_t underflow + +From: Michael Bommarito + +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 +Signed-off-by: Mika Westerberg +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch b/queue-7.0/thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch new file mode 100644 index 0000000000..d6089b7624 --- /dev/null +++ b/queue-7.0/thunderbolt-property-reject-u32-wrap-in-tb_property_entry_valid.patch @@ -0,0 +1,65 @@ +From 01deda0152066c6c955f0619114ea6afa070aaec Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 10 May 2026 19:16:56 -0400 +Subject: thunderbolt: property: Reject u32 wrap in tb_property_entry_valid() + +From: Michael Bommarito + +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 +Signed-off-by: Mika Westerberg +Signed-off-by: Greg Kroah-Hartman +--- + 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 ++#include + #include + #include + #include +@@ -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-7.0/tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch b/queue-7.0/tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch new file mode 100644 index 0000000000..3f993c69d7 --- /dev/null +++ b/queue-7.0/tty-serial-pch_uart-add-check-for-dma_alloc_coherent.patch @@ -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 +Signed-off-by: Zhaoyang Yu <2426767509@qq.com> +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/tencent_E328416B7CFD436F6029F2DF02AD7ED89C08@qq.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch b/queue-7.0/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch new file mode 100644 index 0000000000..661b6529c7 --- /dev/null +++ b/queue-7.0/tty-serial-samsung-remove-redundant-port-lock-acquisition-in-rx-helpers.patch @@ -0,0 +1,81 @@ +From a3bb136bff5e6a5e48cdd813246c9c4686feaaa9 Mon Sep 17 00:00:00 2001 +From: Tudor Ambarus +Date: Fri, 15 May 2026 12:41:21 +0000 +Subject: tty: serial: samsung: Remove redundant port lock acquisition in rx helpers + +From: Tudor Ambarus + +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 +Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers") +Reported-by: John Ogness +Closes: https://sashiko.dev/#/patchset/20260506121606.5805-1-john.ogness%40linutronix.de [1] +Signed-off-by: Tudor Ambarus +Link: https://patch.msgid.link/20260515-samsung-tty-flow-control-deadlock-v1-1-93255edbc9bc@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/uio-uio_pci_generic_sva-fix-double-free-of-devm_kzalloc-memory.patch b/queue-7.0/uio-uio_pci_generic_sva-fix-double-free-of-devm_kzalloc-memory.patch new file mode 100644 index 0000000000..a1875eb34e --- /dev/null +++ b/queue-7.0/uio-uio_pci_generic_sva-fix-double-free-of-devm_kzalloc-memory.patch @@ -0,0 +1,67 @@ +From f74c8696f14149d5e43cc28b015326a759c48f00 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Tue, 5 May 2026 23:02:56 +0800 +Subject: uio: uio_pci_generic_sva: fix double free of devm_kzalloc() memory + +From: Guangshuo Li + +commit f74c8696f14149d5e43cc28b015326a759c48f00 upstream. + +uio_pci_sva allocates struct uio_pci_sva_dev with devm_kzalloc() in +probe(), but then calls kfree(udev) both on the probe() error path +(label out_free) and again in remove(). + +Because devm_kzalloc() allocations are devres-managed and are freed +automatically when the device is detached (including after a failing +probe() and during driver unbind), the explicit kfree() can lead to a +double free. + +If probe() fails after devm_kzalloc(), the error path frees udev and +devres cleanup will free it again when the core unwinds the partially +bound device. On normal driver removal, remove() frees udev and devres +will free it again when the device is detached. + +This issue was identified by a static analysis tool I developed and +confirmed by manual review. Fix by removing the manual kfree() calls +and dropping the now-unused label. + +Fixes: 3397c3cd859a2 ("uio: Add SVA support for PCI devices via uio_pci_generic_sva.c") +Cc: stable +Signed-off-by: Guangshuo Li +Link: https://patch.msgid.link/20260505150256.614071-1-lgs201920130244@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/uio/uio_pci_generic_sva.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +--- a/drivers/uio/uio_pci_generic_sva.c ++++ b/drivers/uio/uio_pci_generic_sva.c +@@ -129,15 +129,13 @@ static int probe(struct pci_dev *pdev, c + ret = devm_uio_register_device(&pdev->dev, &udev->info); + if (ret) { + dev_err(&pdev->dev, "Failed to register uio device\n"); +- goto out_free; ++ goto out_disable; + } + + pci_set_drvdata(pdev, udev); + + return 0; + +-out_free: +- kfree(udev); + out_disable: + pci_disable_device(pdev); + +@@ -146,11 +144,8 @@ out_disable: + + static void remove(struct pci_dev *pdev) + { +- struct uio_pci_sva_dev *udev = pci_get_drvdata(pdev); +- + pci_release_regions(pdev); + pci_disable_device(pdev); +- kfree(udev); + } + + static ssize_t pasid_show(struct device *dev, diff --git a/queue-7.0/usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch b/queue-7.0/usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch new file mode 100644 index 0000000000..488d088878 --- /dev/null +++ b/queue-7.0/usb-chipidea-core-convert-ci_role_switch-to-local-variable.patch @@ -0,0 +1,77 @@ +From 8f6aa392653e52a45858cff5c063df550028836b Mon Sep 17 00:00:00 2001 +From: Xu Yang +Date: Mon, 27 Apr 2026 15:57:55 +0800 +Subject: usb: chipidea: core: convert ci_role_switch to local variable + +From: Xu Yang + +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 +Acked-by: Peter Chen +Reviewed-by: Frank Li +Signed-off-by: Xu Yang +Link: https://patch.msgid.link/20260427075755.3611217-1-xu.yang_2@nxp.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -670,12 +670,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) + { +@@ -802,9 +796,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; +@@ -1048,6 +1039,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; +@@ -1194,7 +1186,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-7.0/usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch b/queue-7.0/usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch new file mode 100644 index 0000000000..ee40e6b725 --- /dev/null +++ b/queue-7.0/usb-core-fix-up-interrupt-in-endpoints-with-bogus-wbytesperinterval.patch @@ -0,0 +1,65 @@ +From 727d045d064b7c9a24db3bce9c0485a382cb768b Mon Sep 17 00:00:00 2001 +From: Michal Pecio +Date: Mon, 18 May 2026 07:32:07 +0200 +Subject: usb: core: Fix up Interrupt IN endpoints with bogus wBytesPerInterval + +From: Michal Pecio + +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 +Closes: https://lore.kernel.org/linux-usb/20260402021400.28853-1-xuetao09@huawei.com/ +Cc: stable@vger.kernel.org +Signed-off-by: Michal Pecio +Link: https://patch.msgid.link/20260518073207.5b7d26e7.michal.pecio@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch b/queue-7.0/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch new file mode 100644 index 0000000000..dec5735ab0 --- /dev/null +++ b/queue-7.0/usb-dwc3-xilinx-fix-error-handling-in-zynqmp-init-error-paths.patch @@ -0,0 +1,90 @@ +From c1a0ecbf32c4b397353204e2ec94c5bb9f3300ed Mon Sep 17 00:00:00 2001 +From: Radhey Shyam Pandey +Date: Tue, 19 May 2026 17:25:29 +0530 +Subject: usb: dwc3: xilinx: fix error handling in zynqmp init error paths + +From: Radhey Shyam Pandey + +commit c1a0ecbf32c4b397353204e2ec94c5bb9f3300ed upstream. + +Fix error handling and resource cleanup i.e remove invalid +phy_exit() after failed phy_init(), route failures through +proper cleanup paths and return 0 explicitly on success. + +Fixes: 84770f028fab ("usb: dwc3: Add driver for Xilinx platforms") +Cc: stable@vger.kernel.org +Acked-by: Thinh Nguyen +Signed-off-by: Radhey Shyam Pandey +Link: https://patch.msgid.link/20260519115529.2980421-1-radhey.shyam.pandey@amd.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/dwc3-xilinx.c | 27 +++++++++++++++------------ + 1 file changed, 15 insertions(+), 12 deletions(-) + +--- a/drivers/usb/dwc3/dwc3-xilinx.c ++++ b/drivers/usb/dwc3/dwc3-xilinx.c +@@ -184,15 +184,13 @@ static int dwc3_xlnx_init_zynqmp(struct + } + + ret = phy_init(priv_data->usb3_phy); +- if (ret < 0) { +- phy_exit(priv_data->usb3_phy); ++ if (ret < 0) + goto err; +- } + + ret = reset_control_deassert(apbrst); + if (ret < 0) { + dev_err(dev, "Failed to release APB reset\n"); +- goto err; ++ goto err_phy_exit; + } + + if (priv_data->usb3_phy) { +@@ -208,26 +206,24 @@ static int dwc3_xlnx_init_zynqmp(struct + ret = reset_control_deassert(crst); + if (ret < 0) { + dev_err(dev, "Failed to release core reset\n"); +- goto err; ++ goto err_phy_exit; + } + + ret = reset_control_deassert(hibrst); + if (ret < 0) { + dev_err(dev, "Failed to release hibernation reset\n"); +- goto err; ++ goto err_phy_exit; + } + + ret = phy_power_on(priv_data->usb3_phy); +- if (ret < 0) { +- phy_exit(priv_data->usb3_phy); +- goto err; +- } ++ if (ret < 0) ++ goto err_phy_exit; + + /* ulpi reset via gpio-modepin or gpio-framework driver */ + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) { +- return dev_err_probe(dev, PTR_ERR(reset_gpio), +- "Failed to request reset GPIO\n"); ++ ret = PTR_ERR(reset_gpio); ++ goto err_phy_power_off; + } + + if (reset_gpio) { +@@ -237,6 +233,13 @@ static int dwc3_xlnx_init_zynqmp(struct + } + + dwc3_xlnx_set_coherency(priv_data, XLNX_USB_TRAFFIC_ROUTE_CONFIG); ++ ++ return 0; ++ ++err_phy_power_off: ++ phy_power_off(priv_data->usb3_phy); ++err_phy_exit: ++ phy_exit(priv_data->usb3_phy); + err: + return ret; + } diff --git a/queue-7.0/usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch b/queue-7.0/usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch new file mode 100644 index 0000000000..ceb857d730 --- /dev/null +++ b/queue-7.0/usb-gadget-composite-fix-integer-underflow-in-webusb-get_url-handling.patch @@ -0,0 +1,62 @@ +From 6c5dbc104dadd79fc2923497c20bae759a18758c Mon Sep 17 00:00:00 2001 +From: Jeremy Erazo +Date: Tue, 12 May 2026 16:05:30 +0000 +Subject: usb: gadget: composite: fix integer underflow in WebUSB GET_URL handling + +From: Jeremy Erazo + +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 +Signed-off-by: Jeremy Erazo +Link: https://patch.msgid.link/20260512160530.352318-1-mendozayt13@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch b/queue-7.0/usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch new file mode 100644 index 0000000000..4c1e599fe6 --- /dev/null +++ b/queue-7.0/usb-gadget-dummy_hcd-reject-hub-port-requests-for-non-existent-ports.patch @@ -0,0 +1,50 @@ +From 7d9633528dd40e33964d2dc74a5abbf5c4d116ce Mon Sep 17 00:00:00 2001 +From: Seungjin Bae +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 + +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 +Suggested-by: Alan Stern +Signed-off-by: Seungjin Bae +Reviewed-by: Alan Stern +Link: https://patch.msgid.link/20260518234314.1889396-1-eeodqql09@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch b/queue-7.0/usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch new file mode 100644 index 0000000000..9139fb8c67 --- /dev/null +++ b/queue-7.0/usb-gadget-f_fs-copy-only-received-bytes-on-short-ep0-read.patch @@ -0,0 +1,79 @@ +From 4e036c10e7f4df5d951c69cc3697bc8e209c6d02 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +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 + +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 +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260419160359.1577270-1-michael.bommarito@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -619,7 +619,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-7.0/usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch b/queue-7.0/usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch new file mode 100644 index 0000000000..6b7d9c36a5 --- /dev/null +++ b/queue-7.0/usb-gadget-f_fs-serialize-dmabuf-cancel-against-request-completion.patch @@ -0,0 +1,162 @@ +From 2796646f6d892c1eb6818c7ca41fdfa12568e8d1 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 19 Apr 2026 12:12:27 -0400 +Subject: usb: gadget: f_fs: serialize DMABUF cancel against request completion + +From: Michael Bommarito + +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 +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260419161227.1587668-1-michael.bommarito@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -150,6 +150,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 { +@@ -1385,6 +1387,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); +@@ -1414,8 +1431,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) +@@ -1699,6 +1716,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); +@@ -1708,7 +1729,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-7.0/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch b/queue-7.0/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch new file mode 100644 index 0000000000..a383b73af0 --- /dev/null +++ b/queue-7.0/usb-gadget-f_hid-fix-device-reference-leak-in-hidg_alloc.patch @@ -0,0 +1,53 @@ +From 4f88d65def6f3c90121601b4f62a4c967f3063a6 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Mon, 13 Apr 2026 22:21:19 +0800 +Subject: usb: gadget: f_hid: fix device reference leak in hidg_alloc() + +From: Guangshuo Li + +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 +Reviewed-by: Johan Hovold +Signed-off-by: Guangshuo Li +Reviewed-by: Johan Hovold johan@kernel.org +Link: https://patch.msgid.link/20260413142119.2977716-1-lgs201920130244@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1620,7 +1620,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; +@@ -1657,7 +1657,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-7.0/usb-gadget-net2280-fix-double-free-in-probe-error-path.patch b/queue-7.0/usb-gadget-net2280-fix-double-free-in-probe-error-path.patch new file mode 100644 index 0000000000..a9d21a8e98 --- /dev/null +++ b/queue-7.0/usb-gadget-net2280-fix-double-free-in-probe-error-path.patch @@ -0,0 +1,48 @@ +From c8547c74988e0b5f4cbb1b895e2a57aae084f070 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Mon, 27 Apr 2026 23:36:51 +0800 +Subject: usb: gadget: net2280: Fix double free in probe error path + +From: Guangshuo Li + +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 +Signed-off-by: Guangshuo Li +Reviewed-by: Alan Stern +Link: https://patch.msgid.link/20260427153651.337846-1-lgs201920130244@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch b/queue-7.0/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch new file mode 100644 index 0000000000..152f9a90ed --- /dev/null +++ b/queue-7.0/usb-gadget-uvc-hold-opts-lock-across-xu-walks-in-uvc_function_bind.patch @@ -0,0 +1,137 @@ +From 68aa70648b625fa684bc0b71bbfd905f4943ca20 Mon Sep 17 00:00:00 2001 +From: Kai Aizen +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 + +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 +Signed-off-by: Kai Aizen +Link: https://patch.msgid.link/20260430175643.67120-1-kai.aizen.dev@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch b/queue-7.0/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch new file mode 100644 index 0000000000..a80b18be32 --- /dev/null +++ b/queue-7.0/usb-musb-omap2430-fix-use-after-free-in-omap2430_probe.patch @@ -0,0 +1,49 @@ +From e194ce048f5a6c549b3a23a8c568c6470f40f772 Mon Sep 17 00:00:00 2001 +From: Wentao Liang +Date: Thu, 9 Apr 2026 10:11:04 +0000 +Subject: usb: musb: omap2430: Fix use-after-free in omap2430_probe() + +From: Wentao Liang + +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 +Signed-off-by: Wentao Liang +Link: https://patch.msgid.link/20260409101104.480623-1-vulab@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -337,7 +337,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; +@@ -455,6 +454,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; + +@@ -464,6 +464,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-7.0/usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch b/queue-7.0/usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch new file mode 100644 index 0000000000..816442765f --- /dev/null +++ b/queue-7.0/usb-quirks-add-no_lpm-for-lenovo-thinkpad-usb-c-dock-gen2-hub-controllers.patch @@ -0,0 +1,40 @@ +From 9ddb9c0deca48d2c2a22ebf4d2f35c925a520328 Mon Sep 17 00:00:00 2001 +From: "Stephen J. Fuhry" +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 + +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 +Cc: stable +Link: https://patch.msgid.link/20260513171419.44849-1-fuhrysteve@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -513,6 +513,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-7.0/usb-serial-belkin_sa-validate-interrupt-status-length.patch b/queue-7.0/usb-serial-belkin_sa-validate-interrupt-status-length.patch new file mode 100644 index 0000000000..f25e550eb5 --- /dev/null +++ b/queue-7.0/usb-serial-belkin_sa-validate-interrupt-status-length.patch @@ -0,0 +1,50 @@ +From 4ce058df2ee02cc2a0f0fd5cd64ce6f1482a0b65 Mon Sep 17 00:00:00 2001 +From: Zhang Cen +Date: Tue, 19 May 2026 19:11:50 +0800 +Subject: USB: serial: belkin_sa: validate interrupt status length + +From: Zhang Cen + +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 +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-serial-cypress_m8-validate-interrupt-packet-headers.patch b/queue-7.0/usb-serial-cypress_m8-validate-interrupt-packet-headers.patch new file mode 100644 index 0000000000..b1de7b2d90 --- /dev/null +++ b/queue-7.0/usb-serial-cypress_m8-validate-interrupt-packet-headers.patch @@ -0,0 +1,86 @@ +From 9f9bfc80c67f35a275820da7e83a35dface08281 Mon Sep 17 00:00:00 2001 +From: Zhang Cen +Date: Fri, 22 May 2026 22:54:42 +0800 +Subject: USB: serial: cypress_m8: validate interrupt packet headers + +From: Zhang Cen + +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 +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1025,8 +1025,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 */ +@@ -1064,22 +1064,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-7.0/usb-serial-digi_acceleport-fix-memory-corruption-with-small-endpoints.patch b/queue-7.0/usb-serial-digi_acceleport-fix-memory-corruption-with-small-endpoints.patch new file mode 100644 index 0000000000..680ccc4db7 --- /dev/null +++ b/queue-7.0/usb-serial-digi_acceleport-fix-memory-corruption-with-small-endpoints.patch @@ -0,0 +1,61 @@ +From cb3560e8eab1dfa1cac1ed52631adf8ec6ff2cd5 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 20 May 2026 16:26:22 +0200 +Subject: USB: serial: digi_acceleport: fix memory corruption with small endpoints + +From: Johan Hovold + +commit cb3560e8eab1dfa1cac1ed52631adf8ec6ff2cd5 upstream. + +Add the missing bulk-out buffer size sanity checks to avoid +out-of-bounds memory accesses or slab corruption should a malicious +device report smaller buffers than expected. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/digi_acceleport.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +--- a/drivers/usb/serial/digi_acceleport.c ++++ b/drivers/usb/serial/digi_acceleport.c +@@ -1229,15 +1229,34 @@ static int digi_port_init(struct usb_ser + static int digi_startup(struct usb_serial *serial) + { + struct digi_serial *serial_priv; ++ int oob_port_num; + int ret; ++ int i; ++ ++ /* ++ * The port bulk-out buffers must be large enough for header and ++ * buffered data. ++ */ ++ for (i = 0; i < serial->type->num_ports; i++) { ++ if (serial->port[i]->bulk_out_size < DIGI_OUT_BUF_SIZE + 2) ++ return -EINVAL; ++ } ++ ++ /* ++ * The OOB port bulk-out buffer must be large enough for the two ++ * commands in digi_set_modem_signals(). ++ */ ++ oob_port_num = serial->type->num_ports; ++ if (serial->port[oob_port_num]->bulk_out_size < 8) ++ return -EINVAL; + + serial_priv = kzalloc_obj(*serial_priv); + if (!serial_priv) + return -ENOMEM; + + spin_lock_init(&serial_priv->ds_serial_lock); +- serial_priv->ds_oob_port_num = serial->type->num_ports; +- serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num]; ++ serial_priv->ds_oob_port_num = oob_port_num; ++ serial_priv->ds_oob_port = serial->port[oob_port_num]; + + ret = digi_port_init(serial_priv->ds_oob_port, + serial_priv->ds_oob_port_num); diff --git a/queue-7.0/usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch b/queue-7.0/usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch new file mode 100644 index 0000000000..d47521a6e5 --- /dev/null +++ b/queue-7.0/usb-serial-keyspan-fix-missing-indat-transfer-sanity-check.patch @@ -0,0 +1,34 @@ +From ab8336a7e414f018430aa1af3a46944032f7ff96 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 20 May 2026 16:26:48 +0200 +Subject: USB: serial: keyspan: fix missing indat transfer sanity check + +From: Johan Hovold + +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 +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-serial-mct_u232-fix-memory-corruption-with-small-endpoint.patch b/queue-7.0/usb-serial-mct_u232-fix-memory-corruption-with-small-endpoint.patch new file mode 100644 index 0000000000..b770ccfb24 --- /dev/null +++ b/queue-7.0/usb-serial-mct_u232-fix-memory-corruption-with-small-endpoint.patch @@ -0,0 +1,76 @@ +From 915b36d701950503c4ea0f6e314b10868e59fce3 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 20 May 2026 16:27:00 +0200 +Subject: USB: serial: mct_u232: fix memory corruption with small endpoint + +From: Johan Hovold + +commit 915b36d701950503c4ea0f6e314b10868e59fce3 upstream. + +The driver overrides the maximum transfer size for a specific device +which only accepts 16 byte packets for its 32 byte bulk-out endpoint. + +Make sure to never increase the maximum transfer size to prevent slab +corruption should a malicious device report a smaller endpoint max +packet size than expected. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/serial/mct_u232.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +--- a/drivers/usb/serial/mct_u232.c ++++ b/drivers/usb/serial/mct_u232.c +@@ -378,6 +378,7 @@ static int mct_u232_port_probe(struct us + { + struct usb_serial *serial = port->serial; + struct mct_u232_private *priv; ++ u16 pid; + + /* check first to simplify error handling */ + if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) { +@@ -385,6 +386,16 @@ static int mct_u232_port_probe(struct us + return -ENODEV; + } + ++ /* ++ * Compensate for a hardware bug: although the Sitecom U232-P25 ++ * device reports a maximum output packet size of 32 bytes, ++ * it seems to be able to accept only 16 bytes (and that's what ++ * SniffUSB says too...) ++ */ ++ pid = le16_to_cpu(serial->dev->descriptor.idProduct); ++ if (pid == MCT_U232_SITECOM_PID) ++ port->bulk_out_size = min(16, port->bulk_out_size); ++ + priv = kzalloc_obj(*priv); + if (!priv) + return -ENOMEM; +@@ -410,7 +421,6 @@ static void mct_u232_port_remove(struct + + static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) + { +- struct usb_serial *serial = port->serial; + struct mct_u232_private *priv = usb_get_serial_port_data(port); + int retval = 0; + unsigned int control_state; +@@ -418,15 +428,6 @@ static int mct_u232_open(struct tty_str + unsigned char last_lcr; + unsigned char last_msr; + +- /* Compensate for a hardware bug: although the Sitecom U232-P25 +- * device reports a maximum output packet size of 32 bytes, +- * it seems to be able to accept only 16 bytes (and that's what +- * SniffUSB says too...) +- */ +- if (le16_to_cpu(serial->dev->descriptor.idProduct) +- == MCT_U232_SITECOM_PID) +- port->bulk_out_size = 16; +- + /* Do a defined restart: the normal serial device seems to + * always turn on DTR and RTS here, so do the same. I'm not + * sure if this is really necessary. But it should not harm diff --git a/queue-7.0/usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch b/queue-7.0/usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch new file mode 100644 index 0000000000..e38ca34080 --- /dev/null +++ b/queue-7.0/usb-serial-mct_u232-fix-missing-interrupt-in-transfer-sanity-check.patch @@ -0,0 +1,36 @@ +From 245aba83e3c288e176ed037a1f6b618b09e92ed8 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 20 May 2026 16:27:10 +0200 +Subject: USB: serial: mct_u232: fix missing interrupt-in transfer sanity check + +From: Johan Hovold + +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 +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -544,6 +544,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-7.0/usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch b/queue-7.0/usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch new file mode 100644 index 0000000000..556573c7ca --- /dev/null +++ b/queue-7.0/usb-serial-mxuport-fix-memory-corruption-with-small-endpoint.patch @@ -0,0 +1,40 @@ +From 4085f0dbb1ce2251c9a5938d693de6593f0ab2bd Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Fri, 22 May 2026 16:19:50 +0200 +Subject: USB: serial: mxuport: fix memory corruption with small endpoint + +From: Johan Hovold + +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 +Reviewed-by: Greg Kroah-Hartman +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-serial-option-add-meig-srm813q.patch b/queue-7.0/usb-serial-option-add-meig-srm813q.patch new file mode 100644 index 0000000000..cefd008b55 --- /dev/null +++ b/queue-7.0/usb-serial-option-add-meig-srm813q.patch @@ -0,0 +1,94 @@ +From 7d2b37d3e42d19071b62f4ddbee6e16e905efbf1 Mon Sep 17 00:00:00 2001 +From: Jan Volckaert +Date: Sun, 17 May 2026 17:32:37 +0200 +Subject: USB: serial: option: add MeiG SRM813Q + +From: Jan Volckaert + +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 +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch b/queue-7.0/usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch new file mode 100644 index 0000000000..4da87dade0 --- /dev/null +++ b/queue-7.0/usb-serial-option-add-missing-rsvd-5-flag-for-rolling-rw135r-gl.patch @@ -0,0 +1,132 @@ +From 689f2facc689c8add11d7ff69fbbad17d65ee596 Mon Sep 17 00:00:00 2001 +From: Wanquan Zhong +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 + +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 +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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-7.0/usb-storage-add-quirks-for-pny-elite-portable-ssd.patch b/queue-7.0/usb-storage-add-quirks-for-pny-elite-portable-ssd.patch new file mode 100644 index 0000000000..94606dacf4 --- /dev/null +++ b/queue-7.0/usb-storage-add-quirks-for-pny-elite-portable-ssd.patch @@ -0,0 +1,69 @@ +From b53ebb811e00be50a779ce4e7aee604178b4a825 Mon Sep 17 00:00:00 2001 +From: Sam Burkels +Date: Fri, 1 May 2026 15:23:46 +0200 +Subject: usb: storage: Add quirks for PNY Elite Portable SSD + +From: Sam Burkels + +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 +Acked-by: Oliver Neukum +Cc: stable +Link: https://patch.msgid.link/20260501132346.86572-1-sam@1a38.nl +Signed-off-by: Greg Kroah-Hartman +--- + 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 */ ++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 */ + UNUSUAL_DEV(0x154b, 0xf00b, 0x0000, 0x9999, + "PNY", diff --git a/queue-7.0/usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch b/queue-7.0/usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch new file mode 100644 index 0000000000..41c3933954 --- /dev/null +++ b/queue-7.0/usb-typec-tcpm-improve-handling-of-discover_modes-failures.patch @@ -0,0 +1,185 @@ +From c06e6cd488194e37ed4dc29d1488d1ffb760de60 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Wed, 29 Apr 2026 18:33:32 +0200 +Subject: usb: typec: tcpm: improve handling of DISCOVER_MODES failures + +From: Sebastian Reichel + +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 +Fixes: 41d9d75344d9 ("usb: typec: tcpm: add discover svids and discover modes support for sop'") +Reviewed-by: Heikki Krogerus +Signed-off-by: Sebastian Reichel +Reviewed-by: RD Babiera +Reviewed-by: Badhri Jagan Sridharan +Link: https://patch.msgid.link/20260429-tcpm-discover-modes-nak-fix-v4-1-75945d0ed30f@collabora.com +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -2002,6 +2002,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, +@@ -2259,41 +2308,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; +@@ -2336,9 +2355,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-7.0/usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch b/queue-7.0/usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch new file mode 100644 index 0000000000..3c784a42ab --- /dev/null +++ b/queue-7.0/usb-typec-tipd-fix-error-code-in-tps6598x_probe.patch @@ -0,0 +1,33 @@ +From b02900c85a6423cf9b3dcc6b47bf060c85075e69 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Tue, 12 May 2026 13:14:59 +0300 +Subject: usb: typec: tipd: Fix error code in tps6598x_probe() + +From: Dan Carpenter + +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 +Signed-off-by: Dan Carpenter +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/agL9o7wUK1dOVBTy@stanley.mountain +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1835,6 +1835,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-7.0/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch b/queue-7.0/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch new file mode 100644 index 0000000000..501b2c1ba0 --- /dev/null +++ b/queue-7.0/usb-typec-ucsi-check-if-power-role-change-actually-happened-before-handling.patch @@ -0,0 +1,63 @@ +From b80e7d34c7ea6a564525119d6138fbb577a23dba Mon Sep 17 00:00:00 2001 +From: Myrrh Periwinkle +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 + +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 +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-1-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1267,7 +1267,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; +@@ -1278,6 +1278,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", +@@ -1294,7 +1296,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-7.0/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch b/queue-7.0/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch new file mode 100644 index 0000000000..028dd46041 --- /dev/null +++ b/queue-7.0/usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch @@ -0,0 +1,39 @@ +From d98d413ca65d0790a8f3695d0a5845538958ab84 Mon Sep 17 00:00:00 2001 +From: Myrrh Periwinkle +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 + +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 +Fixes: 7616f006db07 ("usb: typec: ucsi: Update power_supply on power role change") +Signed-off-by: Myrrh Periwinkle +Reported-and-tested-by: Sergey Senozhatsky +Link: https://patch.msgid.link/20260519-ucsi-fix-2-v1-2-6f1239535187@qtmlabs.xyz +Signed-off-by: Greg Kroah-Hartman +--- + 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 +@@ -1298,7 +1298,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-7.0/usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch b/queue-7.0/usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch new file mode 100644 index 0000000000..4653ae7b87 --- /dev/null +++ b/queue-7.0/usb-usbtmc-check-urb-actual_length-for-interrupt-in-notifications.patch @@ -0,0 +1,49 @@ +From 52f2ad3f7e5eb3b5908e1d685d4342519dc9cfcd Mon Sep 17 00:00:00 2001 +From: Heitor Alves de Siqueira +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 + +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 +Suggested-by: Michal Pecio +Signed-off-by: Heitor Alves de Siqueira +Link: https://patch.msgid.link/20260505-usbtmc-iin-size-v3-1-a36113f62db7@igalia.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/usbtmc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/usb/class/usbtmc.c ++++ b/drivers/usb/class/usbtmc.c +@@ -2306,6 +2306,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-7.0/usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch b/queue-7.0/usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch new file mode 100644 index 0000000000..86bf3e6a9c --- /dev/null +++ b/queue-7.0/usb-usbtmc-reject-interrupt-endpoints-with-small-wmaxpacketsize.patch @@ -0,0 +1,41 @@ +From 121d2f682ba912b1427cddca7cf84840f41cc620 Mon Sep 17 00:00:00 2001 +From: Heitor Alves de Siqueira +Date: Tue, 5 May 2026 15:56:04 -0300 +Subject: usb: usbtmc: reject interrupt endpoints with small wMaxPacketSize + +From: Heitor Alves de Siqueira + +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 +Suggested-by: Michal Pecio +Signed-off-by: Heitor Alves de Siqueira +Link: https://patch.msgid.link/20260505-usbtmc-iin-size-v3-2-a36113f62db7@igalia.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/usbtmc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/usb/class/usbtmc.c ++++ b/drivers/usb/class/usbtmc.c +@@ -2440,6 +2440,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-7.0/usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch b/queue-7.0/usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch new file mode 100644 index 0000000000..0b9f306bba --- /dev/null +++ b/queue-7.0/usbip-vudc-fix-use-after-free-bug-in-vudc_remove-due-to-race-condition.patch @@ -0,0 +1,77 @@ +From d96209626a29ea64666be98c30b30ac82e5f1be6 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +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 + +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 +Reported-by: Zheng Wang +Closes: https://lore.kernel.org/linux-usb/20230317100954.2626573-1-zyytlz.wz@163.com/ +Signed-off-by: Michael Bommarito +Acked-by: Shuah Khan +Link: https://patch.msgid.link/20260417163552.807548-1-michael.bommarito@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + 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; + }