From: Greg Kroah-Hartman Date: Mon, 1 Apr 2024 10:09:38 +0000 (+0200) Subject: 6.7-stable patches X-Git-Tag: v6.7.12~65 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=80d0136ceed92ed1777c357a534e0fcbf60482d2;p=thirdparty%2Fkernel%2Fstable-queue.git 6.7-stable patches added patches: usb-core-add-hub_get-and-hub_put-routines.patch usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch usb-core-fix-deadlock-in-usb_deauthorize_interface.patch usb-dwc3-properly-set-system-wakeup.patch --- diff --git a/queue-6.7/series b/queue-6.7/series index cf20cba1adb..3ba9d6c90ef 100644 --- a/queue-6.7/series +++ b/queue-6.7/series @@ -392,3 +392,7 @@ scsi-sg-avoid-sg-device-teardown-race.patch scsi-core-fix-unremoved-procfs-host-directory-regression.patch staging-vc04_services-changen-strncpy-to-strscpy_pad.patch staging-vc04_services-fix-information-leak-in-create_component.patch +usb-dwc3-properly-set-system-wakeup.patch +usb-core-fix-deadlock-in-usb_deauthorize_interface.patch +usb-core-add-hub_get-and-hub_put-routines.patch +usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch diff --git a/queue-6.7/usb-core-add-hub_get-and-hub_put-routines.patch b/queue-6.7/usb-core-add-hub_get-and-hub_put-routines.patch new file mode 100644 index 00000000000..1c66a4661d9 --- /dev/null +++ b/queue-6.7/usb-core-add-hub_get-and-hub_put-routines.patch @@ -0,0 +1,113 @@ +From ee113b860aa169e9a4d2c167c95d0f1961c6e1b8 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 15 Mar 2024 13:04:50 -0400 +Subject: USB: core: Add hub_get() and hub_put() routines + +From: Alan Stern + +commit ee113b860aa169e9a4d2c167c95d0f1961c6e1b8 upstream. + +Create hub_get() and hub_put() routines to encapsulate the kref_get() +and kref_put() calls in hub.c. The new routines will be used by the +next patch in this series. + +Signed-off-by: Alan Stern +Link: https://lore.kernel.org/r/604da420-ae8a-4a9e-91a4-2d511ff404fb@rowland.harvard.edu +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/hub.c | 23 ++++++++++++++++------- + drivers/usb/core/hub.h | 2 ++ + 2 files changed, 18 insertions(+), 7 deletions(-) + +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -123,7 +123,6 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rws + #define HUB_DEBOUNCE_STEP 25 + #define HUB_DEBOUNCE_STABLE 100 + +-static void hub_release(struct kref *kref); + static int usb_reset_and_verify_device(struct usb_device *udev); + static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); + static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, +@@ -685,14 +684,14 @@ static void kick_hub_wq(struct usb_hub * + */ + intf = to_usb_interface(hub->intfdev); + usb_autopm_get_interface_no_resume(intf); +- kref_get(&hub->kref); ++ hub_get(hub); + + if (queue_work(hub_wq, &hub->events)) + return; + + /* the work has already been scheduled */ + usb_autopm_put_interface_async(intf); +- kref_put(&hub->kref, hub_release); ++ hub_put(hub); + } + + void usb_kick_hub_wq(struct usb_device *hdev) +@@ -1060,7 +1059,7 @@ static void hub_activate(struct usb_hub + goto init2; + goto init3; + } +- kref_get(&hub->kref); ++ hub_get(hub); + + /* The superspeed hub except for root hub has to use Hub Depth + * value as an offset into the route string to locate the bits +@@ -1308,7 +1307,7 @@ static void hub_activate(struct usb_hub + device_unlock(&hdev->dev); + } + +- kref_put(&hub->kref, hub_release); ++ hub_put(hub); + } + + /* Implement the continuations for the delays above */ +@@ -1724,6 +1723,16 @@ static void hub_release(struct kref *kre + kfree(hub); + } + ++void hub_get(struct usb_hub *hub) ++{ ++ kref_get(&hub->kref); ++} ++ ++void hub_put(struct usb_hub *hub) ++{ ++ kref_put(&hub->kref, hub_release); ++} ++ + static unsigned highspeed_hubs; + + static void hub_disconnect(struct usb_interface *intf) +@@ -1772,7 +1781,7 @@ static void hub_disconnect(struct usb_in + + onboard_hub_destroy_pdevs(&hub->onboard_hub_devs); + +- kref_put(&hub->kref, hub_release); ++ hub_put(hub); + } + + static bool hub_descriptor_is_sane(struct usb_host_interface *desc) +@@ -5894,7 +5903,7 @@ out_hdev_lock: + + /* Balance the stuff in kick_hub_wq() and allow autosuspend */ + usb_autopm_put_interface(intf); +- kref_put(&hub->kref, hub_release); ++ hub_put(hub); + + kcov_remote_stop(); + } +--- a/drivers/usb/core/hub.h ++++ b/drivers/usb/core/hub.h +@@ -129,6 +129,8 @@ extern void usb_hub_remove_port_device(s + extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, + int port1, bool set); + extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev); ++extern void hub_get(struct usb_hub *hub); ++extern void hub_put(struct usb_hub *hub); + extern int hub_port_debounce(struct usb_hub *hub, int port1, + bool must_be_connected); + extern int usb_clear_port_feature(struct usb_device *hdev, diff --git a/queue-6.7/usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch b/queue-6.7/usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch new file mode 100644 index 00000000000..15514434729 --- /dev/null +++ b/queue-6.7/usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch @@ -0,0 +1,123 @@ +From f4d1960764d8a70318b02f15203a1be2b2554ca1 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 15 Mar 2024 13:06:33 -0400 +Subject: USB: core: Fix deadlock in port "disable" sysfs attribute + +From: Alan Stern + +commit f4d1960764d8a70318b02f15203a1be2b2554ca1 upstream. + +The show and store callback routines for the "disable" sysfs attribute +file in port.c acquire the device lock for the port's parent hub +device. This can cause problems if another process has locked the hub +to remove it or change its configuration: + + Removing the hub or changing its configuration requires the + hub interface to be removed, which requires the port device + to be removed, and device_del() waits until all outstanding + sysfs attribute callbacks for the ports have returned. The + lock can't be released until then. + + But the disable_show() or disable_store() routine can't return + until after it has acquired the lock. + +The resulting deadlock can be avoided by calling +sysfs_break_active_protection(). This will cause the sysfs core not +to wait for the attribute's callback routine to return, allowing the +removal to proceed. The disadvantage is that after making this call, +there is no guarantee that the hub structure won't be deallocated at +any moment. To prevent this, we have to acquire a reference to it +first by calling hub_get(). + +Signed-off-by: Alan Stern +Cc: stable +Link: https://lore.kernel.org/r/f7a8c135-a495-4ce6-bd49-405a45e7ea9a@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/port.c | 38 ++++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +--- a/drivers/usb/core/port.c ++++ b/drivers/usb/core/port.c +@@ -55,11 +55,22 @@ static ssize_t disable_show(struct devic + u16 portstatus, unused; + bool disabled; + int rc; ++ struct kernfs_node *kn; + ++ hub_get(hub); + rc = usb_autopm_get_interface(intf); + if (rc < 0) +- return rc; ++ goto out_hub_get; + ++ /* ++ * Prevent deadlock if another process is concurrently ++ * trying to unregister hdev. ++ */ ++ kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); ++ if (!kn) { ++ rc = -ENODEV; ++ goto out_autopm; ++ } + usb_lock_device(hdev); + if (hub->disconnected) { + rc = -ENODEV; +@@ -69,9 +80,13 @@ static ssize_t disable_show(struct devic + usb_hub_port_status(hub, port1, &portstatus, &unused); + disabled = !usb_port_is_power_on(hub, portstatus); + +-out_hdev_lock: ++ out_hdev_lock: + usb_unlock_device(hdev); ++ sysfs_unbreak_active_protection(kn); ++ out_autopm: + usb_autopm_put_interface(intf); ++ out_hub_get: ++ hub_put(hub); + + if (rc) + return rc; +@@ -89,15 +104,26 @@ static ssize_t disable_store(struct devi + int port1 = port_dev->portnum; + bool disabled; + int rc; ++ struct kernfs_node *kn; + + rc = kstrtobool(buf, &disabled); + if (rc) + return rc; + ++ hub_get(hub); + rc = usb_autopm_get_interface(intf); + if (rc < 0) +- return rc; ++ goto out_hub_get; + ++ /* ++ * Prevent deadlock if another process is concurrently ++ * trying to unregister hdev. ++ */ ++ kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); ++ if (!kn) { ++ rc = -ENODEV; ++ goto out_autopm; ++ } + usb_lock_device(hdev); + if (hub->disconnected) { + rc = -ENODEV; +@@ -118,9 +144,13 @@ static ssize_t disable_store(struct devi + if (!rc) + rc = count; + +-out_hdev_lock: ++ out_hdev_lock: + usb_unlock_device(hdev); ++ sysfs_unbreak_active_protection(kn); ++ out_autopm: + usb_autopm_put_interface(intf); ++ out_hub_get: ++ hub_put(hub); + + return rc; + } diff --git a/queue-6.7/usb-core-fix-deadlock-in-usb_deauthorize_interface.patch b/queue-6.7/usb-core-fix-deadlock-in-usb_deauthorize_interface.patch new file mode 100644 index 00000000000..62aa8e32c6b --- /dev/null +++ b/queue-6.7/usb-core-fix-deadlock-in-usb_deauthorize_interface.patch @@ -0,0 +1,70 @@ +From 80ba43e9f799cbdd83842fc27db667289b3150f5 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Tue, 12 Mar 2024 11:48:23 -0400 +Subject: USB: core: Fix deadlock in usb_deauthorize_interface() + +From: Alan Stern + +commit 80ba43e9f799cbdd83842fc27db667289b3150f5 upstream. + +Among the attribute file callback routines in +drivers/usb/core/sysfs.c, the interface_authorized_store() function is +the only one which acquires a device lock on an ancestor device: It +calls usb_deauthorize_interface(), which locks the interface's parent +USB device. + +The will lead to deadlock if another process already owns that lock +and tries to remove the interface, whether through a configuration +change or because the device has been disconnected. As part of the +removal procedure, device_del() waits for all ongoing sysfs attribute +callbacks to complete. But usb_deauthorize_interface() can't complete +until the device lock has been released, and the lock won't be +released until the removal has finished. + +The mechanism provided by sysfs to prevent this kind of deadlock is +to use the sysfs_break_active_protection() function, which tells sysfs +not to wait for the attribute callback. + +Reported-and-tested by: Yue Sun +Reported by: xingwei lee + +Signed-off-by: Alan Stern +Link: https://lore.kernel.org/linux-usb/CAEkJfYO6jRVC8Tfrd_R=cjO0hguhrV31fDPrLrNOOHocDkPoAA@mail.gmail.com/#r +Fixes: 310d2b4124c0 ("usb: interface authorization: SysFS part of USB interface authorization") +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/1c37eea1-9f56-4534-b9d8-b443438dc869@rowland.harvard.edu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/core/sysfs.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +--- a/drivers/usb/core/sysfs.c ++++ b/drivers/usb/core/sysfs.c +@@ -1168,14 +1168,24 @@ static ssize_t interface_authorized_stor + { + struct usb_interface *intf = to_usb_interface(dev); + bool val; ++ struct kernfs_node *kn; + + if (kstrtobool(buf, &val) != 0) + return -EINVAL; + +- if (val) ++ if (val) { + usb_authorize_interface(intf); +- else +- usb_deauthorize_interface(intf); ++ } else { ++ /* ++ * Prevent deadlock if another process is concurrently ++ * trying to unregister intf. ++ */ ++ kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); ++ if (kn) { ++ usb_deauthorize_interface(intf); ++ sysfs_unbreak_active_protection(kn); ++ } ++ } + + return count; + } diff --git a/queue-6.7/usb-dwc3-properly-set-system-wakeup.patch b/queue-6.7/usb-dwc3-properly-set-system-wakeup.patch new file mode 100644 index 00000000000..f2af04f2e3a --- /dev/null +++ b/queue-6.7/usb-dwc3-properly-set-system-wakeup.patch @@ -0,0 +1,128 @@ +From f9aa41130ac69d13a53ce2a153ca79c70d43f39c Mon Sep 17 00:00:00 2001 +From: Thinh Nguyen +Date: Fri, 8 Mar 2024 02:40:25 +0000 +Subject: usb: dwc3: Properly set system wakeup + +From: Thinh Nguyen + +commit f9aa41130ac69d13a53ce2a153ca79c70d43f39c upstream. + +If the device is configured for system wakeup, then make sure that the +xHCI driver knows about it and make sure to permit wakeup only at the +appropriate time. + +For host mode, if the controller goes through the dwc3 code path, then a +child xHCI platform device is created. Make sure the platform device +also inherits the wakeup setting for xHCI to enable remote wakeup. + +For device mode, make sure to disable system wakeup if no gadget driver +is bound. We may experience unwanted system wakeup due to the wakeup +signal from the controller PMU detecting connection/disconnection when +in low power (D3). E.g. In the case of Steam Deck, the PCI PME prevents +the system staying in suspend. + +Cc: stable@vger.kernel.org +Reported-by: Guilherme G. Piccoli +Closes: https://lore.kernel.org/linux-usb/70a7692d-647c-9be7-00a6-06fc60f77294@igalia.com/T/#mf00d6669c2eff7b308d1162acd1d66c09f0853c7 +Fixes: d07e8819a03d ("usb: dwc3: add xHCI Host support") +Signed-off-by: Thinh Nguyen +Tested-by: Sanath S +Tested-by: Guilherme G. Piccoli # Steam Deck +Link: https://lore.kernel.org/r/667cfda7009b502e08462c8fb3f65841d103cc0a.1709865476.git.Thinh.Nguyen@synopsys.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.c | 2 ++ + drivers/usb/dwc3/core.h | 2 ++ + drivers/usb/dwc3/gadget.c | 10 ++++++++++ + drivers/usb/dwc3/host.c | 11 +++++++++++ + 4 files changed, 25 insertions(+) + +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1507,6 +1507,8 @@ static void dwc3_get_properties(struct d + else + dwc->sysdev = dwc->dev; + ++ dwc->sys_wakeup = device_may_wakeup(dwc->sysdev); ++ + ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name); + if (ret >= 0) { + dwc->usb_psy = power_supply_get_by_name(usb_psy_name); +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -1127,6 +1127,7 @@ struct dwc3_scratchpad_array { + * 3 - Reserved + * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. ++ * @sys_wakeup: set if the device may do system wakeup. + * @wakeup_configured: set if the device is configured for remote wakeup. + * @suspended: set to track suspend event due to U3/L2. + * @imod_interval: set the interrupt moderation interval in 250ns +@@ -1350,6 +1351,7 @@ struct dwc3 { + + unsigned dis_split_quirk:1; + unsigned async_callbacks:1; ++ unsigned sys_wakeup:1; + unsigned wakeup_configured:1; + unsigned suspended:1; + +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -2968,6 +2968,9 @@ static int dwc3_gadget_start(struct usb_ + dwc->gadget_driver = driver; + spin_unlock_irqrestore(&dwc->lock, flags); + ++ if (dwc->sys_wakeup) ++ device_wakeup_enable(dwc->sysdev); ++ + return 0; + } + +@@ -2983,6 +2986,9 @@ static int dwc3_gadget_stop(struct usb_g + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + ++ if (dwc->sys_wakeup) ++ device_wakeup_disable(dwc->sysdev); ++ + spin_lock_irqsave(&dwc->lock, flags); + dwc->gadget_driver = NULL; + dwc->max_cfg_eps = 0; +@@ -4664,6 +4670,10 @@ int dwc3_gadget_init(struct dwc3 *dwc) + else + dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed); + ++ /* No system wakeup if no gadget driver bound */ ++ if (dwc->sys_wakeup) ++ device_wakeup_disable(dwc->sysdev); ++ + return 0; + + err5: +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -123,6 +123,14 @@ int dwc3_host_init(struct dwc3 *dwc) + goto err; + } + ++ if (dwc->sys_wakeup) { ++ /* Restore wakeup setting if switched from device */ ++ device_wakeup_enable(dwc->sysdev); ++ ++ /* Pass on wakeup setting to the new xhci platform device */ ++ device_init_wakeup(&xhci->dev, true); ++ } ++ + return 0; + err: + platform_device_put(xhci); +@@ -131,6 +139,9 @@ err: + + void dwc3_host_exit(struct dwc3 *dwc) + { ++ if (dwc->sys_wakeup) ++ device_init_wakeup(&dwc->xhci->dev, false); ++ + platform_device_unregister(dwc->xhci); + dwc->xhci = NULL; + }