NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

re: kern/55919: Creative HP-BTW3 (BT-W3) USB audio device has another descriptor layout



Hi,

matthew green <mrg%eterna.com.au@localhost> writes:

> +       while (offs < size) {
> +               desc = (const void *)(tbuf + offs);
>
> should this be "offs <= size - sizeof(*desc)"?  so that we
> don't attempt to read beyond the buffer for this part, and
> these should probably check the larger structure size before
> deciding it's valid:
>
> +                       asid = (const void *)desc;
> +                       offs += asid->bLength;
>
> +                       asf1d = (const void *)desc;
> +                       offs += asf1d->bLength;
>
> etc..
>
> rest LGTM.  would be nice to have tested on many usb audio
> devices :)

Thanks for your comment.
I have tried to fixed two issues.

How about this?

http://www.ryoon.net/~ryoon/sys-dev-usb-uaudio-3.diff

Index: sys/dev/usb/uaudio.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uaudio.c,v
retrieving revision 1.168
diff -u -r1.168 uaudio.c
--- sys/dev/usb/uaudio.c	10 Jan 2021 15:50:16 -0000	1.168
+++ sys/dev/usb/uaudio.c	15 Feb 2021 13:28:02 -0000
@@ -1532,52 +1532,73 @@
 		  int size, const usb_interface_descriptor_t *id)
 #define offs (*offsp)
 {
-	const struct usb_audio_streaming_interface_descriptor *asid;
-	const struct usb_audio_streaming_type1_descriptor *asf1d;
-	const usb_endpoint_descriptor_audio_t *ed;
-	const usb_endpoint_descriptor_audio_t *epdesc1;
-	const struct usb_audio_streaming_endpoint_descriptor *sed;
+	const struct usb_audio_streaming_interface_descriptor *asid = NULL;
+	const struct usb_audio_streaming_type1_descriptor *asf1d = NULL;
+	const usb_endpoint_descriptor_audio_t *ed = NULL;
+	const usb_endpoint_descriptor_audio_t *epdesc1 = NULL;
+	const struct usb_audio_streaming_endpoint_descriptor *sed = NULL;
+	const usb_descriptor_t *desc = NULL;
 	int format, chan __unused, prec, enc;
 	int dir, type, sync;
 	struct as_info ai;
 	const char *format_str __unused;
 
-	asid = (const void *)(tbuf + offs);
-	if (asid->bDescriptorType != UDESC_CS_INTERFACE ||
-	    asid->bDescriptorSubtype != AS_GENERAL)
-		return USBD_INVAL;
-	DPRINTF("asid: bTerminalLink=%d wFormatTag=%d\n",
-		 asid->bTerminalLink, UGETW(asid->wFormatTag));
-	offs += asid->bLength;
-	if (offs > size)
-		return USBD_INVAL;
+	while (offs <= size - sizeof(*desc)) {
+		desc = (const void *)(tbuf + offs);
 
-	asf1d = (const void *)(tbuf + offs);
-	if (asf1d->bDescriptorType != UDESC_CS_INTERFACE ||
-	    asf1d->bDescriptorSubtype != FORMAT_TYPE)
-		return USBD_INVAL;
-	offs += asf1d->bLength;
-	if (offs > size)
+		if (desc->bDescriptorType == UDESC_CS_INTERFACE &&
+		    desc->bDescriptorSubtype == AS_GENERAL) {
+			offs += desc->bLength;
+			if (offs > size)
+				return USBD_INVAL;
+			asid = (const void *)desc;
+		} else if (desc->bDescriptorType == UDESC_CS_INTERFACE &&
+			   desc->bDescriptorSubtype == FORMAT_TYPE) {
+			offs += desc->bLength;
+			if (offs > size)
+				return USBD_INVAL;
+			asf1d = (const void *)desc;
+		} else if (desc->bDescriptorType == UDESC_ENDPOINT) {
+			offs += desc->bLength;
+			if (offs > size)
+				return USBD_INVAL;
+			ed = (const void *)desc;
+		} else if (desc->bDescriptorType == UDESC_CS_ENDPOINT &&
+	    		   desc->bDescriptorSubtype == AS_GENERAL) {
+			offs += desc->bLength;
+			if (offs > size)
+				return USBD_INVAL;
+			sed = (const void *)desc;
+		} else if (ed != NULL && id->bNumEndpoints > 1 &&
+			   desc->bDescriptorType == UDESC_ENDPOINT) {
+			offs += desc->bLength;
+			if (offs > size)
+				return USBD_INVAL;
+			epdesc1 = (const void*)desc;
+		} else
+			break;
+	}
+
+	if (asid == NULL || asf1d == NULL || ed == NULL || sed == NULL ||
+	    (id->bNumEndpoints > 1 && epdesc1 == NULL))
 		return USBD_INVAL;
 
+	format = UGETW(asid->wFormatTag);
+	DPRINTF("asid: bTerminalLink=%d wFormatTag=%d\n",
+		 asid->bTerminalLink, format);
+
 	if (asf1d->bFormatType != FORMAT_TYPE_I) {
 		aprint_normal_dev(sc->sc_dev,
-		    "ignored setting with type %d format\n", UGETW(asid->wFormatTag));
+		    "ignored setting with type %d format\n", format);
 		return USBD_NORMAL_COMPLETION;
 	}
 
