[PATCH] mtd: lpddr_cmds: fix signed shifts in lpddr_cmds

Ivan Stepchenko posted 1 patch 1 week, 3 days ago
drivers/mtd/lpddr/lpddr_cmds.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
[PATCH] mtd: lpddr_cmds: fix signed shifts in lpddr_cmds
Posted by Ivan Stepchenko 1 week, 3 days ago
There are several places where a value of type 'int' is shifted by
lpddr->chipshift. lpddr->chipshift is derived from QINFO geometry and
might reach 31 when QINFO reports a 2 GiB size - the maximum supported by
LPDDR(1) compliant chips. This may cause unexpected sign-extensions when
casting the integer value to the type of 'unsigned long'.

Use '1UL << lpddr->chipshift' and cast 'j' to unsigned long before
shifting so the computation is performed at the destination width.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: c68264711ca6 ("[MTD] LPDDR Command set driver")
Signed-off-by: Ivan Stepchenko <sid@itb.spb.ru>
---
 drivers/mtd/lpddr/lpddr_cmds.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c
index 14e36ae71958..bd76479b90e4 100644
--- a/drivers/mtd/lpddr/lpddr_cmds.c
+++ b/drivers/mtd/lpddr/lpddr_cmds.c
@@ -79,7 +79,7 @@ struct mtd_info *lpddr_cmdset(struct map_info *map)
 		mutex_init(&shared[i].lock);
 		for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) {
 			*chip = lpddr->chips[i];
-			chip->start += j << lpddr->chipshift;
+			chip->start += (unsigned long)j << lpddr->chipshift;
 			chip->oldstate = chip->state = FL_READY;
 			chip->priv = &shared[i];
 			/* those should be reset too since
@@ -559,7 +559,7 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
 			break;
 
 		if ((len + ofs - 1) >> lpddr->chipshift)
-			thislen = (1<<lpddr->chipshift) - ofs;
+			thislen = (1UL << lpddr->chipshift) - ofs;
 		else
 			thislen = len;
 		/* get the chip */
@@ -575,7 +575,7 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
 		len -= thislen;
 
 		ofs = 0;
-		last_end += 1 << lpddr->chipshift;
+		last_end += 1UL << lpddr->chipshift;
 		chipnum++;
 		chip = &lpddr->chips[chipnum];
 	}
@@ -601,7 +601,7 @@ static int lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
 			break;
 
 		if ((len + ofs - 1) >> lpddr->chipshift)
-			thislen = (1<<lpddr->chipshift) - ofs;
+			thislen = (1UL << lpddr->chipshift) - ofs;
 		else
 			thislen = len;
 
-- 
2.39.5
Re: [PATCH] mtd: lpddr_cmds: fix signed shifts in lpddr_cmds
Posted by Miquel Raynal 2 days, 12 hours ago
On Fri, 21 Nov 2025 14:54:46 +0300, Ivan Stepchenko wrote:
> There are several places where a value of type 'int' is shifted by
> lpddr->chipshift. lpddr->chipshift is derived from QINFO geometry and
> might reach 31 when QINFO reports a 2 GiB size - the maximum supported by
> LPDDR(1) compliant chips. This may cause unexpected sign-extensions when
> casting the integer value to the type of 'unsigned long'.
> 
> Use '1UL << lpddr->chipshift' and cast 'j' to unsigned long before
> shifting so the computation is performed at the destination width.
> 
> [...]

Applied to mtd/next, thanks!

[1/1] mtd: lpddr_cmds: fix signed shifts in lpddr_cmds
      commit: c909fec69f84b39e63876c69b9df2c178c6b76ba

Patche(s) should be available on mtd/linux.git and will be
part of the next PR (provided that no robot complains by then).

Kind regards,
Miquèl