Module Name: src
Committed By: maxv
Date: Sun Sep 15 09:21:36 UTC 2019
Modified Files:
src/sys/dev/usb: uvideo.c
Log Message:
Add missing length checks on descriptors, to prevent buffer overflows.
Found via KASAN+vHCI. Some remain however, but it looks like the code
needs to be re-thought along the way, so it will be fixed later.
To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/sys/dev/usb/uvideo.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/uvideo.c
diff -u src/sys/dev/usb/uvideo.c:1.47 src/sys/dev/usb/uvideo.c:1.48
--- src/sys/dev/usb/uvideo.c:1.47 Sun May 5 03:17:54 2019
+++ src/sys/dev/usb/uvideo.c Sun Sep 15 09:21:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: uvideo.c,v 1.47 2019/05/05 03:17:54 mrg Exp $ */
+/* $NetBSD: uvideo.c,v 1.48 2019/09/15 09:21:36 maxv Exp $ */
/*
* Copyright (c) 2008 Patrick Mahoney
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvideo.c,v 1.47 2019/05/05 03:17:54 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvideo.c,v 1.48 2019/09/15 09:21:36 maxv Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -527,6 +527,12 @@ uvideo_attach(device_t parent, device_t
(ifdesc = usb_desc_iter_next_interface(&iter)) != NULL;
++ifaceidx)
{
+ if (ifdesc->bLength < USB_INTERFACE_DESCRIPTOR_SIZE) {
+ DPRINTFN(50, ("uvideo_attach: "
+ "ignoring incorrect descriptor len=%d\n",
+ ifdesc->bLength));
+ continue;
+ }
if (ifdesc->bInterfaceClass != UICLASS_VIDEO) {
DPRINTFN(50, ("uvideo_attach: "
"ignoring non-uvc interface: "
@@ -884,13 +890,17 @@ uvideo_unit_init(struct uvideo_unit *vu,
switch (desc->bDescriptorSubtype) {
case UDESC_INPUT_TERMINAL:
+ if (desc->bLength < sizeof(*input))
+ return USBD_INVAL;
input = (const uvideo_input_terminal_descriptor_t *)desc;
switch (UGETW(input->wTerminalType)) {
case UVIDEO_ITT_CAMERA:
+ if (desc->bLength < sizeof(*camera))
+ return USBD_INVAL;
camera =
(const uvideo_camera_terminal_descriptor_t *)desc;
- ct = &vu->u.vu_camera;
+ ct = &vu->u.vu_camera;
ct->ct_objective_focal_min =
UGETW(camera->wObjectiveFocalLengthMin);
ct->ct_objective_focal_max =
@@ -911,12 +921,16 @@ uvideo_unit_init(struct uvideo_unit *vu,
case UDESC_OUTPUT_TERMINAL:
break;
case UDESC_SELECTOR_UNIT:
+ if (desc->bLength < sizeof(*selector))
+ return USBD_INVAL;
selector = (const uvideo_selector_unit_descriptor_t *)desc;
uvideo_unit_alloc_sources(vu, selector->bNrInPins,
selector->baSourceID);
break;
case UDESC_PROCESSING_UNIT:
+ if (desc->bLength < sizeof(*processing))
+ return USBD_INVAL;
processing = (const uvideo_processing_unit_descriptor_t *)desc;
pu = &vu->u.vu_processing;
@@ -928,6 +942,8 @@ uvideo_unit_init(struct uvideo_unit *vu,
processing->bmControls);
break;
case UDESC_EXTENSION_UNIT:
+ if (desc->bLength < sizeof(*extension))
+ return USBD_INVAL;
extension = (const uvideo_extension_unit_descriptor_t *)desc;
/* TODO: copy guid */
@@ -1081,6 +1097,9 @@ uvideo_stream_init(struct uvideo_stream
* interface descriptor, modifying the iterator. This may be called
* multiple times because there may be several alternate interfaces
* associated with the same interface number. */
+/*
+ * XXX XXX XXX: This function accesses descriptors in an unsafe manner.
+ */
static usbd_status
uvideo_stream_init_desc(struct uvideo_stream *vs,
const usb_interface_descriptor_t *ifdesc,