-	ed = (const void *)(tbuf + offs);
-	if (ed->bDescriptorType != UDESC_ENDPOINT)
-		return USBD_INVAL;
 	DPRINTF("endpoint[0] bLength=%d bDescriptorType=%d "
 		 "bEndpointAddress=%d bmAttributes=%#x wMaxPacketSize=%d "
 		 "bInterval=%d bRefresh=%d bSynchAddress=%d\n",
 		 ed->bLength, ed->bDescriptorType, ed->bEndpointAddress,
 		 ed->bmAttributes, UGETW(ed->wMaxPacketSize),
 		 ed->bInterval, ed->bRefresh, ed->bSynchAddress);
-	offs += ed->bLength;
-	if (offs > size)
-		return USBD_INVAL;
 	if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS)
 		return USBD_INVAL;
 
@@ -1606,14 +1627,7 @@
 #endif
 	}
 
-	sed = (const void *)(tbuf + offs);
-	if (sed->bDescriptorType != UDESC_CS_ENDPOINT ||
-	    sed->bDescriptorSubtype != AS_GENERAL)
-		return USBD_INVAL;
 	DPRINTF(" streadming_endpoint: offset=%d bLength=%d\n", offs, sed->bLength);
-	offs += sed->bLength;
-	if (offs > size)
-		return USBD_INVAL;
 
 #ifdef UAUDIO_MULTIPLE_ENDPOINTS
 	if (sync && id->bNumEndpoints <= 1) {
@@ -1627,11 +1641,7 @@
 		    "non sync-pipe endpoint but multiple endpoints\n");
 		return USBD_INVAL;
 	}
-	epdesc1 = NULL;
 	if (id->bNumEndpoints > 1) {
-		epdesc1 = (const void*)(tbuf + offs);
-		if (epdesc1->bDescriptorType != UDESC_ENDPOINT)
-			return USBD_INVAL;
 		DPRINTF("endpoint[1] bLength=%d "
 			 "bDescriptorType=%d bEndpointAddress=%d "
 			 "bmAttributes=%#x wMaxPacketSize=%d bInterval=%d "
@@ -1640,9 +1650,6 @@
 			 epdesc1->bEndpointAddress, epdesc1->bmAttributes,
 			 UGETW(epdesc1->wMaxPacketSize), epdesc1->bInterval,
 			 epdesc1->bRefresh, epdesc1->bSynchAddress);
-		offs += epdesc1->bLength;
-		if (offs > size)
-			return USBD_INVAL;
 		if (epdesc1->bSynchAddress != 0) {
 			aprint_error_dev(sc->sc_dev,
 			    "invalid endpoint: bSynchAddress=0\n");
@@ -1665,7 +1672,6 @@
 		/* UE_GET_ADDR(epdesc1->bEndpointAddress), and epdesc1->bRefresh */
 	}
 
-	format = UGETW(asid->wFormatTag);
 	chan = asf1d->bNrChannels;
 	prec = asf1d->bBitResolution;
 	if (prec != 8 && prec != 16 && prec != 24) {


> .mrg.

-- 
Ryo ONODERA // ryo%tetera.org@localhost
PGP fingerprint = 82A2 DC91 76E0 A10A 8ABB  FD1B F404 27FA C7D1 15F3


Home | Main Index | Thread Index | Old Index