From 216e50d8dd3a22a1c41ea5e23a79f14242d9865d Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Mon, 27 Jul 2026 23:02:23 +0200 Subject: [PATCH] audio: copier: bound ALH mapping count to the gateway config size copier_alh_assign_dai_index() reads alh_cfg.count from the host-supplied gateway config blob and walks alh_cfg.mapping[0..count). Count was only bounded by the mapping[] array size, not the actual blob size, so a malformed blob could make the mapping walk read past config_data and underflow dma_config_length in the HDA branch. Validate that the blob contains the fixed header before reading count, then ensure count is within the mapping[] bound and that its computed ALH configuration size fits in the blob. This rejects malformed configurations before any mapping[] access. HDA always reads mapping[0], including for a single gateway. Reject a zero count in this path so a header-only blob cannot cause that out-of-bounds read. Keep zero-count behavior unchanged for single ALH, which does not access mapping[]. Use %zu when logging blob_size to preserve size_t values on 64-bit builds. Signed-off-by: Tomasz Leman --- src/audio/copier/copier_dai.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 109bc2a4a6b2..0e54c0c7a9e5 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -77,7 +77,8 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, struct copier_data *cd = module_get_private_data(mod); const struct sof_alh_configuration_blob *alh_blob = gtw_cfg_data; uint8_t *dma_config; - size_t alh_cfg_size, dma_config_length; + size_t alh_cfg_size, dma_config_length, blob_size; + uint32_t alh_count; int i, dai_num, ret; if (!cd->config.gtw_cfg.config_length) { @@ -85,20 +86,29 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, return -EINVAL; } + blob_size = (size_t)cd->config.gtw_cfg.config_length << 2; + if (blob_size < sizeof(alh_blob->gtw_attributes) + sizeof(alh_blob->alh_cfg.count)) { + comp_err(mod->dev, "Invalid ALH gateway config: blob=%zu bytes", blob_size); + return -EINVAL; + } + + alh_count = alh_blob->alh_cfg.count; + if (alh_count > IPC4_ALH_MAX_NUMBER_OF_GTW || + get_alh_config_size(alh_blob) > blob_size) { + comp_err(mod->dev, "Invalid ALH gateway config: count=%u, blob=%zu bytes", + alh_count, blob_size); + return -EINVAL; + } + alh_cfg_size = get_alh_config_size(alh_blob); + switch (dai->type) { case SOF_DAI_INTEL_HDA: /* We use DAI_INTEL_HDA for ACE 2.0 platforms */ - /* - * alh_cfg.count is host-controlled and scales the config size - * and mapping[] walk below; bound it before any arithmetic so a - * crafted blob cannot read past the gateway config. - */ - if (alh_blob->alh_cfg.count > IPC4_ALH_MAX_NUMBER_OF_GTW) { + if (!alh_count) { comp_err(mod->dev, "Invalid ALH count: %u", - alh_blob->alh_cfg.count); + alh_count); return -EINVAL; } - alh_cfg_size = get_alh_config_size(alh_blob); dma_config = (uint8_t *)gtw_cfg_data + alh_cfg_size; dma_config_length = (cd->config.gtw_cfg.config_length << 2) - alh_cfg_size;