]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: tas2781: bound firmware description string parsing
authorPengpeng Hou <pengpeng@iscas.ac.cn>
Mon, 6 Jul 2026 14:45:39 +0000 (22:45 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 14 Jul 2026 11:24:23 +0000 (12:24 +0100)
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: 915f5eadebd2 ("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>
sound/soc/codecs/tas2781-fmwlib.c

index bd16d5326a23dddc0a93bc2ac43c7b2c325a4205..dcbeb9618195b750996240745b4f2d9e7b7f400c 100644 (file)
@@ -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) {