Skip to content

Commit a0cd49e

Browse files
committed
firmware: cs_dsp: Validate payload length before processing block
JIRA: https://issues.redhat.com/browse/RHEL-53640 CVE: CVE-2024-42237 commit 6598afa Author: Richard Fitzgerald <rf@opensource.cirrus.com> Date: Thu Jun 27 15:14:31 2024 +0100 firmware: cs_dsp: Validate payload length before processing block Move the payload length check in cs_dsp_load() and cs_dsp_coeff_load() to be done before the block is processed. The check that the length of a block payload does not exceed the number of remaining bytes in the firwmware file buffer was being done near the end of the loop iteration. However, some code before that check used the length field without validating it. Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Fixes: f6bc909 ("firmware: cs_dsp: add driver to support firmware loading on Cirrus Logic DSPs") Link: https://patch.msgid.link/20240627141432.93056-4-rf@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: David Arcari <darcari@redhat.com>
1 parent 80852bc commit a0cd49e

File tree

1 file changed

+15
-21
lines changed

1 file changed

+15
-21
lines changed

drivers/firmware/cirrus/cs_dsp.c

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,12 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
15291529
while (pos < firmware->size &&
15301530
sizeof(*region) < firmware->size - pos) {
15311531
region = (void *)&(firmware->data[pos]);
1532+
1533+
if (le32_to_cpu(region->len) > firmware->size - pos - sizeof(*region)) {
1534+
ret = -EOVERFLOW;
1535+
goto out_fw;
1536+
}
1537+
15321538
region_name = "Unknown";
15331539
reg = 0;
15341540
text = NULL;
@@ -1585,16 +1591,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
15851591
regions, le32_to_cpu(region->len), offset,
15861592
region_name);
15871593

1588-
if (le32_to_cpu(region->len) >
1589-
firmware->size - pos - sizeof(*region)) {
1590-
cs_dsp_err(dsp,
1591-
"%s.%d: %s region len %d bytes exceeds file length %zu\n",
1592-
file, regions, region_name,
1593-
le32_to_cpu(region->len), firmware->size);
1594-
ret = -EINVAL;
1595-
goto out_fw;
1596-
}
1597-
15981594
if (text) {
15991595
memcpy(text, region->data, le32_to_cpu(region->len));
16001596
cs_dsp_info(dsp, "%s: %s\n", file, text);
@@ -2219,6 +2215,11 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
22192215
sizeof(*blk) < firmware->size - pos) {
22202216
blk = (void *)(&firmware->data[pos]);
22212217

2218+
if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) {
2219+
ret = -EOVERFLOW;
2220+
goto out_fw;
2221+
}
2222+
22222223
type = le16_to_cpu(blk->type);
22232224
offset = le16_to_cpu(blk->offset);
22242225
version = le32_to_cpu(blk->ver) >> 8;
@@ -2315,17 +2316,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
23152316
}
23162317

23172318
if (reg) {
2318-
if (le32_to_cpu(blk->len) >
2319-
firmware->size - pos - sizeof(*blk)) {
2320-
cs_dsp_err(dsp,
2321-
"%s.%d: %s region len %d bytes exceeds file length %zu\n",
2322-
file, blocks, region_name,
2323-
le32_to_cpu(blk->len),
2324-
firmware->size);
2325-
ret = -EINVAL;
2326-
goto out_fw;
2327-
}
2328-
23292319
buf = cs_dsp_buf_alloc(blk->data,
23302320
le32_to_cpu(blk->len),
23312321
&buf_list);
@@ -2365,6 +2355,10 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
23652355
regmap_async_complete(regmap);
23662356
cs_dsp_buf_free(&buf_list);
23672357
kfree(text);
2358+
2359+
if (ret == -EOVERFLOW)
2360+
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
2361+
23682362
return ret;
23692363
}
23702364

0 commit comments

Comments
 (0)