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)¶m, 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; }