summaryrefslogtreecommitdiff
path: root/sound/soc/sof/ipc3-control.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:17:26 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:17:26 +0200
commitb62ed4c93ad71374b54d2c3a72cbc67b506f580c (patch)
tree6ca6ab974bbce902fc9de300fea6aa056170850f /sound/soc/sof/ipc3-control.c
parent5895db67c12464003afd16c08049b73aa09e58ea (diff)
parent221fc2f4d0eda59d02af2e751a9282fa013a8e97 (diff)
Merge v6.18.40linux-rolling-lts
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound/soc/sof/ipc3-control.c')
-rw-r--r--sound/soc/sof/ipc3-control.c79
1 files changed, 60 insertions, 19 deletions
diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c
index 2b1befad6d5c..d1697401b1da 100644
--- a/sound/soc/sof/ipc3-control.c
+++ b/sound/soc/sof/ipc3-control.c
@@ -315,10 +315,13 @@ static int sof_ipc3_bytes_get(struct snd_sof_control *scontrol,
}
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
- if (data->size > scontrol->max_size - sizeof(*data)) {
+ if (data->size > scontrol->max_size - sizeof(*cdata) -
+ sizeof(*data)) {
dev_err_ratelimited(scomp->dev,
"%u bytes of control data is invalid, max is %zu\n",
- data->size, scontrol->max_size - sizeof(*data));
+ data->size,
+ scontrol->max_size - sizeof(*cdata) -
+ sizeof(*data));
return -EINVAL;
}
@@ -336,6 +339,8 @@ static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_abi_hdr *data = cdata->data;
+ const struct sof_abi_hdr *new_hdr =
+ (const struct sof_abi_hdr *)ucontrol->value.bytes.data;
size_t size;
if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
@@ -344,14 +349,18 @@ static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
return -EINVAL;
}
- /* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
- if (data->size > scontrol->max_size - sizeof(*data)) {
- dev_err_ratelimited(scomp->dev, "data size too big %u bytes max is %zu\n",
- data->size, scontrol->max_size - sizeof(*data));
+ /* Validate the new data's size, not the old one */
+ if (new_hdr->size > scontrol->max_size - sizeof(*cdata) -
+ sizeof(*new_hdr)) {
+ dev_err_ratelimited(scomp->dev,
+ "data size too big %u bytes max is %zu\n",
+ new_hdr->size,
+ scontrol->max_size - sizeof(*cdata) -
+ sizeof(*new_hdr));
return -EINVAL;
}
- size = data->size + sizeof(*data);
+ size = new_hdr->size + sizeof(*new_hdr);
/* copy from kcontrol */
memcpy(data, ucontrol->value.bytes.data, size);
@@ -389,9 +398,17 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
}
/* be->max is coming from topology */
- if (header.length > scontrol->max_size) {
- dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n",
- header.length, scontrol->max_size);
+ if (header.length > scontrol->max_size - sizeof(*cdata)) {
+ dev_err_ratelimited(scomp->dev, "Bytes data size %u exceeds max %zu\n",
+ header.length, scontrol->max_size - sizeof(*cdata));
+ return -EINVAL;
+ }
+
+ /* Ensure the data is large enough to contain the ABI header */
+ if (header.length < sizeof(struct sof_abi_hdr)) {
+ dev_err_ratelimited(scomp->dev,
+ "Bytes data size %u less than ABI header %zu\n",
+ header.length, sizeof(struct sof_abi_hdr));
return -EINVAL;
}
@@ -427,7 +444,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
}
/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
- if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
+ if (cdata->data->size > scontrol->max_size - sizeof(*cdata) - sizeof(struct sof_abi_hdr)) {
dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
goto err_restore;
}
@@ -443,7 +460,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
err_restore:
/* If we have an issue, we restore the old, valid bytes control data */
if (scontrol->old_ipc_control_data) {
- memcpy(cdata->data, scontrol->old_ipc_control_data, scontrol->max_size);
+ memcpy(cdata, scontrol->old_ipc_control_data, scontrol->max_size);
kfree(scontrol->old_ipc_control_data);
scontrol->old_ipc_control_data = NULL;
}
@@ -482,10 +499,13 @@ static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
}
/* check data size doesn't exceed max coming from topology */
- if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
- dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
+ if (cdata->data->size > scontrol->max_size - sizeof(*cdata) -
+ sizeof(struct sof_abi_hdr)) {
+ dev_err_ratelimited(scomp->dev,
+ "User data size %u exceeds max size %zu\n",
cdata->data->size,
- scontrol->max_size - sizeof(struct sof_abi_hdr));
+ scontrol->max_size - sizeof(*cdata) -
+ sizeof(struct sof_abi_hdr));
return -EINVAL;
}
@@ -535,6 +555,15 @@ static void snd_sof_update_control(struct snd_sof_control *scontrol,
return;
}
+ /* Verify the size fits within the allocation */
+ if (cdata->num_elems > scontrol->max_size - sizeof(*local_cdata) -
+ sizeof(*local_cdata->data)) {
+ dev_err(scomp->dev,
+ "cdata binary size %u exceeds buffer\n",
+ cdata->num_elems);
+ return;
+ }
+
/* copy the new binary data */
memcpy(local_cdata->data, cdata->data, cdata->num_elems);
} else if (cdata->num_elems != scontrol->num_channels) {
@@ -626,16 +655,28 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_
return;
}
- expected_size = sizeof(struct sof_ipc_ctrl_data);
switch (cdata->type) {
case SOF_CTRL_TYPE_VALUE_CHAN_GET:
case SOF_CTRL_TYPE_VALUE_CHAN_SET:
- expected_size += cdata->num_elems *
- sizeof(struct sof_ipc_ctrl_value_chan);
+ if (check_mul_overflow((size_t)cdata->num_elems,
+ sizeof(struct sof_ipc_ctrl_value_chan),
+ &expected_size))
+ return;
+ if (check_add_overflow(expected_size,
+ sizeof(struct sof_ipc_ctrl_data),
+ &expected_size))
+ return;
break;
case SOF_CTRL_TYPE_DATA_GET:
case SOF_CTRL_TYPE_DATA_SET:
- expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr);
+ if (check_add_overflow((size_t)cdata->num_elems,
+ sizeof(struct sof_abi_hdr),
+ &expected_size))
+ return;
+ if (check_add_overflow(expected_size,
+ sizeof(struct sof_ipc_ctrl_data),
+ &expected_size))
+ return;
break;
default:
return;