Skip to contentSkip to conversation

usb: core: stop USB enumeration if too many retries

PATCH In review Ray Chi 3 participants 3 messages Nov 7, 2022 – Nov 8, 2022 USB

lore
Share & tools
lore

Ray Chi

author
#0 lore raw

PATCH v5 1/1 usb: core: stop USB enumeration if too many retries

When a broken USB accessory connects to a USB host, usbcore might keep doing enumeration retries. If the host has a watchdog mechanism, the kernel panic will happen on the host.

This patch provides an attribute early_stop to limit the numbers of retries for each port of a hub. If a port was marked with early_stop attribute, unsuccessful connection attempts will fail quickly. In addition, if an early_stop port has failed to initialize, it will ignore all future connection events until early_stop attribute is clear.

---

Changes since v4:
- change the location of calling hub_port_stop_enumerate()
- modify if statement in hub_port_stop_enumerate()
- modify if statement in port_event()

Changes since v3:
- rename the attribute from quick_init to early_stop
- rename the variable of port_dev from ignore_connect to ignore_event
- modify changelog, documentation
- add more comments for hub_port_stop_enumerate()

Changes since v2:
- replace the quirk with the attribute
- Document the attribute
- modify hub_port_stop_enumerate() position in port_event()
- modify the changelog

Changes since v1:
- remove usb_hub_set_port_power()
- add a variable ignore_connect into struct port_dev
- modify hub_port_stop_enumerate() and set ignore_connect in this function
- avoid calling hub_port_connect_change() in port_event()

---
 Documentation/ABI/testing/sysfs-bus-usb | 11 +++++
 drivers/usb/core/hub.c                  | 60 +++++++++++++++++++++++++
 drivers/usb/core/hub.h                  |  4 ++
 drivers/usb/core/port.c                 | 27 +++++++++++
 4 files changed, 102 insertions(+)
Documentation/ABI/testing/sysfs-bus-usb +11 -0
index 568103d3376e..545c2dd97ed0 100644
@@ -264,6 +264,17 @@ Description:
 		attached to the port will not be detected, initialized,
 		or enumerated.
 
+What:		/sys/bus/usb/devices/.../<hub_interface>/port<X>/early_stop
+Date:		Sep 2022
+Contact:	Ray Chi <[email protected]>
+Description:
+		Some USB hosts have some watchdog mechanisms so that the device
+		may enter ramdump if it takes a long time during port initialization.
+		This attribute allows each port just has two attempts so that the
+		port initialization will be failed quickly. In addition, if a port
+		which is marked with early_stop has failed to initialize, it will ignore
+		all future connections until this attribute is clear.
+
 What:		/sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
 Date:		May 2013
 Contact:	Mathias Nyman <[email protected]>
drivers/usb/core/hub.c +60 -0

90 lines not on this page · raw message

drivers/usb/core/hub.h +4 -0
index b2925856b4cb..e23833562e4f 100644
@@ -90,6 +90,8 @@ struct usb_hub {
  * @is_superspeed cache super-speed status
  * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
  * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
+ * @early_stop: whether port initialization will be stopped earlier.
+ * @ignore_event: whether events of the port are ignored.
  */
 struct usb_port {
 	struct usb_device *child;
@@ -103,6 +105,8 @@ struct usb_port {
 	u32 over_current_count;
 	u8 portnum;
 	u32 quirks;
+	unsigned int early_stop:1;
+	unsigned int ignore_event:1;
 	unsigned int is_superspeed:1;
 	unsigned int usb3_lpm_u1_permit:1;
 	unsigned int usb3_lpm_u2_permit:1;
drivers/usb/core/port.c +27 -0
index 015204fc67a1..06a8f1f84f6f 100644
@@ -18,6 +18,32 @@ static int usb_port_block_power_off;
 
 static const struct attribute_group *port_dev_group[];
 
+static ssize_t early_stop_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+
+	return sysfs_emit(buf, "%s\n", port_dev->early_stop ? "yes" : "no");
+}
+
+static ssize_t early_stop_store(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct usb_port *port_dev = to_usb_port(dev);
+	bool value;
+
+	if (kstrtobool(buf, &value))
+		return -EINVAL;
+
+	if (value)
+		port_dev->early_stop = 1;
+	else
+		port_dev->early_stop = 0;
+
+	return count;
+}
+static DEVICE_ATTR_RW(early_stop);
+
 static ssize_t disable_show(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
@@ -237,6 +263,7 @@ static struct attribute *port_dev_attrs[] = {
 	&dev_attr_quirks.attr,
 	&dev_attr_over_current_count.attr,
 	&dev_attr_disable.attr,
+	&dev_attr_early_stop.attr,
 	NULL,
 };
 
Signature · 1 line
2.38.1.431.g37b22c650d-goog
Reviewed-by on v5 1/1
#1 lore raw
Quoted 4 lines · Ray Chi

When a broken USB accessory connects to a USB host, usbcore might keep doing enumeration retries. If the host has a watchdog mechanism, the kernel panic will happen on the host.

Quoted 8 lines

This patch provides an attribute early_stop to limit the numbers of retries for each port of a hub. If a port was marked with early_stop attribute, unsuccessful connection attempts will fail quickly. In addition, if an early_stop port has failed to initialize, it will ignore all future connection events until early_stop attribute is clear.

---

This looks good.

Alan Stern

maintainer
#2 lore raw
In reply to Ray Chi
Quoted 4 lines · Ray Chi

When a broken USB accessory connects to a USB host, usbcore might keep doing enumeration retries. If the host has a watchdog mechanism, the kernel panic will happen on the host.

Quoted 8 lines

This patch provides an attribute early_stop to limit the numbers of retries for each port of a hub. If a port was marked with early_stop attribute, unsuccessful connection attempts will fail quickly. In addition, if an early_stop port has failed to initialize, it will ignore all future connection events until early_stop attribute is clear.

---

Much nicer, thanks for sticking with this! I'll go queue it up now

greg k-h