Skip to content

Commit ea3ad78

Browse files
committed
mtd: spi-nor: fix iteration over smpt array
Iterate over smpt array using its starting address and length instead of the blind iterations that used data found in the array. This prevents possible memory accesses outside of the smpt array boundaries in case software, or manufacturers, misrepresent smpt array fields. Fixes: b038e8e ("mtd: spi-nor: parse SFDP Sector Map Parameter Table") Suggested-by: Boris Brezillon <boris.brezillon@bootlin.com> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> (cherry picked from commit c797bd8) Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
1 parent e432a16 commit ea3ad78

1 file changed

Lines changed: 30 additions & 10 deletions

File tree

drivers/mtd/spi-nor/spi-nor.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,12 +2803,15 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings)
28032803
* spi_nor_get_map_in_use() - get the configuration map in use
28042804
* @nor: pointer to a 'struct spi_nor'
28052805
* @smpt: pointer to the sector map parameter table
2806+
* @smpt_len: sector map parameter table length
28062807
*/
2807-
static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
2808+
static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt,
2809+
u8 smpt_len)
28082810
{
28092811
const u32 *ret = NULL;
2810-
u32 i, addr;
2812+
u32 addr;
28112813
int err;
2814+
u8 i;
28122815
u8 addr_width, read_opcode, read_dummy;
28132816
u8 read_data_mask, data_byte, map_id;
28142817

@@ -2817,9 +2820,11 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
28172820
read_opcode = nor->read_opcode;
28182821

28192822
map_id = 0;
2820-
i = 0;
28212823
/* Determine if there are any optional Detection Command Descriptors */
2822-
while (!(smpt[i] & SMPT_DESC_TYPE_MAP)) {
2824+
for (i = 0; i < smpt_len; i += 2) {
2825+
if (smpt[i] & SMPT_DESC_TYPE_MAP)
2826+
break;
2827+
28232828
read_data_mask = SMPT_CMD_READ_DATA(smpt[i]);
28242829
nor->addr_width = spi_nor_smpt_addr_width(nor, smpt[i]);
28252830
nor->read_dummy = spi_nor_smpt_read_dummy(nor, smpt[i]);
@@ -2835,18 +2840,33 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt)
28352840
* Configuration that is currently in use.
28362841
*/
28372842
map_id = map_id << 1 | !!(data_byte & read_data_mask);
2838-
i = i + 2;
28392843
}
28402844

2841-
/* Find the matching configuration map */
2842-
while (SMPT_MAP_ID(smpt[i]) != map_id) {
2845+
/*
2846+
* If command descriptors are provided, they always precede map
2847+
* descriptors in the table. There is no need to start the iteration
2848+
* over smpt array all over again.
2849+
*
2850+
* Find the matching configuration map.
2851+
*/
2852+
while (i < smpt_len) {
2853+
if (SMPT_MAP_ID(smpt[i]) == map_id) {
2854+
ret = smpt + i;
2855+
break;
2856+
}
2857+
2858+
/*
2859+
* If there are no more configuration map descriptors and no
2860+
* configuration ID matched the configuration identifier, the
2861+
* sector address map is unknown.
2862+
*/
28432863
if (smpt[i] & SMPT_DESC_END)
2844-
goto out;
2864+
break;
2865+
28452866
/* increment the table index to the next map */
28462867
i += SMPT_MAP_REGION_COUNT(smpt[i]) + 1;
28472868
}
28482869

2849-
ret = smpt + i;
28502870
/* fall through */
28512871
out:
28522872
nor->addr_width = addr_width;
@@ -2968,7 +2988,7 @@ static int spi_nor_parse_smpt(struct spi_nor *nor,
29682988
for (i = 0; i < smpt_header->length; i++)
29692989
smpt[i] = le32_to_cpu(smpt[i]);
29702990

2971-
sector_map = spi_nor_get_map_in_use(nor, smpt);
2991+
sector_map = spi_nor_get_map_in_use(nor, smpt, smpt_header->length);
29722992
if (!sector_map) {
29732993
ret = -EINVAL;
29742994
goto out;

0 commit comments

Comments
 (0)