linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] nvmem: eeprom: at25: fix byte_len for FRAM
@ 2021-10-28 13:49 Ralph Siemsen
  2021-11-08 18:16 ` [PATCH v2] nvmem: eeprom: at25: fix FRAM byte_len Ralph Siemsen
  0 siblings, 1 reply; 3+ messages in thread
From: Ralph Siemsen @ 2021-10-28 13:49 UTC (permalink / raw)
  To: arnd, gregkh, jiri.prchal, broonie; +Cc: linux-kernel, Ralph Siemsen

Commit fd307a4ad332 ("nvmem: prepare basics for FRAM support") added
support for FRAM devices such as the Cypress FM25V. During testing, it
was found that the FRAM detects properly, however reads and writes fail.
Upon further investigation, two problem were found in at25_probe() routine.

1) In the case of an FRAM device without platform data, eg.
       fram == true && spi->dev.platform_data == NULL
the stack local variable "struct spi_eeprom chip" is never initialized.
This structure is copied into at25->chip, which is used subsequently.
Fix this by an explicit memset(), similar to existing at25_fw_to_chip().

2) The size of FRAM is computed from its ID register, and is stored into
the stack local "struct spi_eeprom chip" structure. This happens after
the same structure has been copied into at25->chip. As a result,
at25->chip.byte_len does not contain the correct length of the device.
In turn this can cause checks at beginning of at25_ee_read() to fail
(or equally, it could allow reads beyond the end of the device length).

Fixes: fd307a4ad332 ("nvmem: prepare basics for FRAM support")
Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
 drivers/misc/eeprom/at25.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 632325474233..65cfb10fa0b7 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -395,6 +395,8 @@ static int at25_probe(struct spi_device *spi)
 			err = at25_fw_to_chip(&spi->dev, &chip);
 			if (err)
 				return err;
+		} else {
+			memset(&chip, 0, sizeof(chip));
 		}
 	} else
 		chip = *(struct spi_eeprom *)spi->dev.platform_data;
@@ -432,6 +434,7 @@ static int at25_probe(struct spi_device *spi)
 			return -ENODEV;
 		}
 		chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
+		at25->chip.byte_len = chip.byte_len;
 
 		if (at25->chip.byte_len > 64 * 1024)
 			at25->chip.flags |= EE_ADDR3;
-- 
2.25.1


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

* [PATCH v2] nvmem: eeprom: at25: fix FRAM byte_len
  2021-10-28 13:49 [PATCH] nvmem: eeprom: at25: fix byte_len for FRAM Ralph Siemsen
@ 2021-11-08 18:16 ` Ralph Siemsen
  2021-11-08 18:27   ` Arnd Bergmann
  0 siblings, 1 reply; 3+ messages in thread
From: Ralph Siemsen @ 2021-11-08 18:16 UTC (permalink / raw)
  To: arnd, gregkh, jiri.prchal, broonie; +Cc: linux-kernel, Ralph Siemsen

Commit fd307a4ad332 ("nvmem: prepare basics for FRAM support") added
support for FRAM devices such as the Cypress FM25V. During testing, it
was found that the FRAM detects properly, however reads and writes fail.
Upon further investigation, two problem were found in at25_probe() routine.

1) In the case of an FRAM device without platform data, eg.
       fram == true && spi->dev.platform_data == NULL
the stack local variable "struct spi_eeprom chip" is not initialized
fully, prior to being copied into at25->chip. The chip.flags field in
particular can cause problems.

2) The byte_len of FRAM is computed from its ID register, and is stored
into the stack local "struct spi_eeprom chip" structure. This happens
after the same structure has been copied into at25->chip. As a result,
at25->chip.byte_len does not contain the correct length of the device.
In turn this can cause checks at beginning of at25_ee_read() to fail
(or equally, it could allow reads beyond the end of the device length).

Fix both of these issues by eliminating the on-stack struct spi_eeprom.
Instead use the one inside at25_data structure, which starts of zeroed.

Fixes: fd307a4ad332 ("nvmem: prepare basics for FRAM support")
Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
V1 -> V2: refactor to eliminate on-stack copy of "chip" structure

 drivers/misc/eeprom/at25.c | 38 ++++++++++++++++++--------------------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 632325474233..b38978a3b3ff 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -376,7 +376,6 @@ MODULE_DEVICE_TABLE(spi, at25_spi_ids);
 static int at25_probe(struct spi_device *spi)
 {
 	struct at25_data	*at25 = NULL;
-	struct spi_eeprom	chip;
 	int			err;
 	int			sr;
 	u8 id[FM25_ID_LEN];
@@ -389,15 +388,18 @@ static int at25_probe(struct spi_device *spi)
 	if (match && !strcmp(match->compatible, "cypress,fm25"))
 		is_fram = 1;
 
+	at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
+	if (!at25)
+		return -ENOMEM;
+
 	/* Chip description */
-	if (!spi->dev.platform_data) {
-		if (!is_fram) {
-			err = at25_fw_to_chip(&spi->dev, &chip);
-			if (err)
-				return err;
-		}
-	} else
-		chip = *(struct spi_eeprom *)spi->dev.platform_data;
+	if (spi->dev.platform_data) {
+		memcpy(&at25->chip, spi->dev.platform_data, sizeof(at25->chip));
+	} else if (!is_fram) {
+		err = at25_fw_to_chip(&spi->dev, &at25->chip);
+		if (err)
+			return err;
+	}
 
 	/* Ping the chip ... the status register is pretty portable,
 	 * unlike probing manufacturer IDs.  We do expect that system
@@ -409,12 +411,7 @@ static int at25_probe(struct spi_device *spi)
 		return -ENXIO;
 	}
 
-	at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
-	if (!at25)
-		return -ENOMEM;
-
 	mutex_init(&at25->lock);
-	at25->chip = chip;
 	at25->spi = spi;
 	spi_set_drvdata(spi, at25);
 
@@ -431,7 +428,7 @@ static int at25_probe(struct spi_device *spi)
 			dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]);
 			return -ENODEV;
 		}
-		chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
+		at25->chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
 
 		if (at25->chip.byte_len > 64 * 1024)
 			at25->chip.flags |= EE_ADDR3;
@@ -464,7 +461,7 @@ static int at25_probe(struct spi_device *spi)
 	at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM;
 	at25->nvmem_config.name = dev_name(&spi->dev);
 	at25->nvmem_config.dev = &spi->dev;
-	at25->nvmem_config.read_only = chip.flags & EE_READONLY;
+	at25->nvmem_config.read_only = at25->chip.flags & EE_READONLY;
 	at25->nvmem_config.root_only = true;
 	at25->nvmem_config.owner = THIS_MODULE;
 	at25->nvmem_config.compat = true;
@@ -474,17 +471,18 @@ static int at25_probe(struct spi_device *spi)
 	at25->nvmem_config.priv = at25;
 	at25->nvmem_config.stride = 1;
 	at25->nvmem_config.word_size = 1;
-	at25->nvmem_config.size = chip.byte_len;
+	at25->nvmem_config.size = at25->chip.byte_len;
 
 	at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
 	if (IS_ERR(at25->nvmem))
 		return PTR_ERR(at25->nvmem);
 
 	dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
-		 (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
-		 (chip.byte_len < 1024) ? "Byte" : "KByte",
+		 (at25->chip.byte_len < 1024) ?
+			at25->chip.byte_len : (at25->chip.byte_len / 1024),
+		 (at25->chip.byte_len < 1024) ? "Byte" : "KByte",
 		 at25->chip.name, is_fram ? "fram" : "eeprom",
-		 (chip.flags & EE_READONLY) ? " (readonly)" : "",
+		 (at25->chip.flags & EE_READONLY) ? " (readonly)" : "",
 		 at25->chip.page_size);
 	return 0;
 }
-- 
2.25.1


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

* Re: [PATCH v2] nvmem: eeprom: at25: fix FRAM byte_len
  2021-11-08 18:16 ` [PATCH v2] nvmem: eeprom: at25: fix FRAM byte_len Ralph Siemsen
