Module Name: src Committed By: maxv Date: Wed Aug 7 08:47:09 UTC 2019
Modified Files: src/sys/dev/usb: usb.h usb_subr.c Log Message: Introduce USB_DESCRIPTOR_SIZE (3), and fix two bugs: 1) In usbd_find_idesc(), make sure the tables we're reading fit in the allocated buffer, otherwise small overflow (seen on KASAN, with bLength=1). 2) Modify usbd_find_edesc(), to fix the same issues as 1). ok mrg@ To generate a diff of this commit: cvs rdiff -u -r1.116 -r1.117 src/sys/dev/usb/usb.h cvs rdiff -u -r1.236 -r1.237 src/sys/dev/usb/usb_subr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/usb.h diff -u src/sys/dev/usb/usb.h:1.116 src/sys/dev/usb/usb.h:1.117 --- src/sys/dev/usb/usb.h:1.116 Tue Jul 31 16:44:30 2018 +++ src/sys/dev/usb/usb.h Wed Aug 7 08:47:09 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: usb.h,v 1.116 2018/07/31 16:44:30 khorben Exp $ */ +/* $NetBSD: usb.h,v 1.117 2019/08/07 08:47:09 maxv Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -207,6 +207,7 @@ typedef struct { uByte bDescriptorType; uByte bDescriptorSubtype; } UPACKED usb_descriptor_t; +#define USB_DESCRIPTOR_SIZE 3 typedef struct { uByte bLength; Index: src/sys/dev/usb/usb_subr.c diff -u src/sys/dev/usb/usb_subr.c:1.236 src/sys/dev/usb/usb_subr.c:1.237 --- src/sys/dev/usb/usb_subr.c:1.236 Wed Jul 31 19:40:59 2019 +++ src/sys/dev/usb/usb_subr.c Wed Aug 7 08:47:09 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: usb_subr.c,v 1.236 2019/07/31 19:40:59 maxv Exp $ */ +/* $NetBSD: usb_subr.c,v 1.237 2019/08/07 08:47:09 maxv Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ /* @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.236 2019/07/31 19:40:59 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.237 2019/08/07 08:47:09 maxv Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -359,29 +359,41 @@ usbd_find_idesc(usb_config_descriptor_t USBHIST_FUNC(); USBHIST_CALLED(usbdebug); char *p = (char *)cd; char *end = p + UGETW(cd->wTotalLength); - usb_interface_descriptor_t *d; + usb_descriptor_t *desc; + usb_interface_descriptor_t *idesc; int curidx, lastidx, curaidx = 0; for (curidx = lastidx = -1; p < end; ) { - d = (usb_interface_descriptor_t *)p; + desc = (usb_descriptor_t *)p; + DPRINTFN(4, "idx=%jd(%jd) altidx=%jd(%jd)", ifaceidx, curidx, altidx, curaidx); - DPRINTFN(4, "len=%jd type=%jd", d->bLength, d->bDescriptorType, - 0, 0); - if (d->bLength == 0) - break; /* bad descriptor */ - p += d->bLength; - if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { - if (d->bInterfaceNumber != lastidx) { - lastidx = d->bInterfaceNumber; - curidx++; - curaidx = 0; - } else - curaidx++; - if (ifaceidx == curidx && altidx == curaidx) - return d; + DPRINTFN(4, "len=%jd type=%jd", desc->bLength, + desc->bDescriptorType, 0, 0); + + if (desc->bLength < USB_DESCRIPTOR_SIZE) + break; + p += desc->bLength; + if (p > end) + break; + + if (desc->bDescriptorType != UDESC_INTERFACE) + continue; + idesc = (usb_interface_descriptor_t *)desc; + if (idesc->bLength < USB_INTERFACE_DESCRIPTOR_SIZE) + break; + + if (idesc->bInterfaceNumber != lastidx) { + lastidx = idesc->bInterfaceNumber; + curidx++; + curaidx = 0; + } else { + curaidx++; } + if (ifaceidx == curidx && altidx == curaidx) + return idesc; } + return NULL; } @@ -391,29 +403,39 @@ usbd_find_edesc(usb_config_descriptor_t { char *p = (char *)cd; char *end = p + UGETW(cd->wTotalLength); - usb_interface_descriptor_t *d; - usb_endpoint_descriptor_t *e; + usb_interface_descriptor_t *idesc; + usb_endpoint_descriptor_t *edesc; + usb_descriptor_t *desc; int curidx; - d = usbd_find_idesc(cd, ifaceidx, altidx); - if (d == NULL) + idesc = usbd_find_idesc(cd, ifaceidx, altidx); + if (idesc == NULL) return NULL; - if (endptidx >= d->bNumEndpoints) /* quick exit */ + if (endptidx >= idesc->bNumEndpoints) /* quick exit */ return NULL; curidx = -1; - for (p = (char *)d + d->bLength; p < end; ) { - e = (usb_endpoint_descriptor_t *)p; - if (e->bLength == 0) - break; /* bad descriptor */ - p += e->bLength; - if (p <= end && e->bDescriptorType == UDESC_INTERFACE) - return NULL; - if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) { - curidx++; - if (curidx == endptidx) - return e; - } + for (p = (char *)idesc + idesc->bLength; p < end; ) { + desc = (usb_descriptor_t *)p; + + if (desc->bLength < USB_DESCRIPTOR_SIZE) + break; + p += desc->bLength; + if (p > end) + break; + + if (desc->bDescriptorType == UDESC_INTERFACE) + break; + if (desc->bDescriptorType != UDESC_ENDPOINT) + continue; + + edesc = (usb_endpoint_descriptor_t *)desc; + if (edesc->bLength < USB_ENDPOINT_DESCRIPTOR_SIZE) + break; + + curidx++; + if (curidx == endptidx) + return edesc; } return NULL; }