DragonFlyBSD Kernel Audit
DF-1011 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/u4b/uvc/uvc_drv.c b/sys/bus/u4b/uvc/uvc_drv.c
--- a/sys/bus/u4b/uvc/uvc_drv.c
+++ b/sys/bus/u4b/uvc/uvc_drv.c
@@ -1671,7 +1671,7 @@
 	struct uvc_vs_frame_desc *fdesc;
 	struct uvc_vs_frame_based_desc *fbdesc;
 	uint32_t size;
-	uint16_t nfmt, nfrm, nitv;
+	uint32_t nfmt, nfrm, nitv;     /* DF-1011: was uint16_t -> nitv wraps */
 
 	nfmt = nfrm = nitv = 0;
 	desc = NULL;
@@ -1701,12 +1701,24 @@
 				break;
 		case UDESCSUB_VS_FRAME_MJPEG:
 			fdesc = (struct uvc_vs_frame_desc *)desc;
+			/* DF-1011: bFrameIntervalType is a device-controlled uByte that
+			 * claims how many dFrameInterval[] entries follow the 26-byte
+			 * frame header.  Validate it against bLength so the parse loop
+			 * does not read past this descriptor (and so the summed nitv
+			 * cannot be inflated to wrap the allocator). */
+			if (fdesc->bLength < 26 ||
+			    fdesc->bFrameIntervalType > (fdesc->bLength - 26) / 4)
+				return EINVAL;
 			nfrm++;
 			nitv += (fdesc->bFrameIntervalType > 0) ?
 				fdesc->bFrameIntervalType : 3;
 			break;
 		case UDESCSUB_VS_FRAME_FRAME_BASED:
 			fbdesc = (struct uvc_vs_frame_based_desc *)desc;
+			/* DF-1011: frame-based header is 30 bytes before dFrameInterval[]. */
+			if (fbdesc->bLength < 30 ||
+			    fbdesc->bFrameIntervalType > (fbdesc->bLength - 30) / 4)
+				return EINVAL;
 			nfrm++;
 			nitv += (fbdesc->bFrameIntervalType > 0) ?
 				fbdesc->bFrameIntervalType : 3;
diff --git a/sys/bus/u4b/uvc/uvc_drv.h b/sys/bus/u4b/uvc/uvc_drv.h
--- a/sys/bus/u4b/uvc/uvc_drv.h
+++ b/sys/bus/u4b/uvc/uvc_drv.h
@@ -659,9 +659,9 @@
 	struct usb_xfer	*xfer[UVC_N_BULKTRANSFER];
 
 /* data format */
-	uint8_t nfmt;
-	uint8_t nfrm;
-	uint8_t nitv;
+	uint32_t nfmt;       /* DF-1011: was uint8_t, truncated on store */
+	uint32_t nfrm;       /* DF-1011: was uint8_t, truncated on store */
+	uint32_t nitv;       /* DF-1011: was uint8_t, truncated on store */
 	uint8_t unuse[3];
 	struct uvc_data_format *fmt;
 };