Skip to content

Commit d61abab

Browse files
committed
ipc4: basefw_set_fw_config: validate TLV size
basefw_set_fw_config() cast the IPC payload directly to struct sof_tlv* and read tlv->type without checking that the reported payload length (data_offset) was sufficient. A zero-length or undersized LargeConfigSet with param_id=IPC4_FW_CONFIG could cause the handler to access memory beyond the valid payload (CWE-125 / CWE-20). Three guards are added before any TLV field access: 1. data_offset < sizeof(struct sof_tlv) Rejects payloads too short to hold the type+length header (8 B). 2. data_offset < sizeof(struct sof_tlv) + tlv->length Rejects payloads where the declared value length exceeds the actual buffer, preventing OOB reads of tlv->value[]. 3. tlv->length < sizeof(uint32_t) for IPC4_DMI_FORCE_L1_EXIT Rejects a TLV whose value field is too small to contain the force flag read by fw_config_set_force_l1_exit(). The TLV pointer cast is moved to after the header-size check so it is never formed against an undersized buffer. The warning log for unhandled types is updated to include the type value to aid diagnostics. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
1 parent b378052 commit d61abab

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

src/audio/base_fw_intel.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,17 +470,37 @@ __cold static int fw_config_set_force_l1_exit(const struct sof_tlv *tlv)
470470
__cold static int basefw_set_fw_config(bool first_block, bool last_block,
471471
uint32_t data_offset, const char *data)
472472
{
473+
assert_can_be_cold();
474+
475+
/* Validate minimum TLV header (type + length fields) is present */
476+
if (data_offset < sizeof(struct sof_tlv)) {
477+
tr_err(&basefw_comp_tr, "FW_CONFIG payload too small: %u < %zu",
478+
data_offset, sizeof(struct sof_tlv));
479+
return IPC4_INVALID_CONFIG_DATA_LEN;
480+
}
481+
473482
const struct sof_tlv *tlv = (const struct sof_tlv *)data;
474483

475-
assert_can_be_cold();
484+
/* Validate the TLV value payload fits within the reported buffer size */
485+
if (data_offset < sizeof(struct sof_tlv) + tlv->length) {
486+
tr_err(&basefw_comp_tr, "FW_CONFIG TLV value truncated: need %zu, have %u",
487+
sizeof(struct sof_tlv) + tlv->length, data_offset);
488+
return IPC4_INVALID_CONFIG_DATA_LEN;
489+
}
476490

477491
switch (tlv->type) {
478492
case IPC4_DMI_FORCE_L1_EXIT:
493+
if (tlv->length < sizeof(uint32_t)) {
494+
tr_err(&basefw_comp_tr, "DMI_FORCE_L1_EXIT value too small: %u",
495+
tlv->length);
496+
return IPC4_INVALID_CONFIG_DATA_LEN;
497+
}
479498
return fw_config_set_force_l1_exit(tlv);
480499
default:
481500
break;
482501
}
483-
tr_warn(&basefw_comp_tr, "returning success for Set FW_CONFIG without handling it");
502+
503+
tr_warn(&basefw_comp_tr, "Set FW_CONFIG: no handler for type %u", tlv->type);
484504
return 0;
485505
}
486506

0 commit comments

Comments
 (0)