mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] ASoC: tas2781: bound firmware description string parsing
@ 2026-07-01  5:32 Pengpeng Hou
  2026-07-02 18:33 ` Mark Brown
  0 siblings, 1 reply; 2+ messages in thread
From: Pengpeng Hou @ 2026-07-01  5:32 UTC (permalink / raw)
  To: Shenghao Ding, Kevin Lu, Baojun Xu, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai
  Cc: Pengpeng Hou, linux-sound, linux-kernel

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.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 sound/soc/codecs/tas2781-fmwlib.c |   55 ++++++++++++++++++++++++++++++++++---
 1 file changed, 50 insertions(+), 5 deletions(-)

diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 885e0b6f..4ef9ad86 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -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>
@@ -1099,13 +1100,37 @@ static int tasdevice_load_block_kernel(
 	return 0;
 }
 
+static int tasdevice_fw_strnlen(const struct firmware *fmw, int offset)
+{
+	size_t remaining;
+	size_t len;
+
+	if (offset < 0 || offset >= fmw->size)
+		return -EINVAL;
+
+	remaining = fmw->size - offset;
+	len = strnlen((const char *)fmw->data + offset, remaining);
+	if (len == remaining)
+		return -EINVAL;
+	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) {
@@ -1237,7 +1262,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__);
@@ -1308,7 +1338,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) {
@@ -1371,7 +1406,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");
@@ -2165,7 +2205,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) {


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] ASoC: tas2781: bound firmware description string parsing
  2026-07-01  5:32 [PATCH] ASoC: tas2781: bound firmware description string parsing Pengpeng Hou
@ 2026-07-02 18:33 ` Mark Brown
  0 siblings, 0 replies; 2+ messages in thread
From: Mark Brown @ 2026-07-02 18:33 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Shenghao Ding, Kevin Lu, Baojun Xu, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 511 bytes --]

On Wed, Jul 01, 2026 at 01:32:55PM +0800, Pengpeng Hou wrote:

> @@ -2165,7 +2205,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;
> +		}

In this case n is an unsigned number so the error check is broken here.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-02 18:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-01  5:32 [PATCH] ASoC: tas2781: bound firmware description string parsing Pengpeng Hou
2026-07-02 18:33 ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox