⬢ DragonFlyBSD Kernel Audit
DF-5553 / fix.diff
← back to finding ↓ download raw
fix.diff — DF-5553 (authored AFTER verification; validated at table level by
table_check_fixed; NEVER applied to the read-only sys/ tree).

Root cause: usb_make_raw_desc() discriminates CDC union / CDC call-management
descriptors ONLY by (bLength >= 5, bDescriptorType == UDESC_CS_INTERFACE(0x24),
bDescriptorSubtype == {6,1}).  USB Audio class-specific descriptors share the
0x24 type byte and collide with those subtypes: AS_GENERAL is subtype 0x01 and
audio feature units are subtype 0x06.  The phone template therefore has five
descriptors misclassified; two of them sit in non-zero-numbered interfaces and
get their byte[4] incremented by the interface number (bDelay 1->2 in
interface 1, 1->3 in interface 2) inside the generated configuration buffer.

Fix: thread the containing interface's bInterfaceClass into the patcher and
only perform CDC union / CM renumbering inside CDC (0x02) / CDC-data (0x0a)
interfaces.  IAD renumbering stays ungated (type 0x0B cannot collide with
0x24 and composite templates need it).  Audio templates (class 0x01
interfaces) are then left byte-exact.

--- a/sys/bus/u4b/template/usb_template.c
+++ b/sys/bus/u4b/template/usb_template.c
@@ -78,11 +78,13 @@
 static void	usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *);
 static void	usb_make_endpoint_desc(struct usb_temp_setup *,
 		    const struct usb_temp_endpoint_desc *);
@@
-static void	usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *);
+static void	usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *,
+		    uint8_t);
 static void	usb_make_endpoint_desc(struct usb_temp_setup *,
-		    const struct usb_temp_endpoint_desc *);
+		    const struct usb_temp_endpoint_desc *, uint8_t);
@@ -117,8 +119,8 @@
 static void
-usb_make_raw_desc(struct usb_temp_setup *temp,
-    const uint8_t *raw)
+usb_make_raw_desc(struct usb_temp_setup *temp,
+    const uint8_t *raw, uint8_t iface_class)
 {
 	void *dst;
 	uint8_t len;
@@ -133,6 +135,10 @@
 			memcpy(dst, raw, len);
 
 			/* check if we have got a CDC union descriptor */
 
+			/* CDC descriptors only exist inside CDC class
+			 * interfaces: audio CS_INTERFACE descriptors
+			 * collide with subtypes 1 and 6 (DF-5553) */
+			if ((iface_class == UICLASS_CDC) ||
+			    (iface_class == UICLASS_CDC_DATA)) {
 			if ((raw[0] >= sizeof(struct usb_cdc_union_descriptor)) &&
 			    (raw[1] == UDESC_CS_INTERFACE) &&
 			    (raw[2] == UDESCSUB_CDC_UNION)) {
@@ -160,6 +166,7 @@
 				ccd->bDataInterface +=
 				    temp->bInterfaceNumber;
 			}
+			}
 		}
 		temp->size += len;
 	}
@@ -184,8 +191,8 @@
 static void
 usb_make_endpoint_desc(struct usb_temp_setup *temp,
-    const struct usb_temp_endpoint_desc *ted)
+    const struct usb_temp_endpoint_desc *ted, uint8_t iface_class)
 {
@@ -211,7 +218,7 @@
 	rd = ted->ppRawDesc;
 	if (rd) {
 		while (*rd) {
-			usb_make_raw_desc(temp, *rd);
+			usb_make_raw_desc(temp, *rd, iface_class);
 			rd++;
 		}
 	}
@@ -319,7 +326,7 @@
 	if (rd) {
 		while (*rd) {
-			usb_make_raw_desc(temp, *rd);
+			usb_make_raw_desc(temp, *rd, tid->bInterfaceClass);
 			rd++;
 		}
 	}
@@ -332,7 +339,7 @@
 	if (ted) {
 		while (*ted) {
-			usb_make_endpoint_desc(temp, *ted);
+			usb_make_endpoint_desc(temp, *ted,
+			    tid->bInterfaceClass);
 			ted++;
 		}
 	}