[PATCH] mtd: rawnand: cadence: avoid NULL dereference of DMA device pointer

From: niravkumarlaxmidas . rabara

Date: Tue Oct 28 2025 - 01:46:53 EST


From: Niravkumar L Rabara <niravkumarlaxmidas.rabara@xxxxxxxxxx>

The cdns_ctrl->dmac->device was accessed unconditionally, even when
'has_dma' is false and cdns_ctrl->dmac is not assigned. This could lead to
a NULL pointer dereference when DMA is not used.

Rework the logic so that DMA mapping and unmapping are performed only when
cdns_ctrl->dmac is valid. When DMA is not used, the I/O resource address
is used directly. Also a proper check is added before calling
dma_unmap_resource().

Fixes: 5c56bf214af8 ("mtd: rawnand: cadence: fix DMA device NULL pointer dereference")
Reported-by: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
Closes: https://lore.kernel.org/all/aP8S9oEgMv6PXzax@stanley.mountain/
Signed-off-by: Niravkumar L Rabara <niravkumarlaxmidas.rabara@xxxxxxxxxx>
---

- The changes were verified using Smatch and tested on the Intel Agilex5
SoCFPGA development kit.

.../mtd/nand/raw/cadence-nand-controller.c | 27 ++++++++++---------
1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index 32ed38b89394..5a40e0560984 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -2871,7 +2871,6 @@ cadence_nand_irq_cleanup(int irqnum, struct cdns_nand_ctrl *cdns_ctrl)
static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
{
dma_cap_mask_t mask;
- struct dma_device *dma_dev;
int ret;

cdns_ctrl->cdma_desc = dma_alloc_coherent(cdns_ctrl->dev,
@@ -2913,17 +2912,19 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
"%d: Failed to get a DMA channel\n", ret);
goto disable_irq;
}
- }

- dma_dev = cdns_ctrl->dmac->device;
- cdns_ctrl->io.iova_dma = dma_map_resource(dma_dev->dev, cdns_ctrl->io.dma,
- cdns_ctrl->io.size,
- DMA_BIDIRECTIONAL, 0);
+ cdns_ctrl->io.iova_dma = dma_map_resource(cdns_ctrl->dmac->device->dev,
+ cdns_ctrl->io.dma, cdns_ctrl->io.size,
+ DMA_BIDIRECTIONAL, 0);

- ret = dma_mapping_error(dma_dev->dev, cdns_ctrl->io.iova_dma);
- if (ret) {
- dev_err(cdns_ctrl->dev, "Failed to map I/O resource to DMA\n");
- goto dma_release_chnl;
+ ret = dma_mapping_error(cdns_ctrl->dmac->device->dev,
+ cdns_ctrl->io.iova_dma);
+ if (ret) {
+ dev_err(cdns_ctrl->dev, "Failed to map I/O resource to DMA\n");
+ goto dma_release_chnl;
+ }
+ } else {
+ cdns_ctrl->io.iova_dma = cdns_ctrl->io.dma;
}

nand_controller_init(&cdns_ctrl->controller);
@@ -2949,8 +2950,10 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
return 0;

unmap_dma_resource:
- dma_unmap_resource(dma_dev->dev, cdns_ctrl->io.iova_dma,
- cdns_ctrl->io.size, DMA_BIDIRECTIONAL, 0);
+ if (cdns_ctrl->dmac && cdns_ctrl->dmac->device)
+ dma_unmap_resource(cdns_ctrl->dmac->device->dev,
+ cdns_ctrl->io.iova_dma, cdns_ctrl->io.size,
+ DMA_BIDIRECTIONAL, 0);

dma_release_chnl:
if (cdns_ctrl->dmac)
--
2.25.1