--- a/sys/bus/cam/scsi/scsi_cd.c 2026-10-01 22:57:28.582365539 +0000 +++ b/sys/bus/cam/scsi/scsi_cd.c 2026-10-01 22:57:28.594365386 +0000 @@ -3436,6 +3436,7 @@ */ if (error == 0) { u_int32_t data_len; + u_int32_t bd_len, hdr_size; if (data->cdb_size == 10) { struct scsi_mode_header_10 *hdr10; @@ -3443,12 +3444,16 @@ hdr10 = (struct scsi_mode_header_10 *)data->mode_buf; data_len = scsi_2btoul(hdr10->data_length); data_len += sizeof(hdr10->data_length); + bd_len = scsi_2btoul(hdr10->blk_desc_len); + hdr_size = sizeof(*hdr10); } else { struct scsi_mode_header_6 *hdr6; hdr6 = (struct scsi_mode_header_6 *)data->mode_buf; data_len = hdr6->data_length; data_len += sizeof(hdr6->data_length); + bd_len = hdr6->blk_desc_len; + hdr_size = sizeof(*hdr6); } /* @@ -3458,7 +3463,18 @@ * drive returns multiple block descriptors, or if it sets * the data length incorrectly. */ - if (data_len > data->alloc_len) { + /* + * The block descriptor length is likewise device + * controlled and feeds find_mode_page_*(), which derives + * the page pointer that the ioctl layer then reads and + * writes. Make sure header + block descriptors + the + * mode page the caller touches stays inside the + * allocation. + */ + if (data_len > data->alloc_len || + bd_len > data->alloc_len || + hdr_size + bd_len + sizeof(union cd_pages) > + data->alloc_len) { xpt_print(periph->path, "allocated modepage %d length " "%d < returned length %d\n", page, data->alloc_len, data_len);