@ 2021-11-08 18:27   ` Arnd Bergmann
  0 siblings, 0 replies; 3+ messages in thread
From: Arnd Bergmann @ 2021-11-08 18:27 UTC (permalink / raw)
  To: Ralph Siemsen
  Cc: Arnd Bergmann, gregkh, jiri.prchal, Mark Brown,
	Linux Kernel Mailing List

On Mon, Nov 8, 2021 at 7:16 PM Ralph Siemsen <ralph.siemsen@linaro.org> wrote:
>
> Commit fd307a4ad332 ("nvmem: prepare basics for FRAM support") added
> support for FRAM devices such as the Cypress FM25V. During testing, it
> was found that the FRAM detects properly, however reads and writes fail.
> Upon further investigation, two problem were found in at25_probe() routine.
>
> 1) In the case of an FRAM device without platform data, eg.
>        fram == true && spi->dev.platform_data == NULL
> the stack local variable "struct spi_eeprom chip" is not initialized
> fully, prior to being copied into at25->chip. The chip.flags field in
> particular can cause problems.
>
> 2) The byte_len of FRAM is computed from its ID register, and is stored
> into the stack local "struct spi_eeprom chip" structure. This happens
> after the same structure has been copied into at25->chip. As a result,
> at25->chip.byte_len does not contain the correct length of the device.
> In turn this can cause checks at beginning of at25_ee_read() to fail
> (or equally, it could allow reads beyond the end of the device length).
>
> Fix both of these issues by eliminating the on-stack struct spi_eeprom.
> Instead use the one inside at25_data structure, which starts of zeroed.
>
> Fixes: fd307a4ad332 ("nvmem: prepare basics for FRAM support")
> Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>

Reviewed-by: Arnd Bergmann <arnd@arndb.de>

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

end of thread, other threads:[~2021-11-08 18:27 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-28 13:49 [PATCH] nvmem: eeprom: at25: fix byte_len for FRAM Ralph Siemsen
2021-11-08 18:16 ` [PATCH v2] nvmem: eeprom: at25: fix FRAM byte_len Ralph Siemsen
2021-11-08 18:27   ` Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).