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 @@ -495,6 +495,12 @@ struct ioc_read_subchannel *args = (struct ioc_read_subchannel *)ap->a_data; u_int8_t format; + /* args is the raw user pointer; snapshot data_len into a local + * immediately after validation and use it for the final copyout so + * a concurrent mutation of the userspace value (TOCTOU) cannot + * enlarge the copy past the 24-byte cdp->subchan and leak adjacent + * kernel heap. See DF-2503. */ + int data_len; int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0, sizeof(cdp->subchan)>>8, sizeof(cdp->subchan), 0, 0, 0, 0, 0, 0, 0 }; @@ -504,6 +510,7 @@ error = EINVAL; break; } + data_len = args->data_len; format = args->data_format; if ((format != CD_CURRENT_POSITION) && @@ -534,10 +541,10 @@ } } if (nocopyout == 0) { - error = copyout(&cdp->subchan, args->data, args->data_len); + error = copyout(&cdp->subchan, args->data, data_len); } else { error = 0; - bcopy(&cdp->subchan, args->data, args->data_len); + bcopy(&cdp->subchan, args->data, data_len); } } break;