lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20211126115652.1134230-1-kai.heng.feng@canonical.com>
Date:   Fri, 26 Nov 2021 19:56:51 +0800
From:   Kai-Heng Feng <kai.heng.feng@...onical.com>
To:     gregkh@...uxfoundation.org
Cc:     stern@...land.harvard.edu, mathias.nyman@...ux.intel.com,
        Kai-Heng Feng <kai.heng.feng@...onical.com>,
        Thinh Nguyen <Thinh.Nguyen@...opsys.com>,
        Andrew Lunn <andrew@...n.ch>, Rajat Jain <rajatja@...gle.com>,
        Chris Chiu <chris.chiu@...onical.com>,
        linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH v2] usb: core: Avoid doing warm reset on disconnect event

Unplugging USB device may cause an incorrect warm reset loop:
[  143.039019] xhci_hcd 0000:00:14.0: Port change event, 2-3, id 19, portsc: 0x4202c0
[  143.039025] xhci_hcd 0000:00:14.0: handle_port_status: starting usb2 port polling.
[  143.039051] hub 2-0:1.0: state 7 ports 10 chg 0000 evt 0008
[  143.039058] xhci_hcd 0000:00:14.0: Get port status 2-3 read: 0x4202c0, return 0x4102c0
[  143.039092] xhci_hcd 0000:00:14.0: clear port3 connect change, portsc: 0x4002c0
[  143.039096] usb usb2-port3: link state change
[  143.039099] xhci_hcd 0000:00:14.0: clear port3 link state change, portsc: 0x2c0
[  143.039101] usb usb2-port3: do warm reset
[  143.096736] xhci_hcd 0000:00:14.0: Get port status 2-3 read: 0x2b0, return 0x2b0
[  143.096751] usb usb2-port3: not warm reset yet, waiting 50ms
[  143.131500] xhci_hcd 0000:00:14.0: Can't queue urb, port error, link inactive
[  143.138260] xhci_hcd 0000:00:14.0: Port change event, 2-3, id 19, portsc: 0x2802a0
[  143.138263] xhci_hcd 0000:00:14.0: handle_port_status: starting usb2 port polling.
[  143.160756] xhci_hcd 0000:00:14.0: Get port status 2-3 read: 0x2802a0, return 0x3002a0
[  143.160798] usb usb2-port3: not warm reset yet, waiting 200ms

The warm reset is due to its PLS is in eSS.Inactive state. However, USB
3.2 spec table 10-13 mentions "Ports can be disabled by either a fault
condition (disconnect event or other fault condition)", xHCI 1.2 spec
table 5-27 also states that "This flag shall automatically be cleared to
‘0’ by a disconnect event or other fault condition." on PED.

So use CSC = 0 and PED = 0 as indication that device is disconnecting to
avoid doing warm reset.

Signed-off-by: Kai-Heng Feng <kai.heng.feng@...onical.com>
---
v2:
 - Change the variable type to bool.

 drivers/usb/core/hub.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index a9a04ea967019..4f081df70ecf2 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -5564,6 +5564,7 @@ static void port_event(struct usb_hub *hub, int port1)
 		__must_hold(&port_dev->status_lock)
 {
 	int connect_change;
+	bool disconnect = false;
 	struct usb_port *port_dev = hub->ports[port1 - 1];
 	struct usb_device *udev = port_dev->child;
 	struct usb_device *hdev = hub->hdev;
@@ -5579,6 +5580,9 @@ static void port_event(struct usb_hub *hub, int port1)
 	if (portchange & USB_PORT_STAT_C_CONNECTION) {
 		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
 		connect_change = 1;
+		if (!(portstatus & USB_PORT_STAT_CONNECTION) &&
+		    !(portstatus & USB_PORT_STAT_ENABLE))
+			disconnect = true;
 	}
 
 	if (portchange & USB_PORT_STAT_C_ENABLE) {
@@ -5647,7 +5651,7 @@ static void port_event(struct usb_hub *hub, int port1)
 	 * Warm reset a USB3 protocol port if it's in
 	 * SS.Inactive state.
 	 */
-	if (hub_port_warm_reset_required(hub, port1, portstatus)) {
+	if (hub_port_warm_reset_required(hub, port1, portstatus) && !disconnect) {
 		dev_dbg(&port_dev->dev, "do warm reset\n");
 		if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
 				|| udev->state == USB_STATE_NOTATTACHED) {
-- 
2.32.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