]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2024 10:09:38 +0000 (12:09 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2024 10:09:38 +0000 (12:09 +0200)
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

queue-6.7/series
queue-6.7/usb-core-add-hub_get-and-hub_put-routines.patch [new file with mode: 0644]
queue-6.7/usb-core-fix-deadlock-in-port-disable-sysfs-attribute.patch [new file with mode: 0644]
queue-6.7/usb-core-fix-deadlock-in-usb_deauthorize_interface.patch [new file with mode: 0644]
queue-6.7/usb-dwc3-properly-set-system-wakeup.patch [new file with mode: 0644]

index cf20cba1adb8511cab3085b834e1a84ad8dc7a8b..3ba9d6c90ef67d1544da6e1b91439de7556ad6e2 100644 (file)
@@ -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 (file)
index 0000000..1c66a46
--- /dev/null
@@ -0,0 +1,113 @@
+From ee113b860aa169e9a4d2c167c95d0f1961c6e1b8 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 15 Mar 2024 13:04:50 -0400
+Subject: USB: core: Add hub_get() and hub_put() routines
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+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 <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/604da420-ae8a-4a9e-91a4-2d511ff404fb@rowland.harvard.edu
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..1551443
--- /dev/null
@@ -0,0 +1,123 @@
+From f4d1960764d8a70318b02f15203a1be2b2554ca1 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 15 Mar 2024 13:06:33 -0400
+Subject: USB: core: Fix deadlock in port "disable" sysfs attribute
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+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 <stern@rowland.harvard.edu>
+Cc: stable <stable@kernel.org>
+Link: https://lore.kernel.org/r/f7a8c135-a495-4ce6-bd49-405a45e7ea9a@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..62aa8e3
--- /dev/null
@@ -0,0 +1,70 @@
+From 80ba43e9f799cbdd83842fc27db667289b3150f5 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 12 Mar 2024 11:48:23 -0400
+Subject: USB: core: Fix deadlock in usb_deauthorize_interface()
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+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 <samsun1006219@gmail.com>
+Reported by: xingwei lee <xrivendell7@gmail.com>
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+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 <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..f2af04f
--- /dev/null
@@ -0,0 +1,128 @@
+From f9aa41130ac69d13a53ce2a153ca79c70d43f39c Mon Sep 17 00:00:00 2001
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Date: Fri, 8 Mar 2024 02:40:25 +0000
+Subject: usb: dwc3: Properly set system wakeup
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+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 <gpiccoli@igalia.com>
+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 <Thinh.Nguyen@synopsys.com>
+Tested-by: Sanath S <Sanath.S@amd.com>
+Tested-by: Guilherme G. Piccoli <gpiccoli@igalia.com> # Steam Deck
+Link: https://lore.kernel.org/r/667cfda7009b502e08462c8fb3f65841d103cc0a.1709865476.git.Thinh.Nguyen@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
+ }