diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2015-12-27 05:17:06 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-12-30 12:26:40 -0500 |
commit | de327e4966cdbad2b7053c84a6f591fbdc54f7cb (patch) | |
tree | 4d84876c8a528509fa6c9fa412a401934f80f56d /drivers/spi/spi-mt65xx.c | |
parent | 8005c49d9aea74d382f474ce11afbbc7d7130bec (diff) |
spi: mediatek: Prevent overflows in FIFO transfers
In the case where transfer length is not a multiple of 4, KASAN
reports 2 out-of-bounds memory accesses:
- mtk_spi_interrupt: ioread32_rep writes past the end of
trans->rx_buf.
- mtk_spi_fifo_transfer: iowrite32_rep reads past the end of
xfer->tx_buf.
Fix this by using memcpy on the remainder of the bytes.
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-mt65xx.c')
-rw-r--r-- | drivers/spi/spi-mt65xx.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 563954a61424..375d412dbf05 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c | |||
@@ -323,7 +323,8 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, | |||
323 | struct spi_device *spi, | 323 | struct spi_device *spi, |
324 | struct spi_transfer *xfer) | 324 | struct spi_transfer *xfer) |
325 | { | 325 | { |
326 | int cnt; | 326 | int cnt, remainder; |
327 | u32 reg_val; | ||
327 | struct mtk_spi *mdata = spi_master_get_devdata(master); | 328 | struct mtk_spi *mdata = spi_master_get_devdata(master); |
328 | 329 | ||
329 | mdata->cur_transfer = xfer; | 330 | mdata->cur_transfer = xfer; |
@@ -331,12 +332,16 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, | |||
331 | mtk_spi_prepare_transfer(master, xfer); | 332 | mtk_spi_prepare_transfer(master, xfer); |
332 | mtk_spi_setup_packet(master); | 333 | mtk_spi_setup_packet(master); |
333 | 334 | ||
334 | if (xfer->len % 4) | 335 | cnt = xfer->len / 4; |
335 | cnt = xfer->len / 4 + 1; | ||
336 | else | ||
337 | cnt = xfer->len / 4; | ||
338 | iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt); | 336 | iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt); |
339 | 337 | ||
338 | remainder = xfer->len % 4; | ||
339 | if (remainder > 0) { | ||
340 | reg_val = 0; | ||
341 | memcpy(®_val, xfer->tx_buf + (cnt * 4), remainder); | ||
342 | writel(reg_val, mdata->base + SPI_TX_DATA_REG); | ||
343 | } | ||
344 | |||
340 | mtk_spi_enable_transfer(master); | 345 | mtk_spi_enable_transfer(master); |
341 | 346 | ||
342 | return 1; | 347 | return 1; |
@@ -418,7 +423,7 @@ static int mtk_spi_setup(struct spi_device *spi) | |||
418 | 423 | ||
419 | static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) | 424 | static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) |
420 | { | 425 | { |
421 | u32 cmd, reg_val, cnt; | 426 | u32 cmd, reg_val, cnt, remainder; |
422 | struct spi_master *master = dev_id; | 427 | struct spi_master *master = dev_id; |
423 | struct mtk_spi *mdata = spi_master_get_devdata(master); | 428 | struct mtk_spi *mdata = spi_master_get_devdata(master); |
424 | struct spi_transfer *trans = mdata->cur_transfer; | 429 | struct spi_transfer *trans = mdata->cur_transfer; |
@@ -431,12 +436,15 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) | |||
431 | 436 | ||
432 | if (!master->can_dma(master, master->cur_msg->spi, trans)) { | 437 | if (!master->can_dma(master, master->cur_msg->spi, trans)) { |
433 | if (trans->rx_buf) { | 438 | if (trans->rx_buf) { |
434 | if (mdata->xfer_len % 4) | 439 | cnt = mdata->xfer_len / 4; |
435 | cnt = mdata->xfer_len / 4 + 1; | ||
436 | else | ||
437 | cnt = mdata->xfer_len / 4; | ||
438 | ioread32_rep(mdata->base + SPI_RX_DATA_REG, | 440 | ioread32_rep(mdata->base + SPI_RX_DATA_REG, |
439 | trans->rx_buf, cnt); | 441 | trans->rx_buf, cnt); |
442 | remainder = mdata->xfer_len % 4; | ||
443 | if (remainder > 0) { | ||
444 | reg_val = readl(mdata->base + SPI_RX_DATA_REG); | ||
445 | memcpy(trans->rx_buf + (cnt * 4), | ||
446 | ®_val, remainder); | ||
447 | } | ||
440 | } | 448 | } |
441 | spi_finalize_current_transfer(master); | 449 | spi_finalize_current_transfer(master); |
442 | return IRQ_HANDLED; | 450 | return IRQ_HANDLED; |