| From 68451592e5dbe92e7c731c9f90c9d6a921861d6c Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 21 Nov 2025 14:54:46 +0300 |
| Subject: mtd: lpddr_cmds: fix signed shifts in lpddr_cmds |
| |
| From: Ivan Stepchenko <sid@itb.spb.ru> |
| |
| [ Upstream commit c909fec69f84b39e63876c69b9df2c178c6b76ba ] |
| |
| 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> |
| Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| 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 ee063baed136c..5c39c9c653233 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 |
| @@ -562,7 +562,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 */ |
| @@ -578,7 +578,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]; |
| } |
| @@ -604,7 +604,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.51.0 |
| |