diff mbox series

spi: Assign dummy scatterlist to unidirectional transfers

Message ID 20240529-dma-oops-dummy-v1-1-bb43aacfb11b@collabora.com
State New
Headers show
Series spi: Assign dummy scatterlist to unidirectional transfers | expand

Commit Message

Nícolas F. R. A. Prado May 29, 2024, 3:42 p.m. UTC
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Commit 8cc3bad9d9d6 ("spi: Remove unneded check for orig_nents")
introduced a regression: unmapped data could now be passed to the DMA
APIs, resulting in null pointer dereferences. Commit 9f788ba457b4 ("spi:
Don't mark message DMA mapped when no transfer in it is") and commit
da560097c056 ("spi: Check if transfer is mapped before calling DMA sync
APIs") addressed the problem, but only partially. Unidirectional
transactions will still result in null pointer dereference. To prevent
that from happening, assign a dummy scatterlist when no data is mapped,
so that the DMA API can be called and not result in a null pointer
dereference.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reported-by: Neil Armstrong <neil.armstrong@linaro.org>
Closes: https://lore.kernel.org/r/8ae675b5-fcf9-4c9b-b06a-4462f70e1322@linaro.org
Reported-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Closes: https://lore.kernel.org/all/d3679496-2e4e-4a7c-97ed-f193bd53af1d@notapiano
Closes: https://lore.kernel.org/all/4748499f-789c-45a8-b50a-2dd09f4bac8c@notapiano
Fixes: 8cc3bad9d9d6 ("spi: Remove unneded check for orig_nents")
Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
[nfraprado: wrote the commit message]
Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
---
 drivers/spi/spi.c | 9 +++++++++
 1 file changed, 9 insertions(+)


---
base-commit: 9d99040b1bc8dbf385a8aa535e9efcdf94466e19
change-id: 20240529-dma-oops-dummy-2cbf8cbaec54

Best regards,

Comments

Yongqin Liu July 22, 2024, 4:05 p.m. UTC | #1
On Thu, 30 May 2024 at 05:04, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>
> Wed, May 29, 2024 at 11:42:35AM -0400, Nícolas F. R. A. Prado kirjoitti:
> > From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> >
> > Commit 8cc3bad9d9d6 ("spi: Remove unneded check for orig_nents")
> > introduced a regression: unmapped data could now be passed to the DMA
> > APIs, resulting in null pointer dereferences. Commit 9f788ba457b4 ("spi:
> > Don't mark message DMA mapped when no transfer in it is") and commit
> > da560097c056 ("spi: Check if transfer is mapped before calling DMA sync
> > APIs") addressed the problem, but only partially. Unidirectional
> > transactions will still result in null pointer dereference. To prevent
> > that from happening, assign a dummy scatterlist when no data is mapped,
> > so that the DMA API can be called and not result in a null pointer
> > dereference.
>
> I feel that with this the da560097c056 ("spi: Check if transfer is mapped
> before calling DMA sync APIs") can be reverted as unneeded. Nícolas, can
> you check that? If it works, we better revert the unneeded checks.

FYI, just tested based on the Android Common Kernel android-mainline branch,
with only the following two changes, the issue is not reported too:
    9dedabe95b49 spi: Assign dummy scatterlist to unidirectional transfers
    9f788ba457b4 spi: Don't mark message DMA mapped when no transfer in it is
diff mbox series

Patch

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index f94420858c22..9bc9fd10d538 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1220,6 +1220,11 @@  void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
 	spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0);
 }
 
+/* Dummy SG for unidirect transfers */
+static struct scatterlist dummy_sg = {
+	.page_link = SG_END,
+};
+
 static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
 {
 	struct device *tx_dev, *rx_dev;
@@ -1258,6 +1263,8 @@  static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
 						attrs);
 			if (ret != 0)
 				return ret;
+		} else {
+			xfer->tx_sg.sgl = &dummy_sg;
 		}
 
 		if (xfer->rx_buf != NULL) {
@@ -1271,6 +1278,8 @@  static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
 
 				return ret;
 			}
+		} else {
+			xfer->rx_sg.sgl = &dummy_sg;
 		}
 	}
 	/* No transfer has been mapped, bail out with success */