Skip to content

Commit 02eca83

Browse files
committed
ASoC: SOF: ipc3-control: Fix heap overflow in bytes_ext put/get
The ipc_control_data buffer is allocated as kzalloc(max_size), where max_size covers the entire struct sof_ipc_ctrl_data including its flexible array payload. However, the bounds checks in bytes_ext_put and _bytes_ext_get compared user data lengths against max_size directly, ignoring that cdata->data sits at an offset of sizeof(struct sof_ipc_ctrl_data) bytes into the allocation. This allowed writing up to sizeof(struct sof_ipc_ctrl_data) bytes past the end of the heap buffer from unprivileged userspace via the ALSA TLV kcontrol interface, and similarly allowed over-reading adjacent heap data on the get path. Fix all bounds checks to subtract sizeof(*cdata) from max_size so they reflect the actual space available at the cdata->data offset. Also fix the error-path restore in bytes_ext_put which wrote to cdata->data instead of cdata, causing the same overflow. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent cd7e8dc commit 02eca83

1 file changed

Lines changed: 10 additions & 7 deletions

File tree

sound/soc/sof/ipc3-control.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,9 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
389389
}
390390

391391
/* be->max is coming from topology */
392-
if (header.length > scontrol->max_size) {
392+
if (header.length > scontrol->max_size - sizeof(*cdata)) {
393393
dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n",
394-
header.length, scontrol->max_size);
394+
header.length, scontrol->max_size - sizeof(*cdata));
395395
return -EINVAL;
396396
}
397397

@@ -427,7 +427,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
427427
}
428428

429429
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
430-
if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
430+
if (cdata->data->size > scontrol->max_size - sizeof(*cdata) - sizeof(struct sof_abi_hdr)) {
431431
dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
432432
goto err_restore;
433433
}
@@ -443,7 +443,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
443443
err_restore:
444444
/* If we have an issue, we restore the old, valid bytes control data */
445445
if (scontrol->old_ipc_control_data) {
446-
memcpy(cdata->data, scontrol->old_ipc_control_data, scontrol->max_size);
446+
memcpy(cdata, scontrol->old_ipc_control_data, scontrol->max_size);
447447
kfree(scontrol->old_ipc_control_data);
448448
scontrol->old_ipc_control_data = NULL;
449449
}
@@ -482,10 +482,13 @@ static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
482482
}
483483

484484
/* check data size doesn't exceed max coming from topology */
485-
if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
486-
dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
485+
if (cdata->data->size > scontrol->max_size - sizeof(*cdata) -
486+
sizeof(struct sof_abi_hdr)) {
487+
dev_err_ratelimited(scomp->dev,
488+
"User data size %d exceeds max size %zu\n",
487489
cdata->data->size,
488-
scontrol->max_size - sizeof(struct sof_abi_hdr));
490+
scontrol->max_size - sizeof(*cdata) -
491+
sizeof(struct sof_abi_hdr));
489492
return -EINVAL;
490493
}
491494

0 commit comments

Comments
 (0)