⬢ DragonFlyBSD Kernel Audit
DF-5434 / fix.diff
← back to finding ↓ download raw
--- sys/bus/u4b/uvc/uvc_buf.c.orig
+++ sys/bus/u4b/uvc/uvc_buf.c
@@ -82,6 +82,8 @@
 #define UVC_LOCK(lkp)   lockmgr(lkp, LK_EXCLUSIVE)
 #define UVC_UNLOCK(lkp) lockmgr(lkp, LK_RELEASE)
 
+static void uvc_buf_queue_init_qbuf(struct uvc_buf *buf, int ind);
+
 #define FRAME_DUMP 0
 #if FRAME_DUMP
 static void uvc_writefile(char *path, void *data, int len);
@@ -517,11 +519,26 @@
 static void
 uvc_buf_queue_free_bufs_locked(struct uvc_buf_queue *bq)
 {
+	int i;
+
 	if (bq->mem) {
 		kfree(bq->mem, M_UVC);
 		bq->mem = NULL;
 		bq->buf_count = 0;
+		bq->buf_size = 0;
 	}
+
+	/*
+	 * The queues and per-buffer descriptors must not outlive the
+	 * backing buffer: a completion callback (uvc_buf_sell_buf /
+	 * uvc_bulkbuf_sell_buf) or a still-open mmap must never see a
+	 * stale buf->mem or a stale vbuf.bytesused.  Drain both STAILQs
+	 * and reset every descriptor.
+	 */
+	STAILQ_INIT(&bq->consumer);
+	STAILQ_INIT(&bq->product);
+	for (i = 0; i < UVC_BUF_MAX_BUFFERS; i++)
+		uvc_buf_queue_init_qbuf(bq->buf + i, i);
 }
 
 void
@@ -537,7 +554,7 @@
 int
 uvc_buf_queue_req_bufs(struct uvc_buf_queue *bq, uint32_t *count, uint32_t len)
 {
-	void *mem;
+	void *mem = NULL;
 	struct uvc_buf *buf;
 	int i, num, ret = 0;
 	unsigned long rl;
@@ -546,9 +563,8 @@
 	rl = round_page(len);
 	DPRINTF("page align size:%lu-real size:%u\n", rl, len);
 
-	num = *count;
-	if (num > UVC_BUF_MAX_BUFFERS)
-		num = UVC_BUF_MAX_BUFFERS;
+	/* unsigned clamp: counts >= 2^31 must clamp, not go negative */
+	num = (*count > UVC_BUF_MAX_BUFFERS) ? UVC_BUF_MAX_BUFFERS : *count;
 
 	UVC_LOCK(&bq->mtx);
 	uvc_buf_queue_free_bufs_locked(bq);
@@ -568,6 +584,7 @@
 
 	for (i = 0; i < num; i++) {
 		buf = bq->buf + i;
+		uvc_buf_queue_init_qbuf(buf, i);
 		buf->index = i;
 		buf->mem = mem;
 		buf->offset = i * rl;