⬢ DragonFlyBSD Kernel Audit
DF-2269 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/cam/scsi/scsi_cd.c	2026-10-17 22:22:48.092532984 +0000
+++ b/sys/bus/cam/scsi/scsi_cd.c	2026-10-17 22:22:55.188442336 +0000
@@ -4281,12 +4281,39 @@
 		break;
 	}
 	default:
-		/*
-		 * Tell the user what the overall length is, no matter
-		 * what we can actually fit in the data buffer.
-		 */
-		dvdstruct->length = length - ccb->csio.resid - 
-			sizeof(struct scsi_read_dvd_struct_data_header);
+		{
+			int transferred;
+
+			/*
+			 * The residual count is device-controlled.  A
+			 * drive that returns CAM_REQ_CMP with a short
+			 * transfer that never covered the 4-byte header,
+			 * or with a resid larger than the allocation,
+			 * would wrap this unsigned subtraction to ~4G
+			 * and make the bcopy below run off the databuf.
+			 * Compute the transferred count with checked
+			 * unsigned math and reject anything that cannot
+			 * yield a sane payload length.
+			 */
+			if (ccb->csio.resid > (u_int32_t)length) {
+				error = EIO;
+				break;
+			}
+			transferred = length - (u_int32_t)ccb->csio.resid;
+			if (transferred <
+			    (int)sizeof(struct scsi_read_dvd_struct_data_header)) {
+				error = EIO;
+				break;
+			}
+
+			/*
+			 * Tell the user what the overall length is, no
+			 * matter what we can actually fit in the data
+			 * buffer.
+			 */
+			dvdstruct->length = transferred -
+			    sizeof(struct scsi_read_dvd_struct_data_header);
+		}
 
 		/*
 		 * But only actually copy out the smaller of what we read