⬢ DragonFlyBSD Kernel Audit
DF-5550 / fix.diff
← back to finding ↓ download raw
diff --git a/a/sys/bus/cam/cam_queue.c b/b/sys/bus/cam/cam_queue.c
index ec2f9fd..0291676 100644
--- a/a/sys/bus/cam/cam_queue.c
+++ b/b/sys/bus/cam/cam_queue.c
@@ -113,11 +113,20 @@ camq_resize(struct camq *queue, int new_size)
 {
 	cam_pinfo **new_array;
 
-#ifdef DIAGNOSTIC
+	/*
+	 * Security fix (DF-5550): the old #ifdef DIAGNOSTIC-only guard is
+	 * compiled out of stock kernels (DIAGNOSTIC is not set even in
+	 * INVARIANTS builds).  A caller that shrinks below the number of
+	 * queued entries -- xpt_remove_periph() does exactly that for a
+	 * periph still on device->drvq (camperiphfree never dequeues it,
+	 * and nothing guards the shrink the way xpt_release_device
+	 * panics for the devq queues) -- made the bcopy below write
+	 * entries*8 bytes into a new_size*8 allocation and left
+	 * entries > array_size so every later camq op indexed past the
+	 * array.  Refuse the shrink instead.
+	 */
 	if (new_size < queue->entries)
-		panic("camq_resize: New queue size can't accommodate "
-		      "queued entries.");
-#endif
+		return (CAM_RESRC_UNAVAIL);
 	new_array = kmalloc(new_size * sizeof(cam_pinfo *), M_CAMQ,
 			    M_INTWAIT | M_ZERO);
 
@@ -145,10 +154,17 @@ camq_resize(struct camq *queue, int new_size)
 void
 camq_insert(struct camq *queue, cam_pinfo *new_entry)
 {
-#ifdef DIAGNOSTIC
+	/*
+	 * Security fix (DF-5551): the full-queue guard was also
+	 * DIAGNOSTIC-only.  On stock kernels the insert below wrote
+	 * queue_array[array_size+1] -- a kernel pointer one slot past
+	 * the kmalloc'd array -- and set entries = array_size+1,
+	 * corrupting the heap and every subsequent queue operation.
+	 * Refuse the insert instead; the entry keeps
+	 * CAM_UNQUEUED_INDEX and callers re-schedule later.
+	 */
 	if (queue->entries >= queue->array_size)
-		panic("camq_insert: Attempt to insert into a full queue");
-#endif
+		return;
 	queue->entries++;
 	queue->queue_array[queue->entries] = new_entry;
 	new_entry->index = queue->entries;