From: Greg Kroah-Hartman Date: Mon, 16 Mar 2026 15:54:53 +0000 (+0100) Subject: 6.18-stable patches X-Git-Tag: v6.18.19~70 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=78b1248207fa9d1ccbf009c55fcd825d819061c1;p=thirdparty%2Fkernel%2Fstable-queue.git 6.18-stable patches added patches: asoc-amd-yc-add-dmi-quirk-for-asus-expertbook-pm1503cda.patch ata-libata-core-add-bridge_ok-quirk-for-qemu-drives.patch kvm-arm64-fix-protected-mode-handling-of-pages-larger-than-4kb.patch kvm-arm64-pkvm-fallback-to-level-3-mapping-on-host-stage-2-fault.patch kvm-svm-initialize-avic-vmcb-fields-if-avic-is-enabled-with-in-kernel-apic.patch kvm-x86-introduce-kvm_x86_quirk_vmcs12_allow_freeze_in_smm.patch revert-usb-gadget-f_ncm-align-net_device-lifecycle-with-bind-unbind.patch revert-usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch revert-usb-gadget-u_ether-add-auto-cleanup-helper-for-freeing-net_device.patch revert-usb-gadget-u_ether-add-gether_opts-for-config-caching.patch revert-usb-legacy-ncm-fix-npe-in-gncm_bind.patch usb-add-quirk_no_bos-for-video-capture-several-devices.patch usb-cdc-acm-restore-cap_brk-functionnality-to-ch343.patch usb-class-cdc-wdm-fix-reordering-issue-in-read-code-path.patch usb-core-don-t-power-off-roothub-phys-if-phy_set_mode-fails.patch usb-core-limit-the-length-of-unkillable-synchronous-timeouts.patch usb-core-quirks-add-huawei-me906s-device-to-wakeup-quirk.patch usb-dwc3-pci-add-support-for-the-intel-nova-lake-h.patch usb-ezcap401-needs-usb_quirk_no_bos-to-function-on-10gbs-usb-speed.patch usb-gadget-f_hid-fix-superspeed-descriptors.patch usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch usb-gadget-f_ncm-fix-net_device-lifecycle-with-device_move.patch usb-gadget-f_tcm-fix-null-pointer-dereferences-in-nexus-handling.patch usb-gadget-uvc-fix-interval_duration-calculation.patch usb-image-mdc800-kill-download-urb-on-timeout.patch usb-legacy-ncm-fix-npe-in-gncm_bind.patch usb-mdc800-handle-signal-and-read-racing.patch usb-misc-uss720-properly-clean-up-reference-in-uss720_probe.patch usb-renesas_usbhs-fix-use-after-free-in-isr-during-device-removal.patch usb-roles-get-usb-role-switch-from-parent-only-for-usb-b-connector.patch usb-typec-altmode-displayport-set-displayport-signaling-rate-in-configure-message.patch usb-usbcore-introduce-usb_bulk_msg_killable.patch usb-usbtmc-use-usb_bulk_msg_killable-with-user-specified-timeouts.patch usb-xhci-fix-memory-leak-in-xhci_disable_slot.patch usb-xhci-prevent-interrupt-storm-on-host-controller-error-hce.patch usb-yurex-fix-race-in-probe.patch --- diff --git a/queue-6.18/asoc-amd-yc-add-dmi-quirk-for-asus-expertbook-pm1503cda.patch b/queue-6.18/asoc-amd-yc-add-dmi-quirk-for-asus-expertbook-pm1503cda.patch new file mode 100644 index 0000000000..b798e38290 --- /dev/null +++ b/queue-6.18/asoc-amd-yc-add-dmi-quirk-for-asus-expertbook-pm1503cda.patch @@ -0,0 +1,38 @@ +From 325291b20f8a6f14b9c82edbf5d12e4e71f6adaa Mon Sep 17 00:00:00 2001 +From: Zhang Heng +Date: Wed, 4 Mar 2026 14:32:55 +0800 +Subject: ASoC: amd: yc: Add DMI quirk for ASUS EXPERTBOOK PM1503CDA + +From: Zhang Heng + +commit 325291b20f8a6f14b9c82edbf5d12e4e71f6adaa upstream. + +Add a DMI quirk for the ASUS EXPERTBOOK PM1503CDA fixing the +issue where the internal microphone was not detected. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221070 +Cc: stable@vger.kernel.org +Signed-off-by: Zhang Heng +Link: https://patch.msgid.link/20260304063255.139331-1-zhangheng@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/sound/soc/amd/yc/acp6x-mach.c ++++ b/sound/soc/amd/yc/acp6x-mach.c +@@ -710,6 +710,13 @@ static const struct dmi_system_id yc_acp + DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK BM1503CDA"), + } + }, ++ { ++ .driver_data = &acp6x_card, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), ++ DMI_MATCH(DMI_BOARD_NAME, "PM1503CDA"), ++ } ++ }, + {} + }; + diff --git a/queue-6.18/ata-libata-core-add-bridge_ok-quirk-for-qemu-drives.patch b/queue-6.18/ata-libata-core-add-bridge_ok-quirk-for-qemu-drives.patch new file mode 100644 index 0000000000..7e19db3cb8 --- /dev/null +++ b/queue-6.18/ata-libata-core-add-bridge_ok-quirk-for-qemu-drives.patch @@ -0,0 +1,48 @@ +From b92b0075ee1870f78f59ab1f7da7dbfdd718ad7a Mon Sep 17 00:00:00 2001 +From: Pedro Falcato +Date: Thu, 5 Mar 2026 14:53:12 +0000 +Subject: ata: libata-core: Add BRIDGE_OK quirk for QEMU drives + +From: Pedro Falcato + +commit b92b0075ee1870f78f59ab1f7da7dbfdd718ad7a upstream. + +Currently, whenever you boot with a QEMU drive over an AHCI interface, +you get: +[ 1.632121] ata1.00: applying bridge limits + +This happens due to the kernel not believing the given drive is SATA, +since word 93 of IDENTIFY (ATA_ID_HW_CONFIG) is non-zero. The result is +a pretty severe limit in max_hw_sectors_kb, which limits our IO sizes. + +QEMU has set word 93 erroneously for SATA drives but does not, in any +way, emulate any of these real hardware details. There is no PATA +drive and no SATA cable. + +As such, add a BRIDGE_OK quirk for QEMU HARDDISK. Special care is taken +to limit this quirk to "2.5+", to allow for fixed future versions. + +This results in the max_hw_sectors being limited solely by the +controller interface's limits. Which, for AHCI controllers, takes it +from 128KB to 32767KB. + +Cc: stable@vger.kernel.org +Signed-off-by: Pedro Falcato +Reviewed-by: Damien Le Moal +Reviewed-by: Hannes Reinecke +Signed-off-by: Niklas Cassel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/ata/libata-core.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -4199,6 +4199,7 @@ static const struct ata_dev_quirks_entry + /* Devices that do not need bridging limits applied */ + { "MTRON MSP-SATA*", NULL, ATA_QUIRK_BRIDGE_OK }, + { "BUFFALO HD-QSU2/R5", NULL, ATA_QUIRK_BRIDGE_OK }, ++ { "QEMU HARDDISK", "2.5+", ATA_QUIRK_BRIDGE_OK }, + + /* Devices which aren't very happy with higher link speeds */ + { "WD My Book", NULL, ATA_QUIRK_1_5_GBPS }, diff --git a/queue-6.18/kvm-arm64-fix-protected-mode-handling-of-pages-larger-than-4kb.patch b/queue-6.18/kvm-arm64-fix-protected-mode-handling-of-pages-larger-than-4kb.patch new file mode 100644 index 0000000000..3f258470b9 --- /dev/null +++ b/queue-6.18/kvm-arm64-fix-protected-mode-handling-of-pages-larger-than-4kb.patch @@ -0,0 +1,81 @@ +From 08f97454b7fa39bfcf82524955c771d2d693d6fe Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Sun, 22 Feb 2026 13:35:13 +0000 +Subject: KVM: arm64: Fix protected mode handling of pages larger than 4kB + +From: Marc Zyngier + +commit 08f97454b7fa39bfcf82524955c771d2d693d6fe upstream. + +Since 3669ddd8fa8b5 ("KVM: arm64: Add a range to pkvm_mappings"), +pKVM tracks the memory that has been mapped into a guest in a +side data structure. Crucially, it uses it to find out whether +a page has already been mapped, and therefore refuses to map it +twice. So far, so good. + +However, this very patch completely breaks non-4kB page support, +with guests being unable to boot. The most obvious symptom is that +we take the same fault repeatedly, and not making forward progress. +A quick investigation shows that this is because of the above +rejection code. + +As it turns out, there are multiple issues at play: + +- while the HPFAR_EL2 register gives you the faulting IPA minus + the bottom 12 bits, it will still give you the extra bits that + are part of the page offset for anything larger than 4kB, + even for a level-3 mapping + +- pkvm_pgtable_stage2_map() assumes that the address passed as + a parameter is aligned to the size of the intended mapping + +- the faulting address is only aligned for a non-page mapping + +When the planets are suitably aligned (pun intended), the guest +faults on a page by accessing it past the bottom 4kB, and extra bits +get set in the HPFAR_EL2 register. If this results in a page mapping +(which is likely with large granule sizes), nothing aligns it further +down, and pkvm_mapping_iter_first() finds an intersection that +doesn't really exist. We assume this is a spurious fault and return +-EAGAIN. And again... + +This doesn't hit outside of the protected code, as the page table +code always aligns the IPA down to a page boundary, hiding the issue +for everyone else. + +Fix it by always forcing the alignment on vma_pagesize, irrespective +of the value of vma_pagesize. + +Fixes: 3669ddd8fa8b5 ("KVM: arm64: Add a range to pkvm_mappings") +Reviewed-by: Fuad Tabba +Tested-by: Fuad Tabba +Signed-off-by: Marc Zyngier +Link: https://https://patch.msgid.link/20260222141000.3084258-1-maz@kernel.org +Cc: stable@vger.kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kvm/mmu.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/arch/arm64/kvm/mmu.c ++++ b/arch/arm64/kvm/mmu.c +@@ -1712,14 +1712,12 @@ static int user_mem_abort(struct kvm_vcp + } + + /* +- * Both the canonical IPA and fault IPA must be hugepage-aligned to +- * ensure we find the right PFN and lay down the mapping in the right +- * place. ++ * Both the canonical IPA and fault IPA must be aligned to the ++ * mapping size to ensure we find the right PFN and lay down the ++ * mapping in the right place. + */ +- if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) { +- fault_ipa &= ~(vma_pagesize - 1); +- ipa &= ~(vma_pagesize - 1); +- } ++ fault_ipa = ALIGN_DOWN(fault_ipa, vma_pagesize); ++ ipa = ALIGN_DOWN(ipa, vma_pagesize); + + gfn = ipa >> PAGE_SHIFT; + mte_allowed = kvm_vma_mte_allowed(vma); diff --git a/queue-6.18/kvm-arm64-pkvm-fallback-to-level-3-mapping-on-host-stage-2-fault.patch b/queue-6.18/kvm-arm64-pkvm-fallback-to-level-3-mapping-on-host-stage-2-fault.patch new file mode 100644 index 0000000000..9e2a2bab3b --- /dev/null +++ b/queue-6.18/kvm-arm64-pkvm-fallback-to-level-3-mapping-on-host-stage-2-fault.patch @@ -0,0 +1,43 @@ +From 8531d5a83d8eb8affb5c0249b466c28d94192603 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Thu, 5 Mar 2026 13:27:51 +0000 +Subject: KVM: arm64: pkvm: Fallback to level-3 mapping on host stage-2 fault + +From: Marc Zyngier + +commit 8531d5a83d8eb8affb5c0249b466c28d94192603 upstream. + +If, for any odd reason, we cannot converge to mapping size that is +completely contained in a memblock region, we fail to install a S2 +mapping and go back to the faulting instruction. Rince, repeat. + +This happens when faulting in regions that are smaller than a page +or that do not have PAGE_SIZE-aligned boundaries (as witnessed on +an O6 board that refuses to boot in protected mode). + +In this situation, fallback to using a PAGE_SIZE mapping anyway -- +it isn't like we can go any lower. + +Fixes: e728e705802fe ("KVM: arm64: Adjust range correctly during host stage-2 faults") +Link: https://lore.kernel.org/r/86wlzr77cn.wl-maz@kernel.org +Cc: stable@vger.kernel.org +Cc: Quentin Perret +Reviewed-by: Quentin Perret +Link: https://patch.msgid.link/20260305132751.2928138-1-maz@kernel.org +Signed-off-by: Marc Zyngier +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/kvm/hyp/nvhe/mem_protect.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c ++++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c +@@ -516,7 +516,7 @@ static int host_stage2_adjust_range(u64 + granule = kvm_granule_size(level); + cur.start = ALIGN_DOWN(addr, granule); + cur.end = cur.start + granule; +- if (!range_included(&cur, range)) ++ if (!range_included(&cur, range) && level < KVM_PGTABLE_LAST_LEVEL) + continue; + *range = cur; + return 0; diff --git a/queue-6.18/kvm-svm-initialize-avic-vmcb-fields-if-avic-is-enabled-with-in-kernel-apic.patch b/queue-6.18/kvm-svm-initialize-avic-vmcb-fields-if-avic-is-enabled-with-in-kernel-apic.patch new file mode 100644 index 0000000000..ce19e1bc72 --- /dev/null +++ b/queue-6.18/kvm-svm-initialize-avic-vmcb-fields-if-avic-is-enabled-with-in-kernel-apic.patch @@ -0,0 +1,61 @@ +From 3989a6d036c8ec82c0de3614bed23a1dacd45de5 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Tue, 3 Feb 2026 11:07:09 -0800 +Subject: KVM: SVM: Initialize AVIC VMCB fields if AVIC is enabled with in-kernel APIC + +From: Sean Christopherson + +commit 3989a6d036c8ec82c0de3614bed23a1dacd45de5 upstream. + +Initialize all per-vCPU AVIC control fields in the VMCB if AVIC is enabled +in KVM and the VM has an in-kernel local APIC, i.e. if it's _possible_ the +vCPU could activate AVIC at any point in its lifecycle. Configuring the +VMCB if and only if AVIC is active "works" purely because of optimizations +in kvm_create_lapic() to speculatively set apicv_active if AVIC is enabled +*and* to defer updates until the first KVM_RUN. In quotes because KVM +likely won't do the right thing if kvm_apicv_activated() is false, i.e. if +a vCPU is created while APICv is inhibited at the VM level for whatever +reason. E.g. if the inhibit is *removed* before KVM_REQ_APICV_UPDATE is +handled in KVM_RUN, then __kvm_vcpu_update_apicv() will elide calls to +vendor code due to seeing "apicv_active == activate". + +Cleaning up the initialization code will also allow fixing a bug where KVM +incorrectly leaves CR8 interception enabled when AVIC is activated without +creating a mess with respect to whether AVIC is activated or not. + +Cc: stable@vger.kernel.org +Fixes: 67034bb9dd5e ("KVM: SVM: Add irqchip_split() checks before enabling AVIC") +Fixes: 6c3e4422dd20 ("svm: Add support for dynamic APICv") +Reviewed-by: Naveen N Rao (AMD) +Reviewed-by: Jim Mattson +Link: https://patch.msgid.link/20260203190711.458413-2-seanjc@google.com +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/svm/avic.c | 2 +- + arch/x86/kvm/svm/svm.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/x86/kvm/svm/avic.c ++++ b/arch/x86/kvm/svm/avic.c +@@ -321,7 +321,7 @@ void avic_init_vmcb(struct vcpu_svm *svm + vmcb->control.avic_physical_id = __sme_set(__pa(kvm_svm->avic_physical_id_table)); + vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE; + +- if (kvm_apicv_activated(svm->vcpu.kvm)) ++ if (kvm_vcpu_apicv_active(&svm->vcpu)) + avic_activate_vmcb(svm); + else + avic_deactivate_vmcb(svm); +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -1141,7 +1141,7 @@ static void init_vmcb(struct kvm_vcpu *v + svm_clr_intercept(svm, INTERCEPT_PAUSE); + } + +- if (kvm_vcpu_apicv_active(vcpu)) ++ if (enable_apicv && irqchip_in_kernel(vcpu->kvm)) + avic_init_vmcb(svm, vmcb); + + if (vnmi) diff --git a/queue-6.18/kvm-x86-introduce-kvm_x86_quirk_vmcs12_allow_freeze_in_smm.patch b/queue-6.18/kvm-x86-introduce-kvm_x86_quirk_vmcs12_allow_freeze_in_smm.patch new file mode 100644 index 0000000000..709a3cd2c2 --- /dev/null +++ b/queue-6.18/kvm-x86-introduce-kvm_x86_quirk_vmcs12_allow_freeze_in_smm.patch @@ -0,0 +1,108 @@ +From e2ffe85b6d2bb7780174b87aa4468a39be17eb81 Mon Sep 17 00:00:00 2001 +From: Jim Mattson +Date: Thu, 5 Feb 2026 15:15:26 -0800 +Subject: KVM: x86: Introduce KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM + +From: Jim Mattson + +commit e2ffe85b6d2bb7780174b87aa4468a39be17eb81 upstream. + +Add KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM to allow L1 to set +FREEZE_IN_SMM in vmcs12's GUEST_IA32_DEBUGCTL field, as permitted +prior to commit 6b1dd26544d0 ("KVM: VMX: Preserve host's +DEBUGCTLMSR_FREEZE_IN_SMM while running the guest"). Enable the quirk +by default for backwards compatibility (like all quirks); userspace +can disable it via KVM_CAP_DISABLE_QUIRKS2 for consistency with the +constraints on WRMSR(IA32_DEBUGCTL). + +Note that the quirk only bypasses the consistency check. The vmcs02 bit is +still owned by the host, and PMCs are not frozen during virtualized SMM. +In particular, if a host administrator decides that PMCs should not be +frozen during physical SMM, then L1 has no say in the matter. + +Fixes: 095686e6fcb4 ("KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter") +Cc: stable@vger.kernel.org +Signed-off-by: Jim Mattson +Link: https://patch.msgid.link/20260205231537.1278753-1-jmattson@google.com +[sean: tag for stable@, clean-up and fix goofs in the comment and docs] +Signed-off-by: Sean Christopherson +[Rename quirk. - Paolo] +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/virt/kvm/api.rst | 8 ++++++++ + arch/x86/include/asm/kvm_host.h | 3 ++- + arch/x86/include/uapi/asm/kvm.h | 1 + + arch/x86/kvm/vmx/nested.c | 22 ++++++++++++++++++---- + 4 files changed, 29 insertions(+), 5 deletions(-) + +--- a/Documentation/virt/kvm/api.rst ++++ b/Documentation/virt/kvm/api.rst +@@ -8403,6 +8403,14 @@ KVM_X86_QUIRK_IGNORE_GUEST_PAT By d + guest software, for example if it does not + expose a bochs graphics device (which is + known to have had a buggy driver). ++ ++KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM By default, KVM relaxes the consistency ++ check for GUEST_IA32_DEBUGCTL in vmcs12 ++ to allow FREEZE_IN_SMM to be set. When ++ this quirk is disabled, KVM requires this ++ bit to be cleared. Note that the vmcs02 ++ bit is still completely controlled by the ++ host, regardless of the quirk setting. + =================================== ============================================ + + 7.32 KVM_CAP_MAX_VCPU_ID +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -2473,7 +2473,8 @@ int memslot_rmap_alloc(struct kvm_memory + KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS | \ + KVM_X86_QUIRK_SLOT_ZAP_ALL | \ + KVM_X86_QUIRK_STUFF_FEATURE_MSRS | \ +- KVM_X86_QUIRK_IGNORE_GUEST_PAT) ++ KVM_X86_QUIRK_IGNORE_GUEST_PAT | \ ++ KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM) + + #define KVM_X86_CONDITIONAL_QUIRKS \ + (KVM_X86_QUIRK_CD_NW_CLEARED | \ +--- a/arch/x86/include/uapi/asm/kvm.h ++++ b/arch/x86/include/uapi/asm/kvm.h +@@ -476,6 +476,7 @@ struct kvm_sync_regs { + #define KVM_X86_QUIRK_SLOT_ZAP_ALL (1 << 7) + #define KVM_X86_QUIRK_STUFF_FEATURE_MSRS (1 << 8) + #define KVM_X86_QUIRK_IGNORE_GUEST_PAT (1 << 9) ++#define KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM (1 << 10) + + #define KVM_STATE_NESTED_FORMAT_VMX 0 + #define KVM_STATE_NESTED_FORMAT_SVM 1 +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -3262,10 +3262,24 @@ static int nested_vmx_check_guest_state( + if (CC(vmcs12->guest_cr4 & X86_CR4_CET && !(vmcs12->guest_cr0 & X86_CR0_WP))) + return -EINVAL; + +- if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) && +- (CC(!kvm_dr7_valid(vmcs12->guest_dr7)) || +- CC(!vmx_is_valid_debugctl(vcpu, vmcs12->guest_ia32_debugctl, false)))) +- return -EINVAL; ++ if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) { ++ u64 debugctl = vmcs12->guest_ia32_debugctl; ++ ++ /* ++ * FREEZE_IN_SMM is not virtualized, but allow L1 to set it in ++ * vmcs12's DEBUGCTL under a quirk for backwards compatibility. ++ * Note that the quirk only relaxes the consistency check. The ++ * vmcc02 bit is still under the control of the host. In ++ * particular, if a host administrator decides to clear the bit, ++ * then L1 has no say in the matter. ++ */ ++ if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM)) ++ debugctl &= ~DEBUGCTLMSR_FREEZE_IN_SMM; ++ ++ if (CC(!kvm_dr7_valid(vmcs12->guest_dr7)) || ++ CC(!vmx_is_valid_debugctl(vcpu, debugctl, false))) ++ return -EINVAL; ++ } + + if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) && + CC(!kvm_pat_valid(vmcs12->guest_ia32_pat))) diff --git a/queue-6.18/revert-usb-gadget-f_ncm-align-net_device-lifecycle-with-bind-unbind.patch b/queue-6.18/revert-usb-gadget-f_ncm-align-net_device-lifecycle-with-bind-unbind.patch new file mode 100644 index 0000000000..60d5b650ca --- /dev/null +++ b/queue-6.18/revert-usb-gadget-f_ncm-align-net_device-lifecycle-with-bind-unbind.patch @@ -0,0 +1,343 @@ +From 37893bc5de2460c543ec1aa8250c37a305234054 Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Mon, 9 Mar 2026 20:04:48 +0800 +Subject: Revert "usb: gadget: f_ncm: align net_device lifecycle with bind/unbind" + +From: Kuen-Han Tsai + +commit 37893bc5de2460c543ec1aa8250c37a305234054 upstream. + +This reverts commit 56a512a9b4107079f68701e7d55da8507eb963d9. + +This commit is being reverted as part of a series-wide revert. + +By deferring the net_device allocation to the bind() phase, a single +function instance will spawn multiple network devices if it is symlinked +to multiple USB configurations. + +This causes regressions for userspace tools (like the postmarketOS DHCP +daemon) that rely on reading the interface name (e.g., "usb0") from +configfs. Currently, configfs returns the template "usb%d", causing the +userspace network setup to fail. + +Crucially, because this patch breaks the 1:1 mapping between the +function instance and the network device, this naming issue cannot +simply be patched. Configfs only exposes a single 'ifname' attribute per +instance, making it impossible to accurately report the actual interface +name when multiple underlying network devices can exist for that single +instance. + +All configurations tied to the same function instance are meant to share +a single network device. Revert this change to restore the 1:1 mapping +by allocating the network device at the instance level (alloc_inst). + +Reported-by: David Heidelberg +Closes: https://lore.kernel.org/linux-usb/70b558ea-a12e-4170-9b8e-c951131249af@ixit.cz/ +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-3-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_ncm.c | 128 ++++++++++++++++++------------------ + drivers/usb/gadget/function/u_ncm.h | 4 - + 2 files changed, 66 insertions(+), 66 deletions(-) + +--- a/drivers/usb/gadget/function/f_ncm.c ++++ b/drivers/usb/gadget/function/f_ncm.c +@@ -83,11 +83,6 @@ static inline struct f_ncm *func_to_ncm( + return container_of(f, struct f_ncm, port.func); + } + +-static inline struct f_ncm_opts *func_to_ncm_opts(struct usb_function *f) +-{ +- return container_of(f->fi, struct f_ncm_opts, func_inst); +-} +- + /*-------------------------------------------------------------------------*/ + + /* +@@ -864,7 +859,6 @@ invalid: + static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + { + struct f_ncm *ncm = func_to_ncm(f); +- struct f_ncm_opts *opts = func_to_ncm_opts(f); + struct usb_composite_dev *cdev = f->config->cdev; + + /* Control interface has only altsetting 0 */ +@@ -887,13 +881,12 @@ static int ncm_set_alt(struct usb_functi + if (alt > 1) + goto fail; + +- scoped_guard(mutex, &opts->lock) +- if (opts->net) { +- DBG(cdev, "reset ncm\n"); +- opts->net = NULL; +- gether_disconnect(&ncm->port); +- ncm_reset_values(ncm); +- } ++ if (ncm->netdev) { ++ DBG(cdev, "reset ncm\n"); ++ ncm->netdev = NULL; ++ gether_disconnect(&ncm->port); ++ ncm_reset_values(ncm); ++ } + + /* + * CDC Network only sends data in non-default altsettings. +@@ -926,8 +919,7 @@ static int ncm_set_alt(struct usb_functi + net = gether_connect(&ncm->port); + if (IS_ERR(net)) + return PTR_ERR(net); +- scoped_guard(mutex, &opts->lock) +- opts->net = net; ++ ncm->netdev = net; + } + + spin_lock(&ncm->lock); +@@ -1374,16 +1366,14 @@ err: + static void ncm_disable(struct usb_function *f) + { + struct f_ncm *ncm = func_to_ncm(f); +- struct f_ncm_opts *opts = func_to_ncm_opts(f); + struct usb_composite_dev *cdev = f->config->cdev; + + DBG(cdev, "ncm deactivated\n"); + +- scoped_guard(mutex, &opts->lock) +- if (opts->net) { +- opts->net = NULL; +- gether_disconnect(&ncm->port); +- } ++ if (ncm->netdev) { ++ ncm->netdev = NULL; ++ gether_disconnect(&ncm->port); ++ } + + if (ncm->notify->enabled) { + usb_ep_disable(ncm->notify); +@@ -1443,44 +1433,39 @@ static int ncm_bind(struct usb_configura + { + struct usb_composite_dev *cdev = c->cdev; + struct f_ncm *ncm = func_to_ncm(f); +- struct f_ncm_opts *ncm_opts = func_to_ncm_opts(f); + struct usb_string *us; + int status = 0; + struct usb_ep *ep; ++ struct f_ncm_opts *ncm_opts; + + struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; +- struct net_device *netdev __free(free_gether_netdev) = NULL; + struct usb_request *request __free(free_usb_request) = NULL; + + if (!can_support_ecm(cdev->gadget)) + return -EINVAL; + ++ ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); ++ + if (cdev->use_os_string) { + os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL); + if (!os_desc_table) + return -ENOMEM; + } + +- netdev = gether_setup_default(); +- if (IS_ERR(netdev)) +- return -ENOMEM; +- +- scoped_guard(mutex, &ncm_opts->lock) { +- gether_apply_opts(netdev, &ncm_opts->net_opts); +- netdev->mtu = ncm_opts->max_segment_size - ETH_HLEN; ++ mutex_lock(&ncm_opts->lock); ++ gether_set_gadget(ncm_opts->net, cdev->gadget); ++ if (!ncm_opts->bound) { ++ ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); ++ status = gether_register_netdev(ncm_opts->net); + } ++ mutex_unlock(&ncm_opts->lock); + +- gether_set_gadget(netdev, cdev->gadget); +- status = gether_register_netdev(netdev); + if (status) + return status; + +- /* export host's Ethernet address in CDC format */ +- status = gether_get_host_addr_cdc(netdev, ncm->ethaddr, +- sizeof(ncm->ethaddr)); +- if (status < 12) +- return -EINVAL; +- ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; ++ ncm_opts->bound = true; ++ ++ ncm_string_defs[1].s = ncm->ethaddr; + + us = usb_gstrings_attach(cdev, ncm_strings, + ARRAY_SIZE(ncm_string_defs)); +@@ -1578,8 +1563,6 @@ static int ncm_bind(struct usb_configura + f->os_desc_n = 1; + } + ncm->notify_req = no_free_ptr(request); +- ncm->netdev = no_free_ptr(netdev); +- ncm->port.ioport = netdev_priv(ncm->netdev); + + DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", + ncm->port.in_ep->name, ncm->port.out_ep->name, +@@ -1594,19 +1577,19 @@ static inline struct f_ncm_opts *to_f_nc + } + + /* f_ncm_item_ops */ +-USB_ETHER_OPTS_ITEM(ncm); ++USB_ETHERNET_CONFIGFS_ITEM(ncm); + + /* f_ncm_opts_dev_addr */ +-USB_ETHER_OPTS_ATTR_DEV_ADDR(ncm); ++USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm); + + /* f_ncm_opts_host_addr */ +-USB_ETHER_OPTS_ATTR_HOST_ADDR(ncm); ++USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm); + + /* f_ncm_opts_qmult */ +-USB_ETHER_OPTS_ATTR_QMULT(ncm); ++USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm); + + /* f_ncm_opts_ifname */ +-USB_ETHER_OPTS_ATTR_IFNAME(ncm); ++USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm); + + static ssize_t ncm_opts_max_segment_size_show(struct config_item *item, + char *page) +@@ -1672,27 +1655,34 @@ static void ncm_free_inst(struct usb_fun + struct f_ncm_opts *opts; + + opts = container_of(f, struct f_ncm_opts, func_inst); ++ if (opts->bound) ++ gether_cleanup(netdev_priv(opts->net)); ++ else ++ free_netdev(opts->net); + kfree(opts->ncm_interf_group); + kfree(opts); + } + + static struct usb_function_instance *ncm_alloc_inst(void) + { +- struct usb_function_instance *ret; ++ struct f_ncm_opts *opts; + struct usb_os_desc *descs[1]; + char *names[1]; + struct config_group *ncm_interf_group; + +- struct f_ncm_opts *opts __free(kfree) = kzalloc(sizeof(*opts), GFP_KERNEL); ++ opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); +- +- opts->net = NULL; + opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; +- gether_setup_opts_default(&opts->net_opts, "usb"); + + mutex_init(&opts->lock); + opts->func_inst.free_func_inst = ncm_free_inst; ++ opts->net = gether_setup_default(); ++ if (IS_ERR(opts->net)) { ++ struct net_device *net = opts->net; ++ kfree(opts); ++ return ERR_CAST(net); ++ } + opts->max_segment_size = ETH_FRAME_LEN; + INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); + +@@ -1703,22 +1693,26 @@ static struct usb_function_instance *ncm + ncm_interf_group = + usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, + names, THIS_MODULE); +- if (IS_ERR(ncm_interf_group)) ++ if (IS_ERR(ncm_interf_group)) { ++ ncm_free_inst(&opts->func_inst); + return ERR_CAST(ncm_interf_group); ++ } + opts->ncm_interf_group = ncm_interf_group; + +- ret = &opts->func_inst; +- retain_and_null_ptr(opts); +- return ret; ++ return &opts->func_inst; + } + + static void ncm_free(struct usb_function *f) + { +- struct f_ncm_opts *opts = func_to_ncm_opts(f); ++ struct f_ncm *ncm; ++ struct f_ncm_opts *opts; + +- scoped_guard(mutex, &opts->lock) +- opts->refcnt--; +- kfree(func_to_ncm(f)); ++ ncm = func_to_ncm(f); ++ opts = container_of(f->fi, struct f_ncm_opts, func_inst); ++ kfree(ncm); ++ mutex_lock(&opts->lock); ++ opts->refcnt--; ++ mutex_unlock(&opts->lock); + } + + static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) +@@ -1742,15 +1736,13 @@ static void ncm_unbind(struct usb_config + + kfree(ncm->notify_req->buf); + usb_ep_free_request(ncm->notify, ncm->notify_req); +- +- ncm->port.ioport = NULL; +- gether_cleanup(netdev_priv(ncm->netdev)); + } + + static struct usb_function *ncm_alloc(struct usb_function_instance *fi) + { + struct f_ncm *ncm; + struct f_ncm_opts *opts; ++ int status; + + /* allocate and initialize one new instance */ + ncm = kzalloc(sizeof(*ncm), GFP_KERNEL); +@@ -1758,12 +1750,22 @@ static struct usb_function *ncm_alloc(st + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_ncm_opts, func_inst); ++ mutex_lock(&opts->lock); ++ opts->refcnt++; + +- scoped_guard(mutex, &opts->lock) +- opts->refcnt++; ++ /* export host's Ethernet address in CDC format */ ++ status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr, ++ sizeof(ncm->ethaddr)); ++ if (status < 12) { /* strlen("01234567890a") */ ++ kfree(ncm); ++ mutex_unlock(&opts->lock); ++ return ERR_PTR(-EINVAL); ++ } + + spin_lock_init(&ncm->lock); + ncm_reset_values(ncm); ++ ncm->port.ioport = netdev_priv(opts->net); ++ mutex_unlock(&opts->lock); + ncm->port.is_fixed = true; + ncm->port.supports_multi_frame = true; + +--- a/drivers/usb/gadget/function/u_ncm.h ++++ b/drivers/usb/gadget/function/u_ncm.h +@@ -15,13 +15,11 @@ + + #include + +-#include "u_ether.h" +- + struct f_ncm_opts { + struct usb_function_instance func_inst; + struct net_device *net; ++ bool bound; + +- struct gether_opts net_opts; + struct config_group *ncm_interf_group; + struct usb_os_desc ncm_os_desc; + char ncm_ext_compat_id[16]; diff --git a/queue-6.18/revert-usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch b/queue-6.18/revert-usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch new file mode 100644 index 0000000000..5a002a7165 --- /dev/null +++ b/queue-6.18/revert-usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch @@ -0,0 +1,155 @@ +From 11199720fac2debbe718aec11e026ab3330dc80d Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Mon, 9 Mar 2026 20:04:46 +0800 +Subject: Revert "usb: gadget: f_ncm: Fix atomic context locking issue" + +From: Kuen-Han Tsai + +commit 11199720fac2debbe718aec11e026ab3330dc80d upstream. + +This reverts commit 0d6c8144ca4d93253de952a5ea0028c19ed7ab68. + +This commit is being reverted as part of a series-wide revert. + +By deferring the net_device allocation to the bind() phase, a single +function instance will spawn multiple network devices if it is symlinked +to multiple USB configurations. + +This causes regressions for userspace tools (like the postmarketOS DHCP +daemon) that rely on reading the interface name (e.g., "usb0") from +configfs. Currently, configfs returns the template "usb%d", causing the +userspace network setup to fail. + +Crucially, because this patch breaks the 1:1 mapping between the +function instance and the network device, this naming issue cannot +simply be patched. Configfs only exposes a single 'ifname' attribute per +instance, making it impossible to accurately report the actual interface +name when multiple underlying network devices can exist for that single +instance. + +All configurations tied to the same function instance are meant to share +a single network device. Revert this change to restore the 1:1 mapping +by allocating the network device at the instance level (alloc_inst). + +Reported-by: David Heidelberg +Closes: https://lore.kernel.org/linux-usb/70b558ea-a12e-4170-9b8e-c951131249af@ixit.cz/ +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-1-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_ncm.c | 29 ++++++++++++++----------- + drivers/usb/gadget/function/u_ether_configfs.h | 11 ++++++++- + drivers/usb/gadget/function/u_ncm.h | 1 + 3 files changed, 28 insertions(+), 13 deletions(-) + +--- a/drivers/usb/gadget/function/f_ncm.c ++++ b/drivers/usb/gadget/function/f_ncm.c +@@ -58,7 +58,6 @@ struct f_ncm { + u8 notify_state; + atomic_t notify_count; + bool is_open; +- bool is_connected; + + const struct ndp_parser_opts *parser_opts; + bool is_crc; +@@ -865,6 +864,7 @@ invalid: + static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + { + struct f_ncm *ncm = func_to_ncm(f); ++ struct f_ncm_opts *opts = func_to_ncm_opts(f); + struct usb_composite_dev *cdev = f->config->cdev; + + /* Control interface has only altsetting 0 */ +@@ -887,12 +887,13 @@ static int ncm_set_alt(struct usb_functi + if (alt > 1) + goto fail; + +- if (ncm->is_connected) { +- DBG(cdev, "reset ncm\n"); +- ncm->is_connected = false; +- gether_disconnect(&ncm->port); +- ncm_reset_values(ncm); +- } ++ scoped_guard(mutex, &opts->lock) ++ if (opts->net) { ++ DBG(cdev, "reset ncm\n"); ++ opts->net = NULL; ++ gether_disconnect(&ncm->port); ++ ncm_reset_values(ncm); ++ } + + /* + * CDC Network only sends data in non-default altsettings. +@@ -925,7 +926,8 @@ static int ncm_set_alt(struct usb_functi + net = gether_connect(&ncm->port); + if (IS_ERR(net)) + return PTR_ERR(net); +- ncm->is_connected = true; ++ scoped_guard(mutex, &opts->lock) ++ opts->net = net; + } + + spin_lock(&ncm->lock); +@@ -1372,14 +1374,16 @@ err: + static void ncm_disable(struct usb_function *f) + { + struct f_ncm *ncm = func_to_ncm(f); ++ struct f_ncm_opts *opts = func_to_ncm_opts(f); + struct usb_composite_dev *cdev = f->config->cdev; + + DBG(cdev, "ncm deactivated\n"); + +- if (ncm->is_connected) { +- ncm->is_connected = false; +- gether_disconnect(&ncm->port); +- } ++ scoped_guard(mutex, &opts->lock) ++ if (opts->net) { ++ opts->net = NULL; ++ gether_disconnect(&ncm->port); ++ } + + if (ncm->notify->enabled) { + usb_ep_disable(ncm->notify); +@@ -1683,6 +1687,7 @@ static struct usb_function_instance *ncm + if (!opts) + return ERR_PTR(-ENOMEM); + ++ opts->net = NULL; + opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; + gether_setup_opts_default(&opts->net_opts, "usb"); + +--- a/drivers/usb/gadget/function/u_ether_configfs.h ++++ b/drivers/usb/gadget/function/u_ether_configfs.h +@@ -326,9 +326,18 @@ out: \ + char *page) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ ++ const char *name; \ + \ + guard(mutex)(&opts->lock); \ +- return sysfs_emit(page, "%s\n", opts->net_opts.name); \ ++ rtnl_lock(); \ ++ if (opts->net_opts.ifname_set) \ ++ name = opts->net_opts.name; \ ++ else if (opts->net) \ ++ name = netdev_name(opts->net); \ ++ else \ ++ name = "(inactive net_device)"; \ ++ rtnl_unlock(); \ ++ return sysfs_emit(page, "%s\n", name); \ + } \ + \ + static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ +--- a/drivers/usb/gadget/function/u_ncm.h ++++ b/drivers/usb/gadget/function/u_ncm.h +@@ -19,6 +19,7 @@ + + struct f_ncm_opts { + struct usb_function_instance func_inst; ++ struct net_device *net; + + struct gether_opts net_opts; + struct config_group *ncm_interf_group; diff --git a/queue-6.18/revert-usb-gadget-u_ether-add-auto-cleanup-helper-for-freeing-net_device.patch b/queue-6.18/revert-usb-gadget-u_ether-add-auto-cleanup-helper-for-freeing-net_device.patch new file mode 100644 index 0000000000..103b5423a1 --- /dev/null +++ b/queue-6.18/revert-usb-gadget-u_ether-add-auto-cleanup-helper-for-freeing-net_device.patch @@ -0,0 +1,80 @@ +From 46662d3a1ad40282ba9f753cccc6f909ec4468cc Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Mon, 9 Mar 2026 20:04:49 +0800 +Subject: Revert "usb: gadget: u_ether: Add auto-cleanup helper for freeing net_device" + +From: Kuen-Han Tsai + +commit 46662d3a1ad40282ba9f753cccc6f909ec4468cc upstream. + +This reverts commit 0c0981126b99288ed354d3d414c8a5fd42ac9e25. + +This commit is being reverted as part of a series-wide revert. + +By deferring the net_device allocation to the bind() phase, a single +function instance will spawn multiple network devices if it is symlinked +to multiple USB configurations. + +This causes regressions for userspace tools (like the postmarketOS DHCP +daemon) that rely on reading the interface name (e.g., "usb0") from +configfs. Currently, configfs returns the template "usb%d", causing the +userspace network setup to fail. + +Crucially, because this patch breaks the 1:1 mapping between the +function instance and the network device, this naming issue cannot +simply be patched. Configfs only exposes a single 'ifname' attribute per +instance, making it impossible to accurately report the actual interface +name when multiple underlying network devices can exist for that single +instance. + +All configurations tied to the same function instance are meant to share +a single network device. Revert this change to restore the 1:1 mapping +by allocating the network device at the instance level (alloc_inst). + +Reported-by: David Heidelberg +Closes: https://lore.kernel.org/linux-usb/70b558ea-a12e-4170-9b8e-c951131249af@ixit.cz/ +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-4-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/u_ether.c | 15 --------------- + drivers/usb/gadget/function/u_ether.h | 2 -- + 2 files changed, 17 deletions(-) + +--- a/drivers/usb/gadget/function/u_ether.c ++++ b/drivers/usb/gadget/function/u_ether.c +@@ -1125,21 +1125,6 @@ void gether_cleanup(struct eth_dev *dev) + } + EXPORT_SYMBOL_GPL(gether_cleanup); + +-void gether_unregister_free_netdev(struct net_device *net) +-{ +- if (!net) +- return; +- +- struct eth_dev *dev = netdev_priv(net); +- +- if (net->reg_state == NETREG_REGISTERED) { +- unregister_netdev(net); +- flush_work(&dev->work); +- } +- free_netdev(net); +-} +-EXPORT_SYMBOL_GPL(gether_unregister_free_netdev); +- + /** + * gether_connect - notify network layer that USB link is active + * @link: the USB link, set up with endpoints, descriptors matching +--- a/drivers/usb/gadget/function/u_ether.h ++++ b/drivers/usb/gadget/function/u_ether.h +@@ -283,8 +283,6 @@ int gether_get_ifname(struct net_device + int gether_set_ifname(struct net_device *net, const char *name, int len); + + void gether_cleanup(struct eth_dev *dev); +-void gether_unregister_free_netdev(struct net_device *net); +-DEFINE_FREE(free_gether_netdev, struct net_device *, gether_unregister_free_netdev(_T)); + + void gether_setup_opts_default(struct gether_opts *opts, const char *name); + void gether_apply_opts(struct net_device *net, struct gether_opts *opts); diff --git a/queue-6.18/revert-usb-gadget-u_ether-add-gether_opts-for-config-caching.patch b/queue-6.18/revert-usb-gadget-u_ether-add-gether_opts-for-config-caching.patch new file mode 100644 index 0000000000..8249c2a7b9 --- /dev/null +++ b/queue-6.18/revert-usb-gadget-u_ether-add-gether_opts-for-config-caching.patch @@ -0,0 +1,319 @@ +From 3131c1aff7cdffb96239f06f98e16188cbc2083f Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Mon, 9 Mar 2026 20:04:51 +0800 +Subject: Revert "usb: gadget: u_ether: add gether_opts for config caching" + +From: Kuen-Han Tsai + +commit 3131c1aff7cdffb96239f06f98e16188cbc2083f upstream. + +This reverts commit e065c6a7e46c2ee9c677fdbf50035323d2de1215. + +This commit is being reverted as part of a series-wide revert. + +By deferring the net_device allocation to the bind() phase, a single +function instance will spawn multiple network devices if it is symlinked +to multiple USB configurations. + +This causes regressions for userspace tools (like the postmarketOS DHCP +daemon) that rely on reading the interface name (e.g., "usb0") from +configfs. Currently, configfs returns the template "usb%d", causing the +userspace network setup to fail. + +Crucially, because this patch breaks the 1:1 mapping between the +function instance and the network device, this naming issue cannot +simply be patched. Configfs only exposes a single 'ifname' attribute per +instance, making it impossible to accurately report the actual interface +name when multiple underlying network devices can exist for that single +instance. + +All configurations tied to the same function instance are meant to share +a single network device. Revert this change to restore the 1:1 mapping +by allocating the network device at the instance level (alloc_inst). + +Reported-by: David Heidelberg +Closes: https://lore.kernel.org/linux-usb/70b558ea-a12e-4170-9b8e-c951131249af@ixit.cz/ +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-6-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/u_ether.c | 30 ---- + drivers/usb/gadget/function/u_ether.h | 28 --- + drivers/usb/gadget/function/u_ether_configfs.h | 176 ------------------------- + 3 files changed, 234 deletions(-) + +--- a/drivers/usb/gadget/function/u_ether.c ++++ b/drivers/usb/gadget/function/u_ether.c +@@ -1039,36 +1039,6 @@ int gether_set_ifname(struct net_device + } + EXPORT_SYMBOL_GPL(gether_set_ifname); + +-void gether_setup_opts_default(struct gether_opts *opts, const char *name) +-{ +- opts->qmult = QMULT_DEFAULT; +- snprintf(opts->name, sizeof(opts->name), "%s%%d", name); +- eth_random_addr(opts->dev_mac); +- opts->addr_assign_type = NET_ADDR_RANDOM; +- eth_random_addr(opts->host_mac); +-} +-EXPORT_SYMBOL_GPL(gether_setup_opts_default); +- +-void gether_apply_opts(struct net_device *net, struct gether_opts *opts) +-{ +- struct eth_dev *dev = netdev_priv(net); +- +- dev->qmult = opts->qmult; +- +- if (opts->ifname_set) { +- strscpy(net->name, opts->name, sizeof(net->name)); +- dev->ifname_set = true; +- } +- +- memcpy(dev->host_mac, opts->host_mac, sizeof(dev->host_mac)); +- +- if (opts->addr_assign_type == NET_ADDR_SET) { +- memcpy(dev->dev_mac, opts->dev_mac, sizeof(dev->dev_mac)); +- net->addr_assign_type = opts->addr_assign_type; +- } +-} +-EXPORT_SYMBOL_GPL(gether_apply_opts); +- + void gether_suspend(struct gether *link) + { + struct eth_dev *dev = link->ioport; +--- a/drivers/usb/gadget/function/u_ether.h ++++ b/drivers/usb/gadget/function/u_ether.h +@@ -38,31 +38,6 @@ + + struct eth_dev; + +-/** +- * struct gether_opts - Options for Ethernet gadget function instances +- * @name: Pattern for the network interface name (e.g., "usb%d"). +- * Used to generate the net device name. +- * @qmult: Queue length multiplier for high/super speed. +- * @host_mac: The MAC address to be used by the host side. +- * @dev_mac: The MAC address to be used by the device side. +- * @ifname_set: True if the interface name pattern has been set by userspace. +- * @addr_assign_type: The method used for assigning the device MAC address +- * (e.g., NET_ADDR_RANDOM, NET_ADDR_SET). +- * +- * This structure caches network-related settings provided through configfs +- * before the net_device is fully instantiated. This allows for early +- * configuration while deferring net_device allocation until the function +- * is bound. +- */ +-struct gether_opts { +- char name[IFNAMSIZ]; +- unsigned int qmult; +- u8 host_mac[ETH_ALEN]; +- u8 dev_mac[ETH_ALEN]; +- bool ifname_set; +- unsigned char addr_assign_type; +-}; +- + /* + * This represents the USB side of an "ethernet" link, managed by a USB + * function which provides control and (maybe) framing. Two functions +@@ -284,9 +259,6 @@ int gether_set_ifname(struct net_device + + void gether_cleanup(struct eth_dev *dev); + +-void gether_setup_opts_default(struct gether_opts *opts, const char *name); +-void gether_apply_opts(struct net_device *net, struct gether_opts *opts); +- + void gether_suspend(struct gether *link); + void gether_resume(struct gether *link); + +--- a/drivers/usb/gadget/function/u_ether_configfs.h ++++ b/drivers/usb/gadget/function/u_ether_configfs.h +@@ -13,12 +13,6 @@ + #ifndef __U_ETHER_CONFIGFS_H + #define __U_ETHER_CONFIGFS_H + +-#include +-#include +-#include +-#include +-#include +- + #define USB_ETHERNET_CONFIGFS_ITEM(_f_) \ + static void _f_##_attr_release(struct config_item *item) \ + { \ +@@ -203,174 +197,4 @@ out: \ + \ + CONFIGFS_ATTR(_f_##_opts_, _n_) + +-#define USB_ETHER_OPTS_ITEM(_f_) \ +- static void _f_##_attr_release(struct config_item *item) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- \ +- usb_put_function_instance(&opts->func_inst); \ +- } \ +- \ +- static struct configfs_item_operations _f_##_item_ops = { \ +- .release = _f_##_attr_release, \ +- } +- +-#define USB_ETHER_OPTS_ATTR_DEV_ADDR(_f_) \ +- static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \ +- char *page) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- \ +- guard(mutex)(&opts->lock); \ +- return sysfs_emit(page, "%pM\n", opts->net_opts.dev_mac); \ +- } \ +- \ +- static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \ +- const char *page, size_t len) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- u8 new_addr[ETH_ALEN]; \ +- const char *p = page; \ +- \ +- guard(mutex)(&opts->lock); \ +- if (opts->refcnt) \ +- return -EBUSY; \ +- \ +- for (int i = 0; i < ETH_ALEN; i++) { \ +- unsigned char num; \ +- if ((*p == '.') || (*p == ':')) \ +- p++; \ +- num = hex_to_bin(*p++) << 4; \ +- num |= hex_to_bin(*p++); \ +- new_addr[i] = num; \ +- } \ +- if (!is_valid_ether_addr(new_addr)) \ +- return -EINVAL; \ +- memcpy(opts->net_opts.dev_mac, new_addr, ETH_ALEN); \ +- opts->net_opts.addr_assign_type = NET_ADDR_SET; \ +- return len; \ +- } \ +- \ +- CONFIGFS_ATTR(_f_##_opts_, dev_addr) +- +-#define USB_ETHER_OPTS_ATTR_HOST_ADDR(_f_) \ +- static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \ +- char *page) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- \ +- guard(mutex)(&opts->lock); \ +- return sysfs_emit(page, "%pM\n", opts->net_opts.host_mac); \ +- } \ +- \ +- static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \ +- const char *page, size_t len) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- u8 new_addr[ETH_ALEN]; \ +- const char *p = page; \ +- \ +- guard(mutex)(&opts->lock); \ +- if (opts->refcnt) \ +- return -EBUSY; \ +- \ +- for (int i = 0; i < ETH_ALEN; i++) { \ +- unsigned char num; \ +- if ((*p == '.') || (*p == ':')) \ +- p++; \ +- num = hex_to_bin(*p++) << 4; \ +- num |= hex_to_bin(*p++); \ +- new_addr[i] = num; \ +- } \ +- if (!is_valid_ether_addr(new_addr)) \ +- return -EINVAL; \ +- memcpy(opts->net_opts.host_mac, new_addr, ETH_ALEN); \ +- return len; \ +- } \ +- \ +- CONFIGFS_ATTR(_f_##_opts_, host_addr) +- +-#define USB_ETHER_OPTS_ATTR_QMULT(_f_) \ +- static ssize_t _f_##_opts_qmult_show(struct config_item *item, \ +- char *page) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- \ +- guard(mutex)(&opts->lock); \ +- return sysfs_emit(page, "%u\n", opts->net_opts.qmult); \ +- } \ +- \ +- static ssize_t _f_##_opts_qmult_store(struct config_item *item, \ +- const char *page, size_t len) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- u32 val; \ +- int ret; \ +- \ +- guard(mutex)(&opts->lock); \ +- if (opts->refcnt) \ +- return -EBUSY; \ +- \ +- ret = kstrtou32(page, 0, &val); \ +- if (ret) \ +- return ret; \ +- \ +- opts->net_opts.qmult = val; \ +- return len; \ +- } \ +- \ +- CONFIGFS_ATTR(_f_##_opts_, qmult) +- +-#define USB_ETHER_OPTS_ATTR_IFNAME(_f_) \ +- static ssize_t _f_##_opts_ifname_show(struct config_item *item, \ +- char *page) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- const char *name; \ +- \ +- guard(mutex)(&opts->lock); \ +- rtnl_lock(); \ +- if (opts->net_opts.ifname_set) \ +- name = opts->net_opts.name; \ +- else if (opts->net) \ +- name = netdev_name(opts->net); \ +- else \ +- name = "(inactive net_device)"; \ +- rtnl_unlock(); \ +- return sysfs_emit(page, "%s\n", name); \ +- } \ +- \ +- static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ +- const char *page, size_t len) \ +- { \ +- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- char tmp[IFNAMSIZ]; \ +- const char *p; \ +- size_t c_len = len; \ +- \ +- if (c_len > 0 && page[c_len - 1] == '\n') \ +- c_len--; \ +- \ +- if (c_len >= sizeof(tmp)) \ +- return -E2BIG; \ +- \ +- strscpy(tmp, page, c_len + 1); \ +- if (!dev_valid_name(tmp)) \ +- return -EINVAL; \ +- \ +- /* Require exactly one %d */ \ +- p = strchr(tmp, '%'); \ +- if (!p || p[1] != 'd' || strchr(p + 2, '%')) \ +- return -EINVAL; \ +- \ +- guard(mutex)(&opts->lock); \ +- if (opts->refcnt) \ +- return -EBUSY; \ +- strscpy(opts->net_opts.name, tmp, sizeof(opts->net_opts.name)); \ +- opts->net_opts.ifname_set = true; \ +- return len; \ +- } \ +- \ +- CONFIGFS_ATTR(_f_##_opts_, ifname) +- + #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/queue-6.18/revert-usb-legacy-ncm-fix-npe-in-gncm_bind.patch b/queue-6.18/revert-usb-legacy-ncm-fix-npe-in-gncm_bind.patch new file mode 100644 index 0000000000..ce7414ed41 --- /dev/null +++ b/queue-6.18/revert-usb-legacy-ncm-fix-npe-in-gncm_bind.patch @@ -0,0 +1,89 @@ +From f2524c0e6ff0a5f72f1e1a32441c69d3b56430c4 Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Mon, 9 Mar 2026 20:04:47 +0800 +Subject: Revert "usb: legacy: ncm: Fix NPE in gncm_bind" + +From: Kuen-Han Tsai + +commit f2524c0e6ff0a5f72f1e1a32441c69d3b56430c4 upstream. + +This reverts commit fde0634ad9856b3943a2d1a8cc8de174a63ac840. + +This commit is being reverted as part of a series-wide revert. + +By deferring the net_device allocation to the bind() phase, a single +function instance will spawn multiple network devices if it is symlinked +to multiple USB configurations. + +This causes regressions for userspace tools (like the postmarketOS DHCP +daemon) that rely on reading the interface name (e.g., "usb0") from +configfs. Currently, configfs returns the template "usb%d", causing the +userspace network setup to fail. + +Crucially, because this patch breaks the 1:1 mapping between the +function instance and the network device, this naming issue cannot +simply be patched. Configfs only exposes a single 'ifname' attribute per +instance, making it impossible to accurately report the actual interface +name when multiple underlying network devices can exist for that single +instance. + +All configurations tied to the same function instance are meant to share +a single network device. Revert this change to restore the 1:1 mapping +by allocating the network device at the instance level (alloc_inst). + +Reported-by: David Heidelberg +Closes: https://lore.kernel.org/linux-usb/70b558ea-a12e-4170-9b8e-c951131249af@ixit.cz/ +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-2-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/legacy/ncm.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c +index e8d565534053..0f1b45e3abd1 100644 +--- a/drivers/usb/gadget/legacy/ncm.c ++++ b/drivers/usb/gadget/legacy/ncm.c +@@ -15,10 +15,8 @@ + /* #define DEBUG */ + /* #define VERBOSE_DEBUG */ + +-#include + #include + #include +-#include + #include + + #include "u_ether.h" +@@ -131,7 +129,6 @@ static int gncm_bind(struct usb_composite_dev *cdev) + struct usb_gadget *gadget = cdev->gadget; + struct f_ncm_opts *ncm_opts; + int status; +- u8 mac[ETH_ALEN]; + + f_ncm_inst = usb_get_function_instance("ncm"); + if (IS_ERR(f_ncm_inst)) +@@ -139,15 +136,11 @@ static int gncm_bind(struct usb_composite_dev *cdev) + + ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst); + +- ncm_opts->net_opts.qmult = qmult; +- if (host_addr && mac_pton(host_addr, mac)) { +- memcpy(&ncm_opts->net_opts.host_mac, mac, ETH_ALEN); ++ gether_set_qmult(ncm_opts->net, qmult); ++ if (!gether_set_host_addr(ncm_opts->net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); +- } +- if (dev_addr && mac_pton(dev_addr, mac)) { +- memcpy(&ncm_opts->net_opts.dev_mac, mac, ETH_ALEN); ++ if (!gether_set_dev_addr(ncm_opts->net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); +- } + + /* Allocate string descriptor numbers ... note that string + * contents can be overridden by the composite_dev glue. +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index e5501c040b..3c60999982 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -117,3 +117,39 @@ rust_binder-avoid-reading-the-written-value-in-offsets-array.patch rust_binder-call-set_notification_done-without-proc-lock.patch rust-kbuild-allow-unused_features.patch rust-str-make-nullterminatedformatter-public.patch +ata-libata-core-add-bridge_ok-quirk-for-qemu-drives.patch +asoc-amd-yc-add-dmi-quirk-for-asus-expertbook-pm1503cda.patch +kvm-arm64-fix-protected-mode-handling-of-pages-larger-than-4kb.patch +kvm-x86-introduce-kvm_x86_quirk_vmcs12_allow_freeze_in_smm.patch +kvm-svm-initialize-avic-vmcb-fields-if-avic-is-enabled-with-in-kernel-apic.patch +kvm-arm64-pkvm-fallback-to-level-3-mapping-on-host-stage-2-fault.patch +usb-add-quirk_no_bos-for-video-capture-several-devices.patch +usb-core-quirks-add-huawei-me906s-device-to-wakeup-quirk.patch +usb-ezcap401-needs-usb_quirk_no_bos-to-function-on-10gbs-usb-speed.patch +usb-xhci-fix-memory-leak-in-xhci_disable_slot.patch +usb-xhci-prevent-interrupt-storm-on-host-controller-error-hce.patch +usb-yurex-fix-race-in-probe.patch +usb-dwc3-pci-add-support-for-the-intel-nova-lake-h.patch +usb-misc-uss720-properly-clean-up-reference-in-uss720_probe.patch +usb-core-don-t-power-off-roothub-phys-if-phy_set_mode-fails.patch +usb-cdc-acm-restore-cap_brk-functionnality-to-ch343.patch +usb-roles-get-usb-role-switch-from-parent-only-for-usb-b-connector.patch +usb-typec-altmode-displayport-set-displayport-signaling-rate-in-configure-message.patch +usb-usbcore-introduce-usb_bulk_msg_killable.patch +usb-usbtmc-use-usb_bulk_msg_killable-with-user-specified-timeouts.patch +usb-core-limit-the-length-of-unkillable-synchronous-timeouts.patch +usb-class-cdc-wdm-fix-reordering-issue-in-read-code-path.patch +usb-renesas_usbhs-fix-use-after-free-in-isr-during-device-removal.patch +usb-gadget-f_hid-fix-superspeed-descriptors.patch +usb-mdc800-handle-signal-and-read-racing.patch +usb-gadget-uvc-fix-interval_duration-calculation.patch +usb-image-mdc800-kill-download-urb-on-timeout.patch +usb-gadget-f_tcm-fix-null-pointer-dereferences-in-nexus-handling.patch +usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch +usb-legacy-ncm-fix-npe-in-gncm_bind.patch +revert-usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch +revert-usb-legacy-ncm-fix-npe-in-gncm_bind.patch +revert-usb-gadget-u_ether-add-auto-cleanup-helper-for-freeing-net_device.patch +revert-usb-gadget-f_ncm-align-net_device-lifecycle-with-bind-unbind.patch +revert-usb-gadget-u_ether-add-gether_opts-for-config-caching.patch +usb-gadget-f_ncm-fix-net_device-lifecycle-with-device_move.patch diff --git a/queue-6.18/usb-add-quirk_no_bos-for-video-capture-several-devices.patch b/queue-6.18/usb-add-quirk_no_bos-for-video-capture-several-devices.patch new file mode 100644 index 0000000000..3293ff9ca4 --- /dev/null +++ b/queue-6.18/usb-add-quirk_no_bos-for-video-capture-several-devices.patch @@ -0,0 +1,59 @@ +From 93cd0d664661f58f7e7bed7373714ab2ace41734 Mon Sep 17 00:00:00 2001 +From: A1RM4X +Date: Wed, 4 Feb 2026 14:26:48 -0500 +Subject: USB: add QUIRK_NO_BOS for video capture several devices + +From: A1RM4X + +commit 93cd0d664661f58f7e7bed7373714ab2ace41734 upstream. + +Several USB capture devices also need the USB_QUIRK_NO_BOS set for them +to work properly, odds are they are all the same chip inside, just +different vendor/product ids. + +This fixes up: + - ASUS TUF 4K PRO + - Avermedia Live Gamer Ultra 2.1 (GC553G2) + - UGREEN 35871 +to now run at full speed (10 Gbps/4K 60 fps mode.) + +Link: https://lore.kernel.org/r/CACy+XB-f-51xGpNQFCSm5pE_momTQLu=BaZggHYU1DiDmFX=ug@mail.gmail.com +Cc: stable +Signed-off-by: A1RM4X +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/quirks.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -377,6 +377,9 @@ static const struct usb_device_id usb_qu + /* SanDisk Extreme 55AE */ + { USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* Avermedia Live Gamer Ultra 2.1 (GC553G2) - BOS descriptor fetch hangs at SuperSpeed Plus */ ++ { USB_DEVICE(0x07ca, 0x2553), .driver_info = USB_QUIRK_NO_BOS }, ++ + /* Realforce 87U Keyboard */ + { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM }, + +@@ -437,6 +440,9 @@ static const struct usb_device_id usb_qu + { USB_DEVICE(0x0b05, 0x17e0), .driver_info = + USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + ++ /* ASUS TUF 4K PRO - BOS descriptor fetch hangs at SuperSpeed Plus */ ++ { USB_DEVICE(0x0b05, 0x1ab9), .driver_info = USB_QUIRK_NO_BOS }, ++ + /* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/ + { USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + +@@ -565,6 +571,9 @@ static const struct usb_device_id usb_qu + + { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */ ++ { USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS }, ++ + /* APTIV AUTOMOTIVE HUB */ + { USB_DEVICE(0x2c48, 0x0132), .driver_info = + USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT }, diff --git a/queue-6.18/usb-cdc-acm-restore-cap_brk-functionnality-to-ch343.patch b/queue-6.18/usb-cdc-acm-restore-cap_brk-functionnality-to-ch343.patch new file mode 100644 index 0000000000..ce767333b8 --- /dev/null +++ b/queue-6.18/usb-cdc-acm-restore-cap_brk-functionnality-to-ch343.patch @@ -0,0 +1,62 @@ +From 14ae24cba291bddfdc296bbcbfd00cd09d0498ef Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Sun, 1 Mar 2026 12:44:40 +0000 +Subject: usb: cdc-acm: Restore CAP_BRK functionnality to CH343 + +From: Marc Zyngier + +commit 14ae24cba291bddfdc296bbcbfd00cd09d0498ef upstream. + +The CH343 USB/serial adapter is as buggy as it is popular (very). +One of its quirks is that despite being capable of signalling a +BREAK condition, it doesn't advertise it. + +This used to work nonetheless until 66aad7d8d3ec5 ("usb: cdc-acm: +return correct error code on unsupported break") applied some +reasonable restrictions, preventing breaks from being emitted on +devices that do not advertise CAP_BRK. + +Add a quirk for this particular device, so that breaks can still +be produced on some of my machines attached to my console server. + +Fixes: 66aad7d8d3ec5 ("usb: cdc-acm: return correct error code on unsupported break") +Signed-off-by: Marc Zyngier +Cc: stable +Cc: Oliver Neukum +Cc: Greg Kroah-Hartman +Acked-by: Oliver Neukum +Link: https://patch.msgid.link/20260301124440.1192752-1-maz@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/cdc-acm.c | 5 +++++ + drivers/usb/class/cdc-acm.h | 1 + + 2 files changed, 6 insertions(+) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1379,6 +1379,8 @@ made_compressed_probe: + acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities; + if (quirks & NO_CAP_LINE) + acm->ctrl_caps &= ~USB_CDC_CAP_LINE; ++ if (quirks & MISSING_CAP_BRK) ++ acm->ctrl_caps |= USB_CDC_CAP_BRK; + acm->ctrlsize = ctrlsize; + acm->readsize = readsize; + acm->rx_buflimit = num_rx_buf; +@@ -2002,6 +2004,9 @@ static const struct usb_device_id acm_id + .driver_info = IGNORE_DEVICE, + }, + ++ /* CH343 supports CAP_BRK, but doesn't advertise it */ ++ { USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, }, ++ + /* control interfaces without any protocol set */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_PROTO_NONE) }, +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -113,3 +113,4 @@ struct acm { + #define CLEAR_HALT_CONDITIONS BIT(5) + #define SEND_ZERO_PACKET BIT(6) + #define DISABLE_ECHO BIT(7) ++#define MISSING_CAP_BRK BIT(8) diff --git a/queue-6.18/usb-class-cdc-wdm-fix-reordering-issue-in-read-code-path.patch b/queue-6.18/usb-class-cdc-wdm-fix-reordering-issue-in-read-code-path.patch new file mode 100644 index 0000000000..63c6ae265f --- /dev/null +++ b/queue-6.18/usb-class-cdc-wdm-fix-reordering-issue-in-read-code-path.patch @@ -0,0 +1,50 @@ +From 8df672bfe3ec2268c2636584202755898e547173 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Wed, 4 Mar 2026 14:01:12 +0100 +Subject: usb: class: cdc-wdm: fix reordering issue in read code path + +From: Oliver Neukum + +commit 8df672bfe3ec2268c2636584202755898e547173 upstream. + +Quoting the bug report: + +Due to compiler optimization or CPU out-of-order execution, the +desc->length update can be reordered before the memmove. If this +happens, wdm_read() can see the new length and call copy_to_user() on +uninitialized memory. This also violates LKMM data race rules [1]. + +Fix it by using WRITE_ONCE and memory barriers. + +Fixes: afba937e540c9 ("USB: CDC WDM driver") +Cc: stable +Signed-off-by: Oliver Neukum +Closes: https://lore.kernel.org/linux-usb/CALbr=LbrUZn_cfp7CfR-7Z5wDTHF96qeuM=3fO2m-q4cDrnC4A@mail.gmail.com/ +Reported-by: Gui-Dong Han +Reviewed-by: Gui-Dong Han +Link: https://patch.msgid.link/20260304130116.1721682-1-oneukum@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/cdc-wdm.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/class/cdc-wdm.c ++++ b/drivers/usb/class/cdc-wdm.c +@@ -225,7 +225,8 @@ static void wdm_in_callback(struct urb * + /* we may already be in overflow */ + if (!test_bit(WDM_OVERFLOW, &desc->flags)) { + memmove(desc->ubuf + desc->length, desc->inbuf, length); +- desc->length += length; ++ smp_wmb(); /* against wdm_read() */ ++ WRITE_ONCE(desc->length, desc->length + length); + } + } + skip_error: +@@ -533,6 +534,7 @@ static ssize_t wdm_read + return -ERESTARTSYS; + + cntr = READ_ONCE(desc->length); ++ smp_rmb(); /* against wdm_in_callback() */ + if (cntr == 0) { + desc->read = 0; + retry: diff --git a/queue-6.18/usb-core-don-t-power-off-roothub-phys-if-phy_set_mode-fails.patch b/queue-6.18/usb-core-don-t-power-off-roothub-phys-if-phy_set_mode-fails.patch new file mode 100644 index 0000000000..c2d62fb6e4 --- /dev/null +++ b/queue-6.18/usb-core-don-t-power-off-roothub-phys-if-phy_set_mode-fails.patch @@ -0,0 +1,50 @@ +From e293015ba76eb96ce4ebed7e3b2cb1a7d319f3e9 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Wed, 18 Feb 2026 21:21:07 +0100 +Subject: usb: core: don't power off roothub PHYs if phy_set_mode() fails + +From: Gabor Juhos + +commit e293015ba76eb96ce4ebed7e3b2cb1a7d319f3e9 upstream. + +Remove the error path from the usb_phy_roothub_set_mode() function. +The code is clearly wrong, because phy_set_mode() calls can't be +balanced with phy_power_off() calls. + +Additionally, the usb_phy_roothub_set_mode() function is called only +from usb_add_hcd() before it powers on the PHYs, so powering off those +makes no sense anyway. + +Presumably, the code is copy-pasted from the phy_power_on() function +without adjusting the error handling. + +Cc: stable@vger.kernel.org # v5.1+ +Fixes: b97a31348379 ("usb: core: comply to PHY framework") +Signed-off-by: Gabor Juhos +Reviewed-by: Miquel Raynal +Link: https://patch.msgid.link/20260218-usb-phy-poweroff-fix-v1-1-66e6831e860e@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/phy.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +--- a/drivers/usb/core/phy.c ++++ b/drivers/usb/core/phy.c +@@ -200,16 +200,10 @@ int usb_phy_roothub_set_mode(struct usb_ + list_for_each_entry(roothub_entry, head, list) { + err = phy_set_mode(roothub_entry->phy, mode); + if (err) +- goto err_out; ++ return err; + } + + return 0; +- +-err_out: +- list_for_each_entry_continue_reverse(roothub_entry, head, list) +- phy_power_off(roothub_entry->phy); +- +- return err; + } + EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode); + diff --git a/queue-6.18/usb-core-limit-the-length-of-unkillable-synchronous-timeouts.patch b/queue-6.18/usb-core-limit-the-length-of-unkillable-synchronous-timeouts.patch new file mode 100644 index 0000000000..d382a4780a --- /dev/null +++ b/queue-6.18/usb-core-limit-the-length-of-unkillable-synchronous-timeouts.patch @@ -0,0 +1,134 @@ +From 1015c27a5e1a63efae2b18a9901494474b4d1dc3 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 17 Feb 2026 22:10:32 -0500 +Subject: USB: core: Limit the length of unkillable synchronous timeouts + +From: Alan Stern + +commit 1015c27a5e1a63efae2b18a9901494474b4d1dc3 upstream. + +The usb_control_msg(), usb_bulk_msg(), and usb_interrupt_msg() APIs in +usbcore allow unlimited timeout durations. And since they use +uninterruptible waits, this leaves open the possibility of hanging a +task for an indefinitely long time, with no way to kill it short of +unplugging the target device. + +To prevent this sort of problem, enforce a maximum limit on the length +of these unkillable timeouts. The limit chosen here, somewhat +arbitrarily, is 60 seconds. On many systems (although not all) this +is short enough to avoid triggering the kernel's hung-task detector. + +In addition, clear up the ambiguity of negative timeout values by +treating them the same as 0, i.e., using the maximum allowed timeout. + +Signed-off-by: Alan Stern +Link: https://lore.kernel.org/linux-usb/3acfe838-6334-4f6d-be7c-4bb01704b33d@rowland.harvard.edu/ +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +CC: stable@vger.kernel.org +Link: https://patch.msgid.link/15fc9773-a007-47b0-a703-df89a8cf83dd@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/message.c | 27 +++++++++++++-------------- + include/linux/usb.h | 3 +++ + 2 files changed, 16 insertions(+), 14 deletions(-) + +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -45,6 +45,8 @@ static void usb_api_blocking_completion( + * Starts urb and waits for completion or timeout. + * Whether or not the wait is killable depends on the flag passed in. + * For example, compare usb_bulk_msg() and usb_bulk_msg_killable(). ++ * ++ * For non-killable waits, we enforce a maximum limit on the timeout value. + */ + static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length, + bool killable) +@@ -61,7 +63,9 @@ static int usb_start_wait_urb(struct urb + if (unlikely(retval)) + goto out; + +- expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; ++ if (!killable && (timeout <= 0 || timeout > USB_MAX_SYNCHRONOUS_TIMEOUT)) ++ timeout = USB_MAX_SYNCHRONOUS_TIMEOUT; ++ expire = (timeout > 0) ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; + if (killable) + rc = wait_for_completion_killable_timeout(&ctx.done, expire); + else +@@ -127,8 +131,7 @@ static int usb_internal_control_msg(stru + * @index: USB message index value + * @data: pointer to the data to send + * @size: length in bytes of the data to send +- * @timeout: time in msecs to wait for the message to complete before timing +- * out (if 0 the wait is forever) ++ * @timeout: time in msecs to wait for the message to complete before timing out + * + * Context: task context, might sleep. + * +@@ -183,8 +186,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg); + * @index: USB message index value + * @driver_data: pointer to the data to send + * @size: length in bytes of the data to send +- * @timeout: time in msecs to wait for the message to complete before timing +- * out (if 0 the wait is forever) ++ * @timeout: time in msecs to wait for the message to complete before timing out + * @memflags: the flags for memory allocation for buffers + * + * Context: !in_interrupt () +@@ -242,8 +244,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_send); + * @index: USB message index value + * @driver_data: pointer to the data to be filled in by the message + * @size: length in bytes of the data to be received +- * @timeout: time in msecs to wait for the message to complete before timing +- * out (if 0 the wait is forever) ++ * @timeout: time in msecs to wait for the message to complete before timing out + * @memflags: the flags for memory allocation for buffers + * + * Context: !in_interrupt () +@@ -314,8 +315,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv); + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred + * in bytes +- * @timeout: time in msecs to wait for the message to complete before +- * timing out (if 0 the wait is forever) ++ * @timeout: time in msecs to wait for the message to complete before timing out + * + * Context: task context, might sleep. + * +@@ -347,8 +347,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred + * in bytes +- * @timeout: time in msecs to wait for the message to complete before +- * timing out (if 0 the wait is forever) ++ * @timeout: time in msecs to wait for the message to complete before timing out + * + * Context: task context, might sleep. + * +@@ -408,12 +407,12 @@ EXPORT_SYMBOL_GPL(usb_bulk_msg); + * @actual_length: pointer to a location to put the actual length transferred + * in bytes + * @timeout: time in msecs to wait for the message to complete before +- * timing out (if 0 the wait is forever) ++ * timing out (if <= 0, the wait is as long as possible) + * + * Context: task context, might sleep. + * +- * This function is just like usb_blk_msg() except that it waits in a +- * killable state. ++ * This function is just like usb_blk_msg(), except that it waits in a ++ * killable state and there is no limit on the timeout length. + * + * Return: + * If successful, 0. Otherwise a negative error number. The number of actual +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1863,6 +1863,9 @@ void usb_free_noncoherent(struct usb_dev + * SYNCHRONOUS CALL SUPPORT * + *-------------------------------------------------------------------*/ + ++/* Maximum value allowed for timeout in synchronous routines below */ ++#define USB_MAX_SYNCHRONOUS_TIMEOUT 60000 /* ms */ ++ + extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, + __u8 request, __u8 requesttype, __u16 value, __u16 index, + void *data, __u16 size, int timeout); diff --git a/queue-6.18/usb-core-quirks-add-huawei-me906s-device-to-wakeup-quirk.patch b/queue-6.18/usb-core-quirks-add-huawei-me906s-device-to-wakeup-quirk.patch new file mode 100644 index 0000000000..cefd8c65e5 --- /dev/null +++ b/queue-6.18/usb-core-quirks-add-huawei-me906s-device-to-wakeup-quirk.patch @@ -0,0 +1,36 @@ +From 0326ff28d56b4fa202de36ffc8462a354f383a64 Mon Sep 17 00:00:00 2001 +From: Christoffer Sandberg +Date: Fri, 6 Mar 2026 18:28:14 +0100 +Subject: usb/core/quirks: Add Huawei ME906S-device to wakeup quirk + +From: Christoffer Sandberg + +commit 0326ff28d56b4fa202de36ffc8462a354f383a64 upstream. + +Similar to other Huawei LTE modules using this quirk, this version with +another vid/pid suffers from spurious wakeups. + +Setting the quirk fixes the issue for this device as well. + +Cc: stable +Signed-off-by: Christoffer Sandberg +Signed-off-by: Werner Sembach +Link: https://patch.msgid.link/20260306172817.2098898-1-wse@tuxedocomputers.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 +@@ -208,6 +208,10 @@ static const struct usb_device_id usb_qu + /* HP v222w 16GB Mini USB Drive */ + { USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT }, + ++ /* Huawei 4G LTE module ME906S */ ++ { USB_DEVICE(0x03f0, 0xa31d), .driver_info = ++ USB_QUIRK_DISCONNECT_SUSPEND }, ++ + /* Creative SB Audigy 2 NX */ + { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + diff --git a/queue-6.18/usb-dwc3-pci-add-support-for-the-intel-nova-lake-h.patch b/queue-6.18/usb-dwc3-pci-add-support-for-the-intel-nova-lake-h.patch new file mode 100644 index 0000000000..683afe2d11 --- /dev/null +++ b/queue-6.18/usb-dwc3-pci-add-support-for-the-intel-nova-lake-h.patch @@ -0,0 +1,39 @@ +From 17ab4d4078e22be7fd8fd6fc710c15c085a4cb1b Mon Sep 17 00:00:00 2001 +From: Heikki Krogerus +Date: Mon, 9 Mar 2026 14:02:04 +0100 +Subject: usb: dwc3: pci: add support for the Intel Nova Lake -H + +From: Heikki Krogerus + +commit 17ab4d4078e22be7fd8fd6fc710c15c085a4cb1b upstream. + +This patch adds the necessary PCI ID for Intel Nova Lake -H +devices. + +Signed-off-by: Heikki Krogerus +Cc: stable +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260309130204.208661-1-heikki.krogerus@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/dwc3-pci.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/dwc3/dwc3-pci.c ++++ b/drivers/usb/dwc3/dwc3-pci.c +@@ -56,6 +56,7 @@ + #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e + #define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0 + #define PCI_DEVICE_ID_INTEL_RPL 0xa70e ++#define PCI_DEVICE_ID_INTEL_NVLH 0xd37f + #define PCI_DEVICE_ID_INTEL_PTLH 0xe332 + #define PCI_DEVICE_ID_INTEL_PTLH_PCH 0xe37e + #define PCI_DEVICE_ID_INTEL_PTLU 0xe432 +@@ -448,6 +449,7 @@ static const struct pci_device_id dwc3_p + { PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) }, ++ { PCI_DEVICE_DATA(INTEL, NVLH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, PTLH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, PTLH_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, PTLU, &dwc3_pci_intel_swnode) }, diff --git a/queue-6.18/usb-ezcap401-needs-usb_quirk_no_bos-to-function-on-10gbs-usb-speed.patch b/queue-6.18/usb-ezcap401-needs-usb_quirk_no_bos-to-function-on-10gbs-usb-speed.patch new file mode 100644 index 0000000000..080f24a4fe --- /dev/null +++ b/queue-6.18/usb-ezcap401-needs-usb_quirk_no_bos-to-function-on-10gbs-usb-speed.patch @@ -0,0 +1,34 @@ +From d0d9b1f4f5391e6a00cee81d73ed2e8f98446d5f Mon Sep 17 00:00:00 2001 +From: Vyacheslav Vahnenko +Date: Fri, 13 Mar 2026 15:36:38 +0300 +Subject: USB: ezcap401 needs USB_QUIRK_NO_BOS to function on 10gbs usb speed + +From: Vyacheslav Vahnenko + +commit d0d9b1f4f5391e6a00cee81d73ed2e8f98446d5f upstream. + +Add USB_QUIRK_NO_BOS for ezcap401 capture card, without it dmesg will show +"unable to get BOS descriptor or descriptor too short" and "unable to +read config index 0 descriptor/start: -71" errors and device will not +able to work at full speed at 10gbs + +Signed-off-by: Vyacheslav Vahnenko +Cc: stable +Link: https://patch.msgid.link/20260313123638.20481-1-vahnenko2003@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -588,6 +588,9 @@ static const struct usb_device_id usb_qu + /* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */ + { USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM }, + ++ /* ezcap401 - BOS descriptor fetch hangs at SuperSpeed Plus */ ++ { USB_DEVICE(0x32ed, 0x0401), .driver_info = USB_QUIRK_NO_BOS }, ++ + /* DELL USB GEN2 */ + { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME }, + diff --git a/queue-6.18/usb-gadget-f_hid-fix-superspeed-descriptors.patch b/queue-6.18/usb-gadget-f_hid-fix-superspeed-descriptors.patch new file mode 100644 index 0000000000..c1b781a64c --- /dev/null +++ b/queue-6.18/usb-gadget-f_hid-fix-superspeed-descriptors.patch @@ -0,0 +1,53 @@ +From 7f58b4148ef5d8ee0fb7d8113dcc38ff5374babc Mon Sep 17 00:00:00 2001 +From: John Keeping +Date: Fri, 27 Feb 2026 11:15:39 +0000 +Subject: usb: gadget: f_hid: fix SuperSpeed descriptors + +From: John Keeping + +commit 7f58b4148ef5d8ee0fb7d8113dcc38ff5374babc upstream. + +When adding dynamic configuration for bInterval, the value was removed +from the static SuperSpeed endpoint descriptors but was not set from the +configured value in hidg_bind(). Thus at SuperSpeed the interrupt +endpoints have bInterval as zero which is not valid per the USB +specification. + +Add the missing setting for SuperSpeed endpoints. + +Fixes: ea34925f5b2ee ("usb: gadget: hid: allow dynamic interval configuration via configfs") +Cc: stable +Signed-off-by: John Keeping +Acked-by: Peter Korsgaard +Link: https://patch.msgid.link/20260227111540.431521-1-jkeeping@inmusicbrands.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_hid.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -1207,9 +1207,11 @@ static int hidg_bind(struct usb_configur + if (!hidg->interval_user_set) { + hidg_fs_in_ep_desc.bInterval = 10; + hidg_hs_in_ep_desc.bInterval = 4; ++ hidg_ss_in_ep_desc.bInterval = 4; + } else { + hidg_fs_in_ep_desc.bInterval = hidg->interval; + hidg_hs_in_ep_desc.bInterval = hidg->interval; ++ hidg_ss_in_ep_desc.bInterval = hidg->interval; + } + + hidg_ss_out_comp_desc.wBytesPerInterval = +@@ -1239,9 +1241,11 @@ static int hidg_bind(struct usb_configur + if (!hidg->interval_user_set) { + hidg_fs_out_ep_desc.bInterval = 10; + hidg_hs_out_ep_desc.bInterval = 4; ++ hidg_ss_out_ep_desc.bInterval = 4; + } else { + hidg_fs_out_ep_desc.bInterval = hidg->interval; + hidg_hs_out_ep_desc.bInterval = hidg->interval; ++ hidg_ss_out_ep_desc.bInterval = hidg->interval; + } + status = usb_assign_descriptors(f, + hidg_fs_descriptors_intout, diff --git a/queue-6.18/usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch b/queue-6.18/usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch new file mode 100644 index 0000000000..6998c605be --- /dev/null +++ b/queue-6.18/usb-gadget-f_ncm-fix-atomic-context-locking-issue.patch @@ -0,0 +1,153 @@ +From 0d6c8144ca4d93253de952a5ea0028c19ed7ab68 Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Sat, 21 Feb 2026 22:48:16 +0800 +Subject: usb: gadget: f_ncm: Fix atomic context locking issue + +From: Kuen-Han Tsai + +commit 0d6c8144ca4d93253de952a5ea0028c19ed7ab68 upstream. + +The ncm_set_alt function was holding a mutex to protect against races +with configfs, which invokes the might-sleep function inside an atomic +context. + +Remove the struct net_device pointer from the f_ncm_opts structure to +eliminate the contention. The connection state is now managed by a new +boolean flag to preserve the use-after-free fix from +commit 6334b8e4553c ("usb: gadget: f_ncm: Fix UAF ncm object at re-bind +after usb ep transport error"). + +BUG: sleeping function called from invalid context +Call Trace: + dump_stack_lvl+0x83/0xc0 + dump_stack+0x14/0x16 + __might_resched+0x389/0x4c0 + __might_sleep+0x8e/0x100 + ... + __mutex_lock+0x6f/0x1740 + ... + ncm_set_alt+0x209/0xa40 + set_config+0x6b6/0xb40 + composite_setup+0x734/0x2b40 + ... + +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable@kernel.org +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260221-legacy-ncm-v2-2-dfb891d76507@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_ncm.c | 29 ++++++++++--------------- + drivers/usb/gadget/function/u_ether_configfs.h | 11 --------- + drivers/usb/gadget/function/u_ncm.h | 1 + 3 files changed, 13 insertions(+), 28 deletions(-) + +--- a/drivers/usb/gadget/function/f_ncm.c ++++ b/drivers/usb/gadget/function/f_ncm.c +@@ -58,6 +58,7 @@ struct f_ncm { + u8 notify_state; + atomic_t notify_count; + bool is_open; ++ bool is_connected; + + const struct ndp_parser_opts *parser_opts; + bool is_crc; +@@ -864,7 +865,6 @@ invalid: + static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + { + struct f_ncm *ncm = func_to_ncm(f); +- struct f_ncm_opts *opts = func_to_ncm_opts(f); + struct usb_composite_dev *cdev = f->config->cdev; + + /* Control interface has only altsetting 0 */ +@@ -887,13 +887,12 @@ static int ncm_set_alt(struct usb_functi + if (alt > 1) + goto fail; + +- scoped_guard(mutex, &opts->lock) +- if (opts->net) { +- DBG(cdev, "reset ncm\n"); +- opts->net = NULL; +- gether_disconnect(&ncm->port); +- ncm_reset_values(ncm); +- } ++ if (ncm->is_connected) { ++ DBG(cdev, "reset ncm\n"); ++ ncm->is_connected = false; ++ gether_disconnect(&ncm->port); ++ ncm_reset_values(ncm); ++ } + + /* + * CDC Network only sends data in non-default altsettings. +@@ -926,8 +925,7 @@ static int ncm_set_alt(struct usb_functi + net = gether_connect(&ncm->port); + if (IS_ERR(net)) + return PTR_ERR(net); +- scoped_guard(mutex, &opts->lock) +- opts->net = net; ++ ncm->is_connected = true; + } + + spin_lock(&ncm->lock); +@@ -1374,16 +1372,14 @@ err: + static void ncm_disable(struct usb_function *f) + { + struct f_ncm *ncm = func_to_ncm(f); +- struct f_ncm_opts *opts = func_to_ncm_opts(f); + struct usb_composite_dev *cdev = f->config->cdev; + + DBG(cdev, "ncm deactivated\n"); + +- scoped_guard(mutex, &opts->lock) +- if (opts->net) { +- opts->net = NULL; +- gether_disconnect(&ncm->port); +- } ++ if (ncm->is_connected) { ++ ncm->is_connected = false; ++ gether_disconnect(&ncm->port); ++ } + + if (ncm->notify->enabled) { + usb_ep_disable(ncm->notify); +@@ -1687,7 +1683,6 @@ static struct usb_function_instance *ncm + if (!opts) + return ERR_PTR(-ENOMEM); + +- opts->net = NULL; + opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; + gether_setup_opts_default(&opts->net_opts, "usb"); + +--- a/drivers/usb/gadget/function/u_ether_configfs.h ++++ b/drivers/usb/gadget/function/u_ether_configfs.h +@@ -326,18 +326,9 @@ out: \ + char *page) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ +- const char *name; \ + \ + guard(mutex)(&opts->lock); \ +- rtnl_lock(); \ +- if (opts->net_opts.ifname_set) \ +- name = opts->net_opts.name; \ +- else if (opts->net) \ +- name = netdev_name(opts->net); \ +- else \ +- name = "(inactive net_device)"; \ +- rtnl_unlock(); \ +- return sysfs_emit(page, "%s\n", name); \ ++ return sysfs_emit(page, "%s\n", opts->net_opts.name); \ + } \ + \ + static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ +--- a/drivers/usb/gadget/function/u_ncm.h ++++ b/drivers/usb/gadget/function/u_ncm.h +@@ -19,7 +19,6 @@ + + struct f_ncm_opts { + struct usb_function_instance func_inst; +- struct net_device *net; + + struct gether_opts net_opts; + struct config_group *ncm_interf_group; diff --git a/queue-6.18/usb-gadget-f_ncm-fix-net_device-lifecycle-with-device_move.patch b/queue-6.18/usb-gadget-f_ncm-fix-net_device-lifecycle-with-device_move.patch new file mode 100644 index 0000000000..15e7ba8acc --- /dev/null +++ b/queue-6.18/usb-gadget-f_ncm-fix-net_device-lifecycle-with-device_move.patch @@ -0,0 +1,208 @@ +From ec35c1969650e7cb6c8a91020e568ed46e3551b0 Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Mon, 9 Mar 2026 20:04:52 +0800 +Subject: usb: gadget: f_ncm: Fix net_device lifecycle with device_move + +From: Kuen-Han Tsai + +commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 upstream. + +The network device outlived its parent gadget device during +disconnection, resulting in dangling sysfs links and null pointer +dereference problems. + +A prior attempt to solve this by removing SET_NETDEV_DEV entirely [1] +was reverted due to power management ordering concerns and a NO-CARRIER +regression. + +A subsequent attempt to defer net_device allocation to bind [2] broke +1:1 mapping between function instance and network device, making it +impossible for configfs to report the resolved interface name. This +results in a regression where the DHCP server fails on pmOS. + +Use device_move to reparent the net_device between the gadget device and +/sys/devices/virtual/ across bind/unbind cycles. This preserves the +network interface across USB reconnection, allowing the DHCP server to +retain their binding. + +Introduce gether_attach_gadget()/gether_detach_gadget() helpers and use +__free(detach_gadget) macro to undo attachment on bind failure. The +bind_count ensures device_move executes only on the first bind. + +[1] https://lore.kernel.org/lkml/f2a4f9847617a0929d62025748384092e5f35cce.camel@crapouillou.net/ +[2] https://lore.kernel.org/linux-usb/795ea759-7eaf-4f78-81f4-01ffbf2d7961@ixit.cz/ + +Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-7-ea2afbc7d9b2@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_ncm.c | 38 ++++++++++++++++++++++------------ + drivers/usb/gadget/function/u_ether.c | 22 +++++++++++++++++++ + drivers/usb/gadget/function/u_ether.h | 26 +++++++++++++++++++++++ + drivers/usb/gadget/function/u_ncm.h | 2 - + 4 files changed, 74 insertions(+), 14 deletions(-) + +--- a/drivers/usb/gadget/function/f_ncm.c ++++ b/drivers/usb/gadget/function/f_ncm.c +@@ -1439,6 +1439,7 @@ static int ncm_bind(struct usb_configura + struct f_ncm_opts *ncm_opts; + + struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; ++ struct net_device *net __free(detach_gadget) = NULL; + struct usb_request *request __free(free_usb_request) = NULL; + + if (!can_support_ecm(cdev->gadget)) +@@ -1452,18 +1453,19 @@ static int ncm_bind(struct usb_configura + return -ENOMEM; + } + +- mutex_lock(&ncm_opts->lock); +- gether_set_gadget(ncm_opts->net, cdev->gadget); +- if (!ncm_opts->bound) { +- ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); +- status = gether_register_netdev(ncm_opts->net); +- } +- mutex_unlock(&ncm_opts->lock); +- +- if (status) +- return status; +- +- ncm_opts->bound = true; ++ scoped_guard(mutex, &ncm_opts->lock) ++ if (ncm_opts->bind_count == 0) { ++ if (!device_is_registered(&ncm_opts->net->dev)) { ++ ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); ++ gether_set_gadget(ncm_opts->net, cdev->gadget); ++ status = gether_register_netdev(ncm_opts->net); ++ } else ++ status = gether_attach_gadget(ncm_opts->net, cdev->gadget); ++ ++ if (status) ++ return status; ++ net = ncm_opts->net; ++ } + + ncm_string_defs[1].s = ncm->ethaddr; + +@@ -1564,6 +1566,9 @@ static int ncm_bind(struct usb_configura + } + ncm->notify_req = no_free_ptr(request); + ++ ncm_opts->bind_count++; ++ retain_and_null_ptr(net); ++ + DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", + ncm->port.in_ep->name, ncm->port.out_ep->name, + ncm->notify->name); +@@ -1655,7 +1660,7 @@ static void ncm_free_inst(struct usb_fun + struct f_ncm_opts *opts; + + opts = container_of(f, struct f_ncm_opts, func_inst); +- if (opts->bound) ++ if (device_is_registered(&opts->net->dev)) + gether_cleanup(netdev_priv(opts->net)); + else + free_netdev(opts->net); +@@ -1718,9 +1723,12 @@ static void ncm_free(struct usb_function + static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) + { + struct f_ncm *ncm = func_to_ncm(f); ++ struct f_ncm_opts *ncm_opts; + + DBG(c->cdev, "ncm unbind\n"); + ++ ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); ++ + hrtimer_cancel(&ncm->task_timer); + + kfree(f->os_desc_table); +@@ -1736,6 +1744,10 @@ static void ncm_unbind(struct usb_config + + kfree(ncm->notify_req->buf); + usb_ep_free_request(ncm->notify, ncm->notify_req); ++ ++ ncm_opts->bind_count--; ++ if (ncm_opts->bind_count == 0) ++ gether_detach_gadget(ncm_opts->net); + } + + static struct usb_function *ncm_alloc(struct usb_function_instance *fi) +--- a/drivers/usb/gadget/function/u_ether.c ++++ b/drivers/usb/gadget/function/u_ether.c +@@ -896,6 +896,28 @@ void gether_set_gadget(struct net_device + } + EXPORT_SYMBOL_GPL(gether_set_gadget); + ++int gether_attach_gadget(struct net_device *net, struct usb_gadget *g) ++{ ++ int ret; ++ ++ ret = device_move(&net->dev, &g->dev, DPM_ORDER_DEV_AFTER_PARENT); ++ if (ret) ++ return ret; ++ ++ gether_set_gadget(net, g); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(gether_attach_gadget); ++ ++void gether_detach_gadget(struct net_device *net) ++{ ++ struct eth_dev *dev = netdev_priv(net); ++ ++ device_move(&net->dev, NULL, DPM_ORDER_NONE); ++ dev->gadget = NULL; ++} ++EXPORT_SYMBOL_GPL(gether_detach_gadget); ++ + int gether_set_dev_addr(struct net_device *net, const char *dev_addr) + { + struct eth_dev *dev; +--- a/drivers/usb/gadget/function/u_ether.h ++++ b/drivers/usb/gadget/function/u_ether.h +@@ -151,6 +151,32 @@ static inline struct net_device *gether_ + void gether_set_gadget(struct net_device *net, struct usb_gadget *g); + + /** ++ * gether_attach_gadget - Reparent net_device to the gadget device. ++ * @net: The network device to reparent. ++ * @g: The target USB gadget device to parent to. ++ * ++ * This function moves the network device to be a child of the USB gadget ++ * device in the device hierarchy. This is typically done when the function ++ * is bound to a configuration. ++ * ++ * Returns 0 on success, or a negative error code on failure. ++ */ ++int gether_attach_gadget(struct net_device *net, struct usb_gadget *g); ++ ++/** ++ * gether_detach_gadget - Detach net_device from its gadget parent. ++ * @net: The network device to detach. ++ * ++ * This function moves the network device to be a child of the virtual ++ * devices parent, effectively detaching it from the USB gadget device ++ * hierarchy. This is typically done when the function is unbound ++ * from a configuration but the instance is not yet freed. ++ */ ++void gether_detach_gadget(struct net_device *net); ++ ++DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T)) ++ ++/** + * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address + * @net: device representing this link + * @dev_addr: eth address of this device +--- a/drivers/usb/gadget/function/u_ncm.h ++++ b/drivers/usb/gadget/function/u_ncm.h +@@ -18,7 +18,7 @@ + struct f_ncm_opts { + struct usb_function_instance func_inst; + struct net_device *net; +- bool bound; ++ int bind_count; + + struct config_group *ncm_interf_group; + struct usb_os_desc ncm_os_desc; diff --git a/queue-6.18/usb-gadget-f_tcm-fix-null-pointer-dereferences-in-nexus-handling.patch b/queue-6.18/usb-gadget-f_tcm-fix-null-pointer-dereferences-in-nexus-handling.patch new file mode 100644 index 0000000000..8bc8433fab --- /dev/null +++ b/queue-6.18/usb-gadget-f_tcm-fix-null-pointer-dereferences-in-nexus-handling.patch @@ -0,0 +1,70 @@ +From b9fde507355342a2d64225d582dc8b98ff5ecb19 Mon Sep 17 00:00:00 2001 +From: Jiasheng Jiang +Date: Thu, 19 Feb 2026 02:38:34 +0000 +Subject: usb: gadget: f_tcm: Fix NULL pointer dereferences in nexus handling + +From: Jiasheng Jiang + +commit b9fde507355342a2d64225d582dc8b98ff5ecb19 upstream. + +The `tpg->tpg_nexus` pointer in the USB Target driver is dynamically +managed and tied to userspace configuration via ConfigFS. It can be +NULL if the USB host sends requests before the nexus is fully +established or immediately after it is dropped. + +Currently, functions like `bot_submit_command()` and the data +transfer paths retrieve `tv_nexus = tpg->tpg_nexus` and immediately +dereference `tv_nexus->tvn_se_sess` without any validation. If a +malicious or misconfigured USB host sends a BOT (Bulk-Only Transport) +command during this race window, it triggers a NULL pointer +dereference, leading to a kernel panic (local DoS). + +This exposes an inconsistent API usage within the module, as peer +functions like `usbg_submit_command()` and `bot_send_bad_response()` +correctly implement a NULL check for `tv_nexus` before proceeding. + +Fix this by bringing consistency to the nexus handling. Add the +missing `if (!tv_nexus)` checks to the vulnerable BOT command and +request processing paths, aborting the command gracefully with an +error instead of crashing the system. + +Fixes: c52661d60f63 ("usb-gadget: Initial merge of target module for UASP + BOT") +Cc: stable +Signed-off-by: Jiasheng Jiang +Reviewed-by: Thinh Nguyen +Link: https://patch.msgid.link/20260219023834.17976-1-jiashengjiangcool@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_tcm.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/usb/gadget/function/f_tcm.c ++++ b/drivers/usb/gadget/function/f_tcm.c +@@ -1222,6 +1222,13 @@ static void usbg_submit_cmd(struct usbg_ + se_cmd = &cmd->se_cmd; + tpg = cmd->fu->tpg; + tv_nexus = tpg->tpg_nexus; ++ if (!tv_nexus) { ++ struct usb_gadget *gadget = fuas_to_gadget(cmd->fu); ++ ++ dev_err(&gadget->dev, "Missing nexus, ignoring command\n"); ++ return; ++ } ++ + dir = get_cmd_dir(cmd->cmd_buf); + if (dir < 0) + goto out; +@@ -1482,6 +1489,13 @@ static void bot_cmd_work(struct work_str + se_cmd = &cmd->se_cmd; + tpg = cmd->fu->tpg; + tv_nexus = tpg->tpg_nexus; ++ if (!tv_nexus) { ++ struct usb_gadget *gadget = fuas_to_gadget(cmd->fu); ++ ++ dev_err(&gadget->dev, "Missing nexus, ignoring command\n"); ++ return; ++ } ++ + dir = get_cmd_dir(cmd->cmd_buf); + if (dir < 0) + goto out; diff --git a/queue-6.18/usb-gadget-uvc-fix-interval_duration-calculation.patch b/queue-6.18/usb-gadget-uvc-fix-interval_duration-calculation.patch new file mode 100644 index 0000000000..d52fdb1ba4 --- /dev/null +++ b/queue-6.18/usb-gadget-uvc-fix-interval_duration-calculation.patch @@ -0,0 +1,41 @@ +From 56135c0c60b07729401af9d329fa9c0eded845a6 Mon Sep 17 00:00:00 2001 +From: Junzhong Pan +Date: Fri, 6 Mar 2026 11:30:09 +0800 +Subject: usb: gadget: uvc: fix interval_duration calculation + +From: Junzhong Pan + +commit 56135c0c60b07729401af9d329fa9c0eded845a6 upstream. + +To correctly convert bInterval as interval_duration: + interval_duration = 2^(bInterval-1) * frame_interval + +Current code uses a wrong left shift operand, computing 2^bInterval +instead of 2^(bInterval-1). + +Fixes: 010dc57cb516 ("usb: gadget: uvc: fix interval_duration calculation") +Cc: stable +Signed-off-by: Junzhong Pan +Reviewed-by: Xu Yang +Link: https://patch.msgid.link/20260306-fix-uvc-interval-v1-1-9a2df6859859@linux.spacemit.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/uvc_video.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c +index 7cea641b06b4..2f9700b3f1b6 100644 +--- a/drivers/usb/gadget/function/uvc_video.c ++++ b/drivers/usb/gadget/function/uvc_video.c +@@ -513,7 +513,7 @@ uvc_video_prep_requests(struct uvc_video *video) + return; + } + +- interval_duration = 2 << (video->ep->desc->bInterval - 1); ++ interval_duration = 1 << (video->ep->desc->bInterval - 1); + if (cdev->gadget->speed < USB_SPEED_HIGH) + interval_duration *= 10000; + else +-- +2.53.0 + diff --git a/queue-6.18/usb-image-mdc800-kill-download-urb-on-timeout.patch b/queue-6.18/usb-image-mdc800-kill-download-urb-on-timeout.patch new file mode 100644 index 0000000000..9fe27bc305 --- /dev/null +++ b/queue-6.18/usb-image-mdc800-kill-download-urb-on-timeout.patch @@ -0,0 +1,49 @@ +From 1be3b77de4eb89af8ae2fd6610546be778e25589 Mon Sep 17 00:00:00 2001 +From: Ziyi Guo +Date: Mon, 9 Feb 2026 15:19:37 +0000 +Subject: usb: image: mdc800: kill download URB on timeout + +From: Ziyi Guo + +commit 1be3b77de4eb89af8ae2fd6610546be778e25589 upstream. + +mdc800_device_read() submits download_urb and waits for completion. +If the timeout fires and the device has not responded, the function +returns without killing the URB, leaving it active. + +A subsequent read() resubmits the same URB while it is still +in-flight, triggering the WARN in usb_submit_urb(): + + "URB submitted while active" + +Check the return value of wait_event_timeout() and kill the URB if +it indicates timeout, ensuring the URB is complete before its status +is inspected or the URB is resubmitted. + +Similar to +- commit 372c93131998 ("USB: yurex: fix control-URB timeout handling") +- commit b98d5000c505 ("media: rc: iguanair: handle timeouts") + +Signed-off-by: Ziyi Guo +Cc: stable +Link: https://patch.msgid.link/20260209151937.2247202-1-n7l8m4@u.northwestern.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/image/mdc800.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/image/mdc800.c ++++ b/drivers/usb/image/mdc800.c +@@ -730,9 +730,11 @@ static ssize_t mdc800_device_read (struc + mutex_unlock(&mdc800->io_lock); + return len-left; + } +- wait_event_timeout(mdc800->download_wait, ++ retval = wait_event_timeout(mdc800->download_wait, + mdc800->downloaded, + msecs_to_jiffies(TO_DOWNLOAD_GET_READY)); ++ if (!retval) ++ usb_kill_urb(mdc800->download_urb); + mdc800->downloaded = 0; + if (mdc800->download_urb->status != 0) + { diff --git a/queue-6.18/usb-legacy-ncm-fix-npe-in-gncm_bind.patch b/queue-6.18/usb-legacy-ncm-fix-npe-in-gncm_bind.patch new file mode 100644 index 0000000000..26ed5a675c --- /dev/null +++ b/queue-6.18/usb-legacy-ncm-fix-npe-in-gncm_bind.patch @@ -0,0 +1,75 @@ +From fde0634ad9856b3943a2d1a8cc8de174a63ac840 Mon Sep 17 00:00:00 2001 +From: Kuen-Han Tsai +Date: Sat, 21 Feb 2026 22:48:15 +0800 +Subject: usb: legacy: ncm: Fix NPE in gncm_bind + +From: Kuen-Han Tsai + +commit fde0634ad9856b3943a2d1a8cc8de174a63ac840 upstream. + +Commit 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle +with bind/unbind") deferred the allocation of the net_device. This +change leads to a NULL pointer dereference in the legacy NCM driver as +it attempts to access the net_device before it's fully instantiated. + +Store the provided qmult, host_addr, and dev_addr into the struct +ncm_opts->net_opts during gncm_bind(). These values will be properly +applied to the net_device when it is allocated and configured later in +the binding process by the NCM function driver. + +Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind") +Cc: stable@kernel.org +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-lkp/202602181727.fd76c561-lkp@intel.com +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260221-legacy-ncm-v2-1-dfb891d76507@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/legacy/ncm.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c +index 0f1b45e3abd1..e8d565534053 100644 +--- a/drivers/usb/gadget/legacy/ncm.c ++++ b/drivers/usb/gadget/legacy/ncm.c +@@ -15,8 +15,10 @@ + /* #define DEBUG */ + /* #define VERBOSE_DEBUG */ + ++#include + #include + #include ++#include + #include + + #include "u_ether.h" +@@ -129,6 +131,7 @@ static int gncm_bind(struct usb_composite_dev *cdev) + struct usb_gadget *gadget = cdev->gadget; + struct f_ncm_opts *ncm_opts; + int status; ++ u8 mac[ETH_ALEN]; + + f_ncm_inst = usb_get_function_instance("ncm"); + if (IS_ERR(f_ncm_inst)) +@@ -136,11 +139,15 @@ static int gncm_bind(struct usb_composite_dev *cdev) + + ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst); + +- gether_set_qmult(ncm_opts->net, qmult); +- if (!gether_set_host_addr(ncm_opts->net, host_addr)) ++ ncm_opts->net_opts.qmult = qmult; ++ if (host_addr && mac_pton(host_addr, mac)) { ++ memcpy(&ncm_opts->net_opts.host_mac, mac, ETH_ALEN); + pr_info("using host ethernet address: %s", host_addr); +- if (!gether_set_dev_addr(ncm_opts->net, dev_addr)) ++ } ++ if (dev_addr && mac_pton(dev_addr, mac)) { ++ memcpy(&ncm_opts->net_opts.dev_mac, mac, ETH_ALEN); + pr_info("using self ethernet address: %s", dev_addr); ++ } + + /* Allocate string descriptor numbers ... note that string + * contents can be overridden by the composite_dev glue. +-- +2.53.0 + diff --git a/queue-6.18/usb-mdc800-handle-signal-and-read-racing.patch b/queue-6.18/usb-mdc800-handle-signal-and-read-racing.patch new file mode 100644 index 0000000000..2c2bcd4388 --- /dev/null +++ b/queue-6.18/usb-mdc800-handle-signal-and-read-racing.patch @@ -0,0 +1,32 @@ +From 2d6d260e9a3576256fe9ef6d1f7930c9ec348723 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Mon, 9 Feb 2026 15:20:48 +0100 +Subject: usb: mdc800: handle signal and read racing + +From: Oliver Neukum + +commit 2d6d260e9a3576256fe9ef6d1f7930c9ec348723 upstream. + +If a signal arrives after a read has partially completed, +we need to return the number of bytes read. -EINTR is correct +only if that number is zero. + +Signed-off-by: Oliver Neukum +Cc: stable +Link: https://patch.msgid.link/20260209142048.1503791-1-oneukum@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/image/mdc800.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/image/mdc800.c ++++ b/drivers/usb/image/mdc800.c +@@ -707,7 +707,7 @@ static ssize_t mdc800_device_read (struc + if (signal_pending (current)) + { + mutex_unlock(&mdc800->io_lock); +- return -EINTR; ++ return len == left ? -EINTR : len-left; + } + + sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left; diff --git a/queue-6.18/usb-misc-uss720-properly-clean-up-reference-in-uss720_probe.patch b/queue-6.18/usb-misc-uss720-properly-clean-up-reference-in-uss720_probe.patch new file mode 100644 index 0000000000..8d99815202 --- /dev/null +++ b/queue-6.18/usb-misc-uss720-properly-clean-up-reference-in-uss720_probe.patch @@ -0,0 +1,33 @@ +From 45dba8011efac11a2f360383221b541f5ea53ce5 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Mon, 23 Feb 2026 13:19:43 +0100 +Subject: usb: misc: uss720: properly clean up reference in uss720_probe() + +From: Greg Kroah-Hartman + +commit 45dba8011efac11a2f360383221b541f5ea53ce5 upstream. + +If get_1284_register() fails, the usb device reference count is +incorrect and needs to be properly dropped before returning. That will +happen when the kref is dropped in the call to destroy_priv(), so jump +to that error path instead of returning directly. + +Cc: stable +Assisted-by: gkh_clanker_2000 +Link: https://patch.msgid.link/2026022342-smokiness-stove-d792@gregkh +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/uss720.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/misc/uss720.c ++++ b/drivers/usb/misc/uss720.c +@@ -736,7 +736,7 @@ static int uss720_probe(struct usb_inter + ret = get_1284_register(pp, 0, ®, GFP_KERNEL); + dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg); + if (ret < 0) +- return ret; ++ goto probe_abort; + + ret = usb_find_last_int_in_endpoint(interface, &epd); + if (!ret) { diff --git a/queue-6.18/usb-renesas_usbhs-fix-use-after-free-in-isr-during-device-removal.patch b/queue-6.18/usb-renesas_usbhs-fix-use-after-free-in-isr-during-device-removal.patch new file mode 100644 index 0000000000..fd18a2cdcb --- /dev/null +++ b/queue-6.18/usb-renesas_usbhs-fix-use-after-free-in-isr-during-device-removal.patch @@ -0,0 +1,46 @@ +From 3cbc242b88c607f55da3d0d0d336b49bf1e20412 Mon Sep 17 00:00:00 2001 +From: Fan Wu +Date: Tue, 3 Mar 2026 07:33:44 +0000 +Subject: usb: renesas_usbhs: fix use-after-free in ISR during device removal + +From: Fan Wu + +commit 3cbc242b88c607f55da3d0d0d336b49bf1e20412 upstream. + +In usbhs_remove(), the driver frees resources (including the pipe array) +while the interrupt handler (usbhs_interrupt) is still registered. If an +interrupt fires after usbhs_pipe_remove() but before the driver is fully +unbound, the ISR may access freed memory, causing a use-after-free. + +Fix this by calling devm_free_irq() before freeing resources. This ensures +the interrupt handler is both disabled and synchronized (waits for any +running ISR to complete) before usbhs_pipe_remove() is called. + +Fixes: f1407d5c6624 ("usb: renesas_usbhs: Add Renesas USBHS common code") +Cc: stable +Suggested-by: Alan Stern +Signed-off-by: Fan Wu +Link: https://patch.msgid.link/20260303073344.34577-1-fanwu01@zju.edu.cn +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/renesas_usbhs/common.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/usb/renesas_usbhs/common.c ++++ b/drivers/usb/renesas_usbhs/common.c +@@ -815,6 +815,15 @@ static void usbhs_remove(struct platform + + usbhs_platform_call(priv, hardware_exit, pdev); + reset_control_assert(priv->rsts); ++ ++ /* ++ * Explicitly free the IRQ to ensure the interrupt handler is ++ * disabled and synchronized before freeing resources. ++ * devm_free_irq() calls free_irq() which waits for any running ++ * ISR to complete, preventing UAF. ++ */ ++ devm_free_irq(&pdev->dev, priv->irq, priv); ++ + usbhs_mod_remove(priv); + usbhs_fifo_remove(priv); + usbhs_pipe_remove(priv); diff --git a/queue-6.18/usb-roles-get-usb-role-switch-from-parent-only-for-usb-b-connector.patch b/queue-6.18/usb-roles-get-usb-role-switch-from-parent-only-for-usb-b-connector.patch new file mode 100644 index 0000000000..f4caae9c6a --- /dev/null +++ b/queue-6.18/usb-roles-get-usb-role-switch-from-parent-only-for-usb-b-connector.patch @@ -0,0 +1,54 @@ +From 8345b1539faa49fcf9c9439c3cbd97dac6eca171 Mon Sep 17 00:00:00 2001 +From: Xu Yang +Date: Mon, 9 Mar 2026 15:43:13 +0800 +Subject: usb: roles: get usb role switch from parent only for usb-b-connector + +From: Xu Yang + +commit 8345b1539faa49fcf9c9439c3cbd97dac6eca171 upstream. + +usb_role_switch_is_parent() was walking up to the parent node and checking +for the "usb-role-switch" property regardless of the type of the passed +fwnode. This could cause unrelated device nodes to be probed as potential +role switch parent, leading to spurious matches and "-EPROBE_DEFER" being +returned infinitely. + +Till now only Type-B connector node will have a parent node which may +present "usb-role-switch" property and register the role switch device. +For Type-C connector node, its parent node will always be a Type-C chip +device which will never register the role switch device. However, it may +still present a non-boolean "usb-role-switch = <&usb_controller>" property +for historical compatibility. + +So restrict the helper to only operate on Type-B connector when attempting +to get the role switch from parent node. + +Fixes: 6fadd72943b8 ("usb: roles: get usb-role-switch from parent") +Cc: stable +Signed-off-by: Xu Yang +Tested-by: Arnaud Ferraris +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260309074313.2809867-3-xu.yang_2@nxp.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/roles/class.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/roles/class.c ++++ b/drivers/usb/roles/class.c +@@ -139,9 +139,14 @@ static void *usb_role_switch_match(const + static struct usb_role_switch * + usb_role_switch_is_parent(struct fwnode_handle *fwnode) + { +- struct fwnode_handle *parent = fwnode_get_parent(fwnode); ++ struct fwnode_handle *parent; + struct device *dev; + ++ if (!fwnode_device_is_compatible(fwnode, "usb-b-connector")) ++ return NULL; ++ ++ parent = fwnode_get_parent(fwnode); ++ + if (!fwnode_property_present(parent, "usb-role-switch")) { + fwnode_handle_put(parent); + return NULL; diff --git a/queue-6.18/usb-typec-altmode-displayport-set-displayport-signaling-rate-in-configure-message.patch b/queue-6.18/usb-typec-altmode-displayport-set-displayport-signaling-rate-in-configure-message.patch new file mode 100644 index 0000000000..93ecb083c4 --- /dev/null +++ b/queue-6.18/usb-typec-altmode-displayport-set-displayport-signaling-rate-in-configure-message.patch @@ -0,0 +1,48 @@ +From e8557acfa079a54b59a21f447c82a31aec7717df Mon Sep 17 00:00:00 2001 +From: RD Babiera +Date: Tue, 10 Mar 2026 20:41:05 +0000 +Subject: usb: typec: altmode/displayport: set displayport signaling rate in configure message + +From: RD Babiera + +commit e8557acfa079a54b59a21f447c82a31aec7717df upstream. + +dp_altmode_configure sets the signaling rate to the current +configuration's rate and then shifts the value to the Select +Configuration bitfield. On the initial configuration, dp->data.conf +is 0 to begin with, so the signaling rate field is never set, which +leads to some DisplayPort Alt Mode partners sending NAK to the +Configure message. + +Set the signaling rate to the capabilities supported by both the +port and the port partner. If the cable supports DisplayPort Alt Mode, +then include its capabilities as well. + +Fixes: a17fae8fc38e ("usb: typec: Add Displayport Alternate Mode 2.1 Support") +Cc: stable +Signed-off-by: RD Babiera +Acked-by: Heikki Krogerus +Link: https://patch.msgid.link/20260310204106.3939862-2-rdbabiera@google.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/typec/altmodes/displayport.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/typec/altmodes/displayport.c ++++ b/drivers/usb/typec/altmodes/displayport.c +@@ -100,9 +100,14 @@ static int dp_altmode_configure(struct d + { + u8 pin_assign = 0; + u32 conf; ++ u32 signal; + + /* DP Signalling */ +- conf = (dp->data.conf & DP_CONF_SIGNALLING_MASK) >> DP_CONF_SIGNALLING_SHIFT; ++ signal = DP_CAP_DP_SIGNALLING(dp->port->vdo) & DP_CAP_DP_SIGNALLING(dp->alt->vdo); ++ if (dp->plug_prime) ++ signal &= DP_CAP_DP_SIGNALLING(dp->plug_prime->vdo); ++ ++ conf = signal << DP_CONF_SIGNALLING_SHIFT; + + switch (con) { + case DP_STATUS_CON_DISABLED: diff --git a/queue-6.18/usb-usbcore-introduce-usb_bulk_msg_killable.patch b/queue-6.18/usb-usbcore-introduce-usb_bulk_msg_killable.patch new file mode 100644 index 0000000000..370c584271 --- /dev/null +++ b/queue-6.18/usb-usbcore-introduce-usb_bulk_msg_killable.patch @@ -0,0 +1,166 @@ +From 416909962e7cdf29fd01ac523c953f37708df93d Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 17 Feb 2026 22:07:47 -0500 +Subject: USB: usbcore: Introduce usb_bulk_msg_killable() + +From: Alan Stern + +commit 416909962e7cdf29fd01ac523c953f37708df93d upstream. + +The synchronous message API in usbcore (usb_control_msg(), +usb_bulk_msg(), and so on) uses uninterruptible waits. However, +drivers may call these routines in the context of a user thread, which +means it ought to be possible to at least kill them. + +For this reason, introduce a new usb_bulk_msg_killable() function +which behaves the same as usb_bulk_msg() except for using +wait_for_completion_killable_timeout() instead of +wait_for_completion_timeout(). The same can be done later for +usb_control_msg() later on, if it turns out to be needed. + +Signed-off-by: Alan Stern +Suggested-by: Oliver Neukum +Link: https://lore.kernel.org/linux-usb/3acfe838-6334-4f6d-be7c-4bb01704b33d@rowland.harvard.edu/ +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +CC: stable@vger.kernel.org +Link: https://patch.msgid.link/248628b4-cc83-4e81-a620-3ce4e0376d41@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/message.c | 79 +++++++++++++++++++++++++++++++++++++++------ + include/linux/usb.h | 5 +- + 2 files changed, 72 insertions(+), 12 deletions(-) + +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -42,16 +42,17 @@ static void usb_api_blocking_completion( + + + /* +- * Starts urb and waits for completion or timeout. Note that this call +- * is NOT interruptible. Many device driver i/o requests should be +- * interruptible and therefore these drivers should implement their +- * own interruptible routines. ++ * Starts urb and waits for completion or timeout. ++ * Whether or not the wait is killable depends on the flag passed in. ++ * For example, compare usb_bulk_msg() and usb_bulk_msg_killable(). + */ +-static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) ++static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length, ++ bool killable) + { + struct api_context ctx; + unsigned long expire; + int retval; ++ long rc; + + init_completion(&ctx.done); + urb->context = &ctx; +@@ -61,12 +62,21 @@ static int usb_start_wait_urb(struct urb + goto out; + + expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; +- if (!wait_for_completion_timeout(&ctx.done, expire)) { ++ if (killable) ++ rc = wait_for_completion_killable_timeout(&ctx.done, expire); ++ else ++ rc = wait_for_completion_timeout(&ctx.done, expire); ++ if (rc <= 0) { + usb_kill_urb(urb); +- retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status); ++ if (ctx.status != -ENOENT) ++ retval = ctx.status; ++ else if (rc == 0) ++ retval = -ETIMEDOUT; ++ else ++ retval = rc; + + dev_dbg(&urb->dev->dev, +- "%s timed out on ep%d%s len=%u/%u\n", ++ "%s timed out or killed on ep%d%s len=%u/%u\n", + current->comm, + usb_endpoint_num(&urb->ep->desc), + usb_urb_dir_in(urb) ? "in" : "out", +@@ -100,7 +110,7 @@ static int usb_internal_control_msg(stru + usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data, + len, usb_api_blocking_completion, NULL); + +- retv = usb_start_wait_urb(urb, timeout, &length); ++ retv = usb_start_wait_urb(urb, timeout, &length, false); + if (retv < 0) + return retv; + else +@@ -385,10 +395,59 @@ int usb_bulk_msg(struct usb_device *usb_ + usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL); + +- return usb_start_wait_urb(urb, timeout, actual_length); ++ return usb_start_wait_urb(urb, timeout, actual_length, false); + } + EXPORT_SYMBOL_GPL(usb_bulk_msg); + ++/** ++ * usb_bulk_msg_killable - Builds a bulk urb, sends it off and waits for completion in a killable state ++ * @usb_dev: pointer to the usb device to send the message to ++ * @pipe: endpoint "pipe" to send the message to ++ * @data: pointer to the data to send ++ * @len: length in bytes of the data to send ++ * @actual_length: pointer to a location to put the actual length transferred ++ * in bytes ++ * @timeout: time in msecs to wait for the message to complete before ++ * timing out (if 0 the wait is forever) ++ * ++ * Context: task context, might sleep. ++ * ++ * This function is just like usb_blk_msg() except that it waits in a ++ * killable state. ++ * ++ * Return: ++ * If successful, 0. Otherwise a negative error number. The number of actual ++ * bytes transferred will be stored in the @actual_length parameter. ++ * ++ */ ++int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe, ++ void *data, int len, int *actual_length, int timeout) ++{ ++ struct urb *urb; ++ struct usb_host_endpoint *ep; ++ ++ ep = usb_pipe_endpoint(usb_dev, pipe); ++ if (!ep || len < 0) ++ return -EINVAL; ++ ++ urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!urb) ++ return -ENOMEM; ++ ++ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == ++ USB_ENDPOINT_XFER_INT) { ++ pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); ++ usb_fill_int_urb(urb, usb_dev, pipe, data, len, ++ usb_api_blocking_completion, NULL, ++ ep->desc.bInterval); ++ } else ++ usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, ++ usb_api_blocking_completion, NULL); ++ ++ return usb_start_wait_urb(urb, timeout, actual_length, true); ++} ++EXPORT_SYMBOL_GPL(usb_bulk_msg_killable); ++ + /*-------------------------------------------------------------------*/ + + static void sg_clean(struct usb_sg_request *io) +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1869,8 +1869,9 @@ extern int usb_control_msg(struct usb_de + extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout); + extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, +- void *data, int len, int *actual_length, +- int timeout); ++ void *data, int len, int *actual_length, int timeout); ++extern int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe, ++ void *data, int len, int *actual_length, int timeout); + + /* wrappers around usb_control_msg() for the most common standard requests */ + int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request, diff --git a/queue-6.18/usb-usbtmc-use-usb_bulk_msg_killable-with-user-specified-timeouts.patch b/queue-6.18/usb-usbtmc-use-usb_bulk_msg_killable-with-user-specified-timeouts.patch new file mode 100644 index 0000000000..a113a1bdfa --- /dev/null +++ b/queue-6.18/usb-usbtmc-use-usb_bulk_msg_killable-with-user-specified-timeouts.patch @@ -0,0 +1,57 @@ +From 7784caa413a89487dd14dd5c41db8753483b2acb Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 17 Feb 2026 22:09:22 -0500 +Subject: USB: usbtmc: Use usb_bulk_msg_killable() with user-specified timeouts + +From: Alan Stern + +commit 7784caa413a89487dd14dd5c41db8753483b2acb upstream. + +The usbtmc driver accepts timeout values specified by the user in an +ioctl command, and uses these timeouts for some usb_bulk_msg() calls. +Since the user can specify arbitrarily long timeouts and +usb_bulk_msg() uses unkillable waits, call usb_bulk_msg_killable() +instead to avoid the possibility of the user hanging a kernel thread +indefinitely. + +Reported-by: syzbot+25ba18e2c5040447585d@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/linux-usb/8e1c7ac5-e076-44b0-84b8-1b34b20f0ae1@suse.com/T/#t +Tested-by: syzbot+25ba18e2c5040447585d@syzkaller.appspotmail.com +Signed-off-by: Alan Stern +Fixes: 048c6d88a021 ("usb: usbtmc: Add ioctls to set/get usb timeout") +CC: stable@vger.kernel.org +Link: https://patch.msgid.link/81c6fc24-0607-40f1-8c20-5270dab2fad5@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/usbtmc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/usb/class/usbtmc.c ++++ b/drivers/usb/class/usbtmc.c +@@ -727,7 +727,7 @@ static int usbtmc488_ioctl_trigger(struc + buffer[1] = data->bTag; + buffer[2] = ~data->bTag; + +- retval = usb_bulk_msg(data->usb_dev, ++ retval = usb_bulk_msg_killable(data->usb_dev, + usb_sndbulkpipe(data->usb_dev, + data->bulk_out), + buffer, USBTMC_HEADER_SIZE, +@@ -1347,7 +1347,7 @@ static int send_request_dev_dep_msg_in(s + buffer[11] = 0; /* Reserved */ + + /* Send bulk URB */ +- retval = usb_bulk_msg(data->usb_dev, ++ retval = usb_bulk_msg_killable(data->usb_dev, + usb_sndbulkpipe(data->usb_dev, + data->bulk_out), + buffer, USBTMC_HEADER_SIZE, +@@ -1419,7 +1419,7 @@ static ssize_t usbtmc_read(struct file * + actual = 0; + + /* Send bulk URB */ +- retval = usb_bulk_msg(data->usb_dev, ++ retval = usb_bulk_msg_killable(data->usb_dev, + usb_rcvbulkpipe(data->usb_dev, + data->bulk_in), + buffer, bufsize, &actual, diff --git a/queue-6.18/usb-xhci-fix-memory-leak-in-xhci_disable_slot.patch b/queue-6.18/usb-xhci-fix-memory-leak-in-xhci_disable_slot.patch new file mode 100644 index 0000000000..11b7532399 --- /dev/null +++ b/queue-6.18/usb-xhci-fix-memory-leak-in-xhci_disable_slot.patch @@ -0,0 +1,66 @@ +From c1c8550e70401159184130a1afc6261db01fc0ce Mon Sep 17 00:00:00 2001 +From: Zilin Guan +Date: Thu, 5 Mar 2026 00:36:37 +0200 +Subject: usb: xhci: Fix memory leak in xhci_disable_slot() + +From: Zilin Guan + +commit c1c8550e70401159184130a1afc6261db01fc0ce upstream. + +xhci_alloc_command() allocates a command structure and, when the +second argument is true, also allocates a completion structure. +Currently, the error handling path in xhci_disable_slot() only frees +the command structure using kfree(), causing the completion structure +to leak. + +Use xhci_free_command() instead of kfree(). xhci_free_command() correctly +frees both the command structure and the associated completion structure. +Since the command structure is allocated with zero-initialization, +command->in_ctx is NULL and will not be erroneously freed by +xhci_free_command(). + +This bug was found using an experimental static analysis tool we are +developing. The tool is based on the LLVM framework and is specifically +designed to detect memory management issues. It is currently under +active development and not yet publicly available, but we plan to +open-source it after our research is published. + +The bug was originally detected on v6.13-rc1 using our static analysis +tool, and we have verified that the issue persists in the latest mainline +kernel. + +We performed build testing on x86_64 with allyesconfig using GCC=11.4.0. +Since triggering these error paths in xhci_disable_slot() requires specific +hardware conditions or abnormal state, we were unable to construct a test +case to reliably trigger these specific error paths at runtime. + +Fixes: 7faac1953ed1 ("xhci: avoid race between disable slot command and host runtime suspend") +CC: stable@vger.kernel.org +Signed-off-by: Zilin Guan +Signed-off-by: Mathias Nyman +Link: https://patch.msgid.link/20260304223639.3882398-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -4139,7 +4139,7 @@ int xhci_disable_slot(struct xhci_hcd *x + if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || + (xhci->xhc_state & XHCI_STATE_HALTED)) { + spin_unlock_irqrestore(&xhci->lock, flags); +- kfree(command); ++ xhci_free_command(xhci, command); + return -ENODEV; + } + +@@ -4147,7 +4147,7 @@ int xhci_disable_slot(struct xhci_hcd *x + slot_id); + if (ret) { + spin_unlock_irqrestore(&xhci->lock, flags); +- kfree(command); ++ xhci_free_command(xhci, command); + return ret; + } + xhci_ring_cmd_db(xhci); diff --git a/queue-6.18/usb-xhci-prevent-interrupt-storm-on-host-controller-error-hce.patch b/queue-6.18/usb-xhci-prevent-interrupt-storm-on-host-controller-error-hce.patch new file mode 100644 index 0000000000..95bc24af16 --- /dev/null +++ b/queue-6.18/usb-xhci-prevent-interrupt-storm-on-host-controller-error-hce.patch @@ -0,0 +1,48 @@ +From d6d5febd12452b7fd951fdd15c3ec262f01901a4 Mon Sep 17 00:00:00 2001 +From: Dayu Jiang +Date: Thu, 5 Mar 2026 00:36:38 +0200 +Subject: usb: xhci: Prevent interrupt storm on host controller error (HCE) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dayu Jiang + +commit d6d5febd12452b7fd951fdd15c3ec262f01901a4 upstream. + +The xHCI controller reports a Host Controller Error (HCE) in UAS Storage +Device plug/unplug scenarios on Android devices. HCE is checked in +xhci_irq() function and causes an interrupt storm (since the interrupt +isn’t cleared), leading to severe system-level faults. + +When the xHC controller reports HCE in the interrupt handler, the driver +only logs a warning and assumes xHC activity will stop as stated in xHCI +specification. An interrupt storm does however continue on some hosts +even after HCE, and only ceases after manually disabling xHC interrupt +and stopping the controller by calling xhci_halt(). + +Add xhci_halt() to xhci_irq() function where STS_HCE status is checked, +mirroring the existing error handling pattern used for STS_FATAL errors. + +This only fixes the interrupt storm. Proper HCE recovery requires resetting +and re-initializing the xHC. + +CC: stable@vger.kernel.org +Signed-off-by: Dayu Jiang +Signed-off-by: Mathias Nyman +Link: https://patch.msgid.link/20260304223639.3882398-3-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-ring.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -3224,6 +3224,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd + + if (status & STS_HCE) { + xhci_warn(xhci, "WARNING: Host Controller Error\n"); ++ xhci_halt(xhci); + goto out; + } + diff --git a/queue-6.18/usb-yurex-fix-race-in-probe.patch b/queue-6.18/usb-yurex-fix-race-in-probe.patch new file mode 100644 index 0000000000..150a704d4f --- /dev/null +++ b/queue-6.18/usb-yurex-fix-race-in-probe.patch @@ -0,0 +1,41 @@ +From 7a875c09899ba0404844abfd8f0d54cdc481c151 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Mon, 9 Feb 2026 15:37:20 +0100 +Subject: usb: yurex: fix race in probe + +From: Oliver Neukum + +commit 7a875c09899ba0404844abfd8f0d54cdc481c151 upstream. + +The bbu member of the descriptor must be set to the value +standing for uninitialized values before the URB whose +completion handler sets bbu is submitted. Otherwise there is +a window during which probing can overwrite already retrieved +data. + +Cc: stable +Signed-off-by: Oliver Neukum +Link: https://patch.msgid.link/20260209143720.1507500-1-oneukum@suse.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/misc/yurex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/misc/yurex.c ++++ b/drivers/usb/misc/yurex.c +@@ -272,6 +272,7 @@ static int yurex_probe(struct usb_interf + dev->int_buffer, YUREX_BUF_SIZE, yurex_interrupt, + dev, 1); + dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ dev->bbu = -1; + if (usb_submit_urb(dev->urb, GFP_KERNEL)) { + retval = -EIO; + dev_err(&interface->dev, "Could not submitting URB\n"); +@@ -280,7 +281,6 @@ static int yurex_probe(struct usb_interf + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); +- dev->bbu = -1; + + /* we can register the device now, as it is ready */ + retval = usb_register_dev(interface, &yurex_class);