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;