DragonFlyBSD Kernel Audit
DF-2348 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/bus/u4b/uvc/uvc_buf.c b/sys/bus/u4b/uvc/uvc_buf.c
--- a/sys/bus/u4b/uvc/uvc_buf.c
+++ b/sys/bus/u4b/uvc/uvc_buf.c
@@ -104,16 +104,21 @@
 static __inline int
 uvc_buf_queue_mmap_locked(struct uvc_buf_queue *bq, vm_paddr_t *paddr, vm_offset_t offset)
 {
-	 uint64_t max_offset = (uint64_t)(bq->buf_size * bq->buf_count) - PAGE_SIZE;
+	 uint64_t total, max_offset;
 
 	if (bq->mem == NULL)
 		return EINVAL;
 
-	if (offset < 0)
+	/* Guard against overflow/underflow: a malicious webcam can report
+	   dwMaxVideoSize=0 (kmalloc(0)=ZERO_LENGTH_PTR, buf_size=0) which made
+	   the old 'max_offset < 0' check a dead unsigned comparison. */
+	if (bq->buf_count != 0 &&
+	    bq->buf_size > (uint64_t)-1 / bq->buf_count)
 		return EINVAL;
-
-	if (max_offset < 0)
+	total = (uint64_t)bq->buf_size * bq->buf_count;
+	if (total < PAGE_SIZE)
 		return EINVAL;
+	max_offset = total - PAGE_SIZE;
 
 	if (offset > max_offset) {
 		kprintf("WARNING: %s offset out of bound: %ld\n; max: %ld",