From 87962114cdc5fb3fddb3e66d62dd206f0170b9ce Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 11 Jun 2026 15:20:28 +0300 Subject: [PATCH 1/2] ipc4: large_config: fix data_off_size underflow on init-only block ipc4_set_vendor_config_module_instance() only validated data_off_size in the bursted-config path (init_block && final_block). The else path with init_block == 1 && final_block == 0 unconditionally executed: data += sizeof(struct sof_tlv); data_off_size -= sizeof(struct sof_tlv); data_off_size is a host-controlled 20-bit field taken straight from the IPC message. When it is smaller than sizeof(struct sof_tlv) (8) the subtraction underflows and wraps to a value close to 0xFFFFFFFF, which is then forwarded as the length to the module's set_large_config() handler. The actual backing buffer is only the MAILBOX_HOSTBOX_SIZE mailbox, so a compromised host could trigger out-of-bounds reads of DSP SRAM (and possible corruption depending on the target module) by sending MOD_LARGE_CONFIG_SET with init_block=1, final_block=0 and data_off_size < 8. Hoist the existing "data_off_size < sizeof(struct sof_tlv) || data_off_size > MAILBOX_HOSTBOX_SIZE" bounds check to the top of the function so it runs for every entry, before any pointer or size arithmetic. The duplicate check in the bursted-config branch is removed as it is now covered by the hoisted one. Signed-off-by: Jyri Sarha --- src/ipc/ipc4/handler-user.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 5a5f3d6d6f32..16becf73d532 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -1109,15 +1109,15 @@ __cold static int ipc4_set_vendor_config_module_instance(struct comp_dev *dev, assert_can_be_cold(); + /* Validate host-controlled payload size before any use or arithmetic. */ + if (data_off_size > MAILBOX_HOSTBOX_SIZE) + return IPC4_INVALID_CONFIG_DATA_STRUCT; + if (init_block && data_off_size < sizeof(struct sof_tlv)) + return IPC4_INVALID_CONFIG_DATA_STRUCT; + /* Old FW comment: bursted configs */ if (init_block && final_block) { const struct sof_tlv *tlv = (struct sof_tlv *)data; - /* if there is no payload in this large config set - * (4 bytes type | 4 bytes length=0 | no value) - * we do not handle such case - */ - if (data_off_size < sizeof(struct sof_tlv) || data_off_size > MAILBOX_HOSTBOX_SIZE) - return IPC4_INVALID_CONFIG_DATA_STRUCT; /* ===Iterate over payload=== * Payload can have multiple sof_tlv structures inside, From 3ca57ac52a6ca8d1b135a466bc849fc46d0f81f4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 11 Jun 2026 14:49:15 +0300 Subject: [PATCH 2/2] ipc4: chain_dma: fix use-after-free on chain DMA deallocate ipc4_process_chain_dma() called ipc4_chain_dma_state() and then, on the deallocate path (allocate == 0 && enable == 0), unconditionally executed list_item_del(&cdma_comp->list). However, on that same deallocate path ipc4_chain_dma_state() already unlinks the matching ipc_comp_dev from ipc->comp_list and frees it with rfree(): list_item_del(&icd->list); rfree(icd); Since icd is the same object as cdma_comp, the subsequent list_item_del(&cdma_comp->list) in the caller dereferenced and wrote to already-freed memory (prev->next / next->prev), a use-after-free. With heap grooming a host sending GLB_CHAIN_DMA with allocate=0/enable=0 on an existing chain could turn this into controlled heap corruption. The unlink-before-free is already handled correctly by ipc4_chain_dma_state(), so the duplicate list_item_del() in the caller is both redundant and unsafe. Remove it. Signed-off-by: Jyri Sarha --- src/ipc/ipc4/handler-user.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 16becf73d532..e98baa5121af 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -611,9 +611,6 @@ __cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) if (ret < 0) return IPC4_INVALID_CHAIN_STATE_TRANSITION; - if (!cdma.primary.r.allocate && !cdma.primary.r.enable) - list_item_del(&cdma_comp->list); - return IPC4_SUCCESS; #else return IPC4_UNAVAILABLE;