Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Introduce USB_DESCRIPTOR_SIZE (3), and fix two b...



details:   https://anonhg.NetBSD.org/src/rev/7ab38a84d5e3
branches:  trunk
changeset: 458691:7ab38a84d5e3
user:      maxv <maxv%NetBSD.org@localhost>
date:      Wed Aug 07 08:47:09 2019 +0000

description:
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@

diffstat:

 sys/dev/usb/usb.h      |   3 +-
 sys/dev/usb/usb_subr.c |  92 ++++++++++++++++++++++++++++++-------------------
 2 files changed, 59 insertions(+), 36 deletions(-)

diffs (150 lines):

diff -r 3e9d754a52dd -r 7ab38a84d5e3 sys/dev/usb/usb.h
--- a/sys/dev/usb/usb.h Wed Aug 07 08:16:24 2019 +0000
+++ b/sys/dev/usb/usb.h Wed Aug 07 08:47:09 2019 +0000
@@ -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 @@
        uByte           bDescriptorType;
        uByte           bDescriptorSubtype;
 } UPACKED usb_descriptor_t;
+#define USB_DESCRIPTOR_SIZE 3
 
 typedef struct {
        uByte           bLength;
diff -r 3e9d754a52dd -r 7ab38a84d5e3 sys/dev/usb/usb_subr.c
--- a/sys/dev/usb/usb_subr.c    Wed Aug 07 08:16:24 2019 +0000
+++ b/sys/dev/usb/usb_subr.c    Wed Aug 07 08:47:09 2019 +0000
@@ -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 @@
        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 @@
 {
        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;
 }



Home | Main Index | Thread Index | Old Index