Skip to content

Commit 7183cde

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 c26c542 commit 7183cde

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

src/audio/base_fw_intel.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,17 +470,38 @@ __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 (tlv->length > data_offset - sizeof(struct sof_tlv)) {
486+
tr_err(&basefw_comp_tr,
487+
"FW_CONFIG TLV value truncated: len %u exceeds payload %u",
488+
tlv->length, data_offset);
489+
return IPC4_INVALID_CONFIG_DATA_LEN;
490+
}
476491

477492
switch (tlv->type) {
478493
case IPC4_DMI_FORCE_L1_EXIT:
494+
if (tlv->length < sizeof(uint32_t)) {
495+
tr_err(&basefw_comp_tr, "DMI_FORCE_L1_EXIT value too small: %u",
496+
tlv->length);
497+
return IPC4_INVALID_CONFIG_DATA_LEN;
498+
}
479499
return fw_config_set_force_l1_exit(tlv);
480500
default:
481501
break;
482502
}
483-
tr_warn(&basefw_comp_tr, "returning success for Set FW_CONFIG without handling it");
503+
504+
tr_warn(&basefw_comp_tr, "Set FW_CONFIG: no handler for type %u", tlv->type);
484505
return 0;
485506
}
486507

0 commit comments

Comments
 (0)