]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mtd: lpddr_cmds: fix signed shifts in lpddr_cmds
authorIvan Stepchenko <sid@itb.spb.ru>
Fri, 21 Nov 2025 11:54:46 +0000 (14:54 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Jan 2026 12:09:36 +0000 (13:09 +0100)
[ 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

index ee063baed136c2e84aeadb0f5f0ce5f1cda944d2..5c39c9c653233462473266fb9c2df7dfc590b2f8 100644 (file)
@@ -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;