]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: SOF: validate probe info element counts
authorYousef Alhouseen <alhouseenyousef@gmail.com>
Sun, 28 Jun 2026 00:03:29 +0000 (02:03 +0200)
committerMark Brown <broonie@kernel.org>
Wed, 1 Jul 2026 12:11:59 +0000 (13:11 +0100)
Probe information replies contain a firmware-provided element count. IPC3
uses that count to copy an array, then returns the unchecked count to its
caller. A short reply can therefore make the caller walk beyond the copied
array.

IPC4 similarly uses the count both to allocate the destination array and
to walk the reply. On 32-bit systems the allocation size can wrap, while on
all systems an excessive count reads beyond the reply payload.

Validate each count against the actual reply size before copying or
allocating the array, and use kcalloc() for the IPC4 allocation.

Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Link: https://patch.msgid.link/20260628000329.18606-1-alhouseenyousef@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/sof-client-probes-ipc3.c
sound/soc/sof/sof-client-probes-ipc4.c

index a78ec0954a6188362d6dd9fd48f133bdd5fe8dce..a3e382d6161f1287c2ace0a46133ed681a7c9d7b 100644 (file)
@@ -107,7 +107,7 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
        struct device *dev = &cdev->auxdev.dev;
        struct sof_ipc_probe_info_params msg = {{{0}}};
        struct sof_ipc_probe_info_params *reply;
-       size_t bytes;
+       size_t bytes, elem_size, payload_size;
        int ret;
 
        *params = NULL;
@@ -128,14 +128,29 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
        if (ret < 0 || reply->rhdr.error < 0)
                goto exit;
 
+       payload_size = reply->rhdr.hdr.size;
+       if (payload_size < offsetof(struct sof_ipc_probe_info_params, dma)) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
        if (!reply->num_elems)
                goto exit;
 
        if (cmd == SOF_IPC_PROBE_DMA_INFO)
-               bytes = sizeof(reply->dma[0]);
+               elem_size = sizeof(reply->dma[0]);
        else
-               bytes = sizeof(reply->desc[0]);
-       bytes *= reply->num_elems;
+               elem_size = sizeof(reply->desc[0]);
+
+       payload_size -= offsetof(struct sof_ipc_probe_info_params, dma);
+       if (reply->num_elems > payload_size / elem_size) {
+               dev_err(dev, "%s: invalid probe info element count %u\n",
+                       __func__, reply->num_elems);
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       bytes = reply->num_elems * elem_size;
        *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
        if (!*params) {
                ret = -ENOMEM;
index 88397c7dc4c37cb3e15d3d971179f4dfee2c7783..2eef32b55395403ddcf905a5bfcc38672da9a290 100644 (file)
@@ -248,10 +248,19 @@ static int ipc4_probes_points_info(struct sof_client_dev *cdev,
                return ret;
        }
        info = msg.data_ptr;
+       if (msg.data_size < sizeof(*info) ||
+           info->num_elems > (msg.data_size - sizeof(*info)) /
+                             sizeof(info->points[0])) {
+               dev_err(dev, "%s: invalid probe info element count %u\n",
+                       __func__, info->num_elems);
+               kfree(msg.data_ptr);
+               return -EINVAL;
+       }
+
        *num_desc = info->num_elems;
        dev_dbg(dev, "%s: got %zu probe points", __func__, *num_desc);
 
-       *desc = kzalloc(*num_desc * sizeof(**desc), GFP_KERNEL);
+       *desc = kcalloc(*num_desc, sizeof(**desc), GFP_KERNEL);
        if (!*desc) {
                kfree(msg.data_ptr);
                return -ENOMEM;