Skip to content

Commit

Permalink
mtd: spi-nor: Fix incorrect buffer access
Browse files Browse the repository at this point in the history
For the Dual parallel mode, spi-nor layer doesn't have support to access
odd flash addresses and the update is, if odd address is requested of len
x with read buffer size of y, then decrement the address by one(which will
give even address) and increment the length by 1(x+1) to access new extra
byte. But we are not changing the size of the buffer, it is still y.
Hence copying x+1 bytes of length to a buffer of size x will lead to stack
corruption. There might be a chance of successful copy of data to that
buffer even the size is x, if the memory we are accessing is still valid.
But in stress kind of tests (ubi stress tests), which creates large buffers
and because of the above bug, at some point of time we are getting the
below error
"Unable to handle kernel paging request at virtual address".

The only way to catch this bug is through ubi stress test.
As we are changing the address(odd to even) and length(x to x+1), we
should also change the buffer size. hence allocate a buffer of size x+1
and free it when we are done with transfer.
We don't create this buffer always, but if the address is odd and that
to only in UBIFS case.

Fixes: 0387834 ("spi: mtd: spi-nor: add ubifs support for
dual-parallel")
Signed-off-by: Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
  • Loading branch information
Naga Sureshkumar Relli authored and Michal Simek committed Sep 23, 2019
1 parent 5f00131 commit e190877
Showing 1 changed file with 13 additions and 2 deletions.
15 changes: 13 additions & 2 deletions drivers/mtd/spi-nor/spi-nor.c
Expand Up @@ -1724,6 +1724,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
u8 cur_bank;
u8 nxt_bank;
u32 bank_size;
u_char *ptr;

#define OFFSET_16_MB 0x1000000

Expand All @@ -1734,6 +1735,12 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
from = (loff_t)(from - 1);
len = (size_t)(len + 1);
is_ofst_odd = 1;
ptr = kmalloc(len, GFP_KERNEL);
if (!ptr)
return -ENOMEM;

} else {
ptr = buf;
}

ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ);
Expand Down Expand Up @@ -1806,8 +1813,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,

if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT)
addr = spi_nor_s3an_addr_convert(nor, offset);
ret = nor->read(nor, offset, read_len, ptr);

ret = nor->read(nor, offset, read_len, buf);
if (ret == 0) {
/* We shouldn't see 0-length reads */
ret = -EIO;
Expand All @@ -1818,7 +1825,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,

WARN_ON(ret > len);
if (is_ofst_odd == 1) {
memcpy(buf, (buf + 1), (len - 1));
memcpy(buf, (ptr + 1), (len - 1));
*retlen += (ret - 1);
} else {
*retlen += ret;
Expand All @@ -1830,6 +1837,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
ret = 0;

read_err:

if (is_ofst_odd == 1)
kfree(ptr);

spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
return ret;
}
Expand Down

0 comments on commit e190877

Please sign in to comment.