mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
ASoC: tas2781: bound firmware description string parsing
The TAS2781 firmware parser reads several variable-length description
strings with strlen() before checking that the string terminator is
present inside the firmware blob. A malformed firmware image without a
NUL terminator can therefore make the parser walk past the end of the
firmware buffer before the later size checks run.
Add a small bounded string-length helper and use it for all description
fields that are parsed from the firmware buffer. Keep the existing size
checks for the fixed bytes that follow each string.
Fixes: 915f5eadeb ("ASoC: tas2781: firmware lib")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260706144540.93929-1-pengpeng@iscas.ac.cn
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
27d090f3cc
commit
bc889dfcea
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
|
@ -1100,13 +1101,42 @@ static int tasdevice_load_block_kernel(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tasdevice_fw_strnlen(const struct firmware *fmw, int offset)
|
||||
{
|
||||
const u8 *start;
|
||||
const u8 *nul;
|
||||
size_t remaining;
|
||||
size_t len;
|
||||
|
||||
if (offset < 0 || offset >= fmw->size)
|
||||
return -EINVAL;
|
||||
|
||||
start = fmw->data + offset;
|
||||
remaining = fmw->size - offset;
|
||||
nul = memchr(start, '\0', remaining);
|
||||
if (!nul)
|
||||
return -EINVAL;
|
||||
|
||||
len = nul - start;
|
||||
if (len > INT_MAX)
|
||||
return -EOVERFLOW;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int fw_parse_variable_hdr(struct tasdevice_priv
|
||||
*tas_priv, struct tasdevice_dspfw_hdr *fw_hdr,
|
||||
const struct firmware *fmw, int offset)
|
||||
{
|
||||
const unsigned char *buf = fmw->data;
|
||||
int len = strlen((char *)&buf[offset]);
|
||||
int len;
|
||||
|
||||
len = tasdevice_fw_strnlen(fmw, offset);
|
||||
if (len < 0) {
|
||||
dev_err(tas_priv->dev, "%s: Description error\n", __func__);
|
||||
offset = len;
|
||||
goto out;
|
||||
}
|
||||
len++;
|
||||
|
||||
if (offset + len + 8 > fmw->size) {
|
||||
|
|
@ -1238,7 +1268,12 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw,
|
|||
memcpy(img_data->name, &data[offset], 64);
|
||||
offset += 64;
|
||||
|
||||
n = strlen((char *)&data[offset]);
|
||||
n = tasdevice_fw_strnlen(fmw, offset);
|
||||
if (n < 0) {
|
||||
dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
|
||||
offset = n;
|
||||
goto out;
|
||||
}
|
||||
n++;
|
||||
if (offset + n + 2 > fmw->size) {
|
||||
dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
|
||||
|
|
@ -1309,7 +1344,12 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
|
|||
}
|
||||
offset += 64;
|
||||
|
||||
n = strlen((char *)&buf[offset]);
|
||||
n = tasdevice_fw_strnlen(fmw, offset);
|
||||
if (n < 0) {
|
||||
dev_err(tas_priv->dev, "Description err\n");
|
||||
offset = n;
|
||||
goto out;
|
||||
}
|
||||
/* skip '\0' and 5 unused bytes */
|
||||
n += 6;
|
||||
if (offset + n > fmw->size) {
|
||||
|
|
@ -1372,7 +1412,12 @@ static int fw_parse_configuration_data(
|
|||
memcpy(config->name, &data[offset], 64);
|
||||
offset += 64;
|
||||
|
||||
n = strlen((char *)&data[offset]);
|
||||
n = tasdevice_fw_strnlen(fmw, offset);
|
||||
if (n < 0) {
|
||||
dev_err(tas_priv->dev, "Description err\n");
|
||||
offset = n;
|
||||
goto out;
|
||||
}
|
||||
n += 15;
|
||||
if (offset + n > fmw->size) {
|
||||
dev_err(tas_priv->dev, "Description err\n");
|
||||
|
|
@ -2134,7 +2179,8 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
|
|||
{
|
||||
struct tasdevice_calibration *calibration;
|
||||
unsigned char *data = (unsigned char *)fmw->data;
|
||||
unsigned int i, n;
|
||||
unsigned int i;
|
||||
int n;
|
||||
|
||||
if (offset + 2 > fmw->size) {
|
||||
dev_err(tas_priv->dev, "%s: Calibrations error\n", __func__);
|
||||
|
|
@ -2166,7 +2212,12 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
|
|||
calibration = &(tas_fmw->calibrations[i]);
|
||||
offset += 64;
|
||||
|
||||
n = strlen((char *)&data[offset]);
|
||||
n = tasdevice_fw_strnlen(fmw, offset);
|
||||
if (n < 0) {
|
||||
dev_err(tas_priv->dev, "Description err\n");
|
||||
offset = n;
|
||||
goto out;
|
||||
}
|
||||
/* skip '\0' and 2 unused bytes */
|
||||
n += 3;
|
||||
if (offset + n > fmw->size) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user