summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi.c
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2015-05-25 12:13:10 +0200
committerMark Brown <broonie@kernel.org>2015-06-02 22:54:56 +0200
commit4b786458ed99eae9e9d9984a1624a79e9bf6cebb (patch)
tree99ce1090513a7c1901d2e0dfe0c34b213015ef9e /drivers/spi/spi.c
parentspi: fix race freeing dummy_tx/rx before it is unmapped (diff)
downloadlinux-4b786458ed99eae9e9d9984a1624a79e9bf6cebb.tar.xz
linux-4b786458ed99eae9e9d9984a1624a79e9bf6cebb.zip
spi: restore rx/tx_buf in case of unset CONFIG_HAS_DMA
The case where spi_master sets the flags SPI_MASTER_MUST_RX/TX while CONFIG_HAS_DMA is unset (which is unlikley) together with a driver that reuses spi_messages with rx/tx_buff set to NULL, can result in: * data disclosure over the SPI (for tx_buf == NULL) * memory corruption (for rx_buf == NULL) This happenes when dummy_rx/dummy_tx are changing address due to krealloc or free and an allocation of the memory by a different part of the kernel. Signed-off-by: Martin Sperl <kernel@martin.sperl.org> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r--drivers/spi/spi.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index d35c1a13217c..cf8b91b23a76 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -571,7 +571,7 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg)
return 0;
}
-static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
+static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
{
struct spi_transfer *xfer;
struct device *tx_dev, *rx_dev;
@@ -583,15 +583,6 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
rx_dev = master->dma_rx->device->dev;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- /*
- * Restore the original value of tx_buf or rx_buf if they are
- * NULL.
- */
- if (xfer->tx_buf == master->dummy_tx)
- xfer->tx_buf = NULL;
- if (xfer->rx_buf == master->dummy_rx)
- xfer->rx_buf = NULL;
-
if (!master->can_dma(master, msg->spi, xfer))
continue;
@@ -608,13 +599,32 @@ static inline int __spi_map_msg(struct spi_master *master,
return 0;
}
-static inline int spi_unmap_msg(struct spi_master *master,
- struct spi_message *msg)
+static inline int __spi_unmap_msg(struct spi_master *master,
+ struct spi_message *msg)
{
return 0;
}
#endif /* !CONFIG_HAS_DMA */
+static inline int spi_unmap_msg(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /*
+ * Restore the original value of tx_buf or rx_buf if they are
+ * NULL.
+ */
+ if (xfer->tx_buf == master->dummy_tx)
+ xfer->tx_buf = NULL;
+ if (xfer->rx_buf == master->dummy_rx)
+ xfer->rx_buf = NULL;
+ }
+
+ return __spi_unmap_msg(master, msg);
+}
+
static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
{
struct spi_transfer *xfer;