Module Name: src
Committed By: riastradh
Date: Sun Mar 13 11:30:13 UTC 2022
Modified Files:
src/sys/dev/usb: usb_subr.c usbdi.c usbdi_util.c
Log Message:
usb: Parse descriptors a little more robustly.
- Avoid reading past the end in the event of bogus bLength.
- Avoid arithmetic overflow by rearranging inequalities.
Reported-by: [email protected]
To generate a diff of this commit:
cvs rdiff -u -r1.271 -r1.272 src/sys/dev/usb/usb_subr.c
cvs rdiff -u -r1.236 -r1.237 src/sys/dev/usb/usbdi.c
cvs rdiff -u -r1.84 -r1.85 src/sys/dev/usb/usbdi_util.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_subr.c
diff -u src/sys/dev/usb/usb_subr.c:1.271 src/sys/dev/usb/usb_subr.c:1.272
--- src/sys/dev/usb/usb_subr.c:1.271 Sun Mar 13 11:28:42 2022
+++ src/sys/dev/usb/usb_subr.c Sun Mar 13 11:30:12 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_subr.c,v 1.271 2022/03/13 11:28:42 riastradh Exp $ */
+/* $NetBSD: usb_subr.c,v 1.272 2022/03/13 11:30:12 riastradh 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.271 2022/03/13 11:28:42 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.272 2022/03/13 11:30:12 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@@ -326,7 +326,7 @@ usbd_find_idesc(usb_config_descriptor_t
usb_interface_descriptor_t *idesc;
int curidx, lastidx, curaidx = 0;
- for (curidx = lastidx = -1; p < end; ) {
+ for (curidx = lastidx = -1; end - p >= sizeof(*desc);) {
desc = (usb_descriptor_t *)p;
DPRINTFN(4, "idx=%jd(%jd) altidx=%jd(%jd)", ifaceidx, curidx,
@@ -336,15 +336,15 @@ usbd_find_idesc(usb_config_descriptor_t
if (desc->bLength < USB_DESCRIPTOR_SIZE)
break;
- p += desc->bLength;
- if (p > end)
+ if (desc->bLength > end - p)
break;
+ p += desc->bLength;
if (desc->bDescriptorType != UDESC_INTERFACE)
continue;
- idesc = (usb_interface_descriptor_t *)desc;
- if (idesc->bLength < USB_INTERFACE_DESCRIPTOR_SIZE)
+ if (desc->bLength < USB_INTERFACE_DESCRIPTOR_SIZE)
break;
+ idesc = (usb_interface_descriptor_t *)desc;
if (idesc->bInterfaceNumber != lastidx) {
lastidx = idesc->bInterfaceNumber;
@@ -378,23 +378,23 @@ usbd_find_edesc(usb_config_descriptor_t
return NULL;
curidx = -1;
- for (p = (char *)idesc + idesc->bLength; p < end; ) {
+ for (p = (char *)idesc + idesc->bLength; end - p >= sizeof(*edesc);) {
desc = (usb_descriptor_t *)p;
if (desc->bLength < USB_DESCRIPTOR_SIZE)
break;
- p += desc->bLength;
- if (p > end)
+ if (desc->bLength > end - p)
break;
+ p += desc->bLength;
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)
+ if (desc->bLength < USB_ENDPOINT_DESCRIPTOR_SIZE)
break;
+ edesc = (usb_endpoint_descriptor_t *)desc;
curidx++;
if (curidx == endptidx)
@@ -553,23 +553,26 @@ usbd_fill_iface_data(struct usbd_device
p = (char *)idesc + idesc->bLength;
end = (char *)dev->ud_cdesc + UGETW(dev->ud_cdesc->wTotalLength);
+ KASSERTMSG((char *)dev->ud_cdesc <= (char *)idesc, "cdesc=%p idesc=%p",
+ dev->ud_cdesc, idesc);
+ KASSERTMSG((char *)idesc < end, "idesc=%p end=%p", idesc, end);
#define ed ((usb_endpoint_descriptor_t *)p)
for (endpt = 0; endpt < nendpt; endpt++) {
DPRINTFN(10, "endpt=%jd", endpt, 0, 0, 0);
- for (; p < end; p += ed->bLength) {
+ for (; end - p >= sizeof(*ed); p += ed->bLength) {
DPRINTFN(10, "p=%#jx end=%#jx len=%jd type=%jd",
(uintptr_t)p, (uintptr_t)end, ed->bLength,
ed->bDescriptorType);
- if (p + ed->bLength <= end &&
- ed->bLength >= USB_ENDPOINT_DESCRIPTOR_SIZE &&
- ed->bDescriptorType == UDESC_ENDPOINT)
- goto found;
- if (ed->bLength == 0 ||
+ if (ed->bLength < sizeof(*ed) ||
+ ed->bLength > end - p ||
ed->bDescriptorType == UDESC_INTERFACE)
break;
+ if (ed->bLength >= USB_ENDPOINT_DESCRIPTOR_SIZE &&
+ ed->bDescriptorType == UDESC_ENDPOINT)
+ goto found;
}
/* passed end, or bad desc */
- if (p < end) {
+ if (end - p >= sizeof(*ed)) {
if (ed->bLength == 0) {
printf("%s: bad descriptor: 0 length\n",
__func__);
@@ -607,6 +610,8 @@ usbd_fill_iface_data(struct usbd_device
}
endpoints[endpt].ue_refcnt = 0;
endpoints[endpt].ue_toggle = 0;
+ KASSERTMSG(end - p >= ed->bLength, "p=%p end=%p length=%u",
+ p, end, ed->bLength);
p += ed->bLength;
}
#undef ed
Index: src/sys/dev/usb/usbdi.c
diff -u src/sys/dev/usb/usbdi.c:1.236 src/sys/dev/usb/usbdi.c:1.237
--- src/sys/dev/usb/usbdi.c:1.236 Sun Mar 13 11:29:01 2022
+++ src/sys/dev/usb/usbdi.c Sun Mar 13 11:30:13 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.c,v 1.236 2022/03/13 11:29:01 riastradh Exp $ */
+/* $NetBSD: usbdi.c,v 1.237 2022/03/13 11:30:13 riastradh Exp $ */
/*
* Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.236 2022/03/13 11:29:01 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.237 2022/03/13 11:30:13 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -976,10 +976,11 @@ usbd_get_no_alts(usb_config_descriptor_t
usb_interface_descriptor_t *d;
int n;
- for (n = 0; p < end; p += d->bLength) {
+ for (n = 0; end - p >= sizeof(*d); p += d->bLength) {
d = (usb_interface_descriptor_t *)p;
- if (p + d->bLength <= end &&
- d->bDescriptorType == UDESC_INTERFACE &&
+ if (d->bLength < sizeof(*d) || d->bLength > end - p)
+ break;
+ if (d->bDescriptorType == UDESC_INTERFACE &&
d->bInterfaceNumber == ifaceno)
n++;
}
Index: src/sys/dev/usb/usbdi_util.c
diff -u src/sys/dev/usb/usbdi_util.c:1.84 src/sys/dev/usb/usbdi_util.c:1.85
--- src/sys/dev/usb/usbdi_util.c:1.84 Tue Jun 16 17:25:56 2020
+++ src/sys/dev/usb/usbdi_util.c Sun Mar 13 11:30:13 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi_util.c,v 1.84 2020/06/16 17:25:56 maxv Exp $ */
+/* $NetBSD: usbdi_util.c,v 1.85 2022/03/13 11:30:13 riastradh Exp $ */
/*
* Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.84 2020/06/16 17:25:56 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.85 2022/03/13 11:30:13 riastradh Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -599,10 +599,11 @@ usbd_get_hid_descriptor(struct usbd_inte
p = (char *)idesc + idesc->bLength;
end = (char *)cdesc + UGETW(cdesc->wTotalLength);
- for (; p < end; p += hd->bLength) {
+ for (; end - p >= sizeof(*hd); p += hd->bLength) {
hd = (usb_hid_descriptor_t *)p;
- if (p + hd->bLength <= end &&
- hd->bLength >= USB_HID_DESCRIPTOR_SIZE(0) &&
+ if (hd->bLength < sizeof(*hd) || hd->bLength > end - p)
+ break;
+ if (hd->bLength >= USB_HID_DESCRIPTOR_SIZE(0) &&
hd->bDescriptorType == UDESC_HID)
return hd;
if (hd->bDescriptorType == UDESC_INTERFACE)
@@ -725,7 +726,7 @@ usb_desc_iter_peek(usbd_desc_iter_t *ite
{
const usb_descriptor_t *desc;
- if (iter->cur + sizeof(usb_descriptor_t) > iter->end) {
+ if (iter->end - iter->cur < sizeof(usb_descriptor_t)) {
if (iter->cur != iter->end)
printf("%s: bad descriptor\n", __func__);
return NULL;
@@ -735,7 +736,7 @@ usb_desc_iter_peek(usbd_desc_iter_t *ite
printf("%s: descriptor length too small\n", __func__);
return NULL;
}
- if (iter->cur + desc->bLength > iter->end) {
+ if (desc->bLength > iter->end - iter->cur) {
printf("%s: descriptor length too large\n", __func__);
return NULL;
}
@@ -748,6 +749,7 @@ usb_desc_iter_next(usbd_desc_iter_t *ite
const usb_descriptor_t *desc = usb_desc_iter_peek(iter);
if (desc == NULL)
return NULL;
+ KASSERT(desc->bLength <= iter->end - iter->cur);
iter->cur += desc->bLength;
return desc;
}