DragonFlyBSD Kernel Audit
DF-2506 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/nata/atapi-cd.c b/sys/dev/disk/nata/atapi-cd.c
--- a/sys/dev/disk/nata/atapi-cd.c
+++ b/sys/dev/disk/nata/atapi-cd.c
@@ -1315,8 +1315,13 @@
 {
     struct acd_softc *cdp = device_get_ivars(dev);
     struct write_param param;
-    int8_t ccb[16] = { ATAPI_SEND_CUE_SHEET, 0, 0, 0, 0, 0, 
-		       cuesheet->len>>16, cuesheet->len>>8, cuesheet->len,
+    /* cuesheet is a raw user pointer and ->len is currently fetched four
+     * times (CCB, kmalloc, copyin, bytecount).  Snapshot it once so a race
+     * cannot make copyin() write past the kmalloc'd M_ACD buffer.  See
+     * DF-2506. */
+    int32_t cue_len = cuesheet->len;
+    int8_t ccb[16] = { ATAPI_SEND_CUE_SHEET, 0, 0, 0, 0, 0,
+		       cue_len>>16, cue_len>>8, cue_len,
 		       0, 0, 0, 0, 0, 0, 0 };
     int8_t *buffer;
     int32_t error;
@@ -1342,11 +1347,11 @@
     if ((error = acd_mode_select(dev, (caddr_t)&param, param.page_length + 10)))
 	return error;
 
-    if (!(buffer = kmalloc(cuesheet->len, M_ACD, M_WAITOK | M_NULLOK)))
+    if (!(buffer = kmalloc(cue_len, M_ACD, M_WAITOK | M_NULLOK)))
 	return ENOMEM;
 
-    if (!(error = copyin(cuesheet->entries, buffer, cuesheet->len)))
-	error = ata_atapicmd(dev, ccb, buffer, cuesheet->len, 0, 30);
+    if (!(error = copyin(cuesheet->entries, buffer, cue_len)))
+	error = ata_atapicmd(dev, ccb, buffer, cue_len, 0, 30);
     kfree(buffer, M_ACD);
     return error;
 }