Reviewed-by: Robin Gong <yibin.gong@xxxxxxx> > -----Original Message----- > From: Sven Van Asbroeck <thesven73@xxxxxxxxx> > Subject: [PATCH] dmaengine: imx-sdma: fix use-after-free on probe error path > > If probe() fails anywhere beyond the point where > sdma_get_firmware() is called, then a kernel oops may occur. > > Problematic sequence of events: > 1. probe() calls sdma_get_firmware(), which schedules the > firmware callback to run when firmware becomes available, > using the sdma instance structure as the context 2. probe() encounters an > error, which deallocates the > sdma instance structure > 3. firmware becomes available, firmware callback is > called with deallocated sdma instance structure 4. use after free - kernel > oops ! > > Solution: only attempt to load firmware when we're certain that probe() will > succeed. This guarantees that the firmware callback's context will remain valid. > > Note that the remove() path is unaffected by this issue: the firmware loader will > increment the driver module's use count, ensuring that the module cannot be > unloaded while the firmware callback is pending or running. > > To: Robin Gong <yibin.gong@xxxxxxx> > Cc: Vinod Koul <vkoul@xxxxxxxxxx> > Cc: Dan Williams <dan.j.williams@xxxxxxxxx> > Cc: Shawn Guo <shawnguo@xxxxxxxxxx> > Cc: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > Cc: Pengutronix Kernel Team <kernel@xxxxxxxxxxxxxx> > Cc: Fabio Estevam <festevam@xxxxxxxxx> > Cc: NXP Linux Team <linux-imx@xxxxxxx> > Cc: dmaengine@xxxxxxxxxxxxxxx > Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx > Cc: linux-kernel@xxxxxxxxxxxxxxx > Signed-off-by: Sven Van Asbroeck <TheSven73@xxxxxxxxx> > --- > drivers/dma/imx-sdma.c | 48 ++++++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 21 deletions(-) > > diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index > 99d9f431ae2c..3f0f41d16e1c 100644 > --- a/drivers/dma/imx-sdma.c > +++ b/drivers/dma/imx-sdma.c > @@ -2096,27 +2096,6 @@ static int sdma_probe(struct platform_device > *pdev) > if (pdata && pdata->script_addrs) > sdma_add_scripts(sdma, pdata->script_addrs); > > - if (pdata) { > - ret = sdma_get_firmware(sdma, pdata->fw_name); > - if (ret) > - dev_warn(&pdev->dev, "failed to get firmware from platform > data\n"); > - } else { > - /* > - * Because that device tree does not encode ROM script address, > - * the RAM script in firmware is mandatory for device tree > - * probe, otherwise it fails. > - */ > - ret = of_property_read_string(np, "fsl,sdma-ram-script-name", > - &fw_name); > - if (ret) > - dev_warn(&pdev->dev, "failed to get firmware name\n"); > - else { > - ret = sdma_get_firmware(sdma, fw_name); > - if (ret) > - dev_warn(&pdev->dev, "failed to get firmware from device > tree\n"); > - } > - } > - > sdma->dma_device.dev = &pdev->dev; > > sdma->dma_device.device_alloc_chan_resources = > sdma_alloc_chan_resources; @@ -2161,6 +2140,33 @@ static int > sdma_probe(struct platform_device *pdev) > of_node_put(spba_bus); > } > > + /* > + * Kick off firmware loading as the very last step: > + * attempt to load firmware only if we're not on the error path, because > + * the firmware callback requires a fully functional and allocated sdma > + * instance. > + */ > + if (pdata) { > + ret = sdma_get_firmware(sdma, pdata->fw_name); > + if (ret) > + dev_warn(&pdev->dev, "failed to get firmware from platform > data\n"); > + } else { > + /* > + * Because that device tree does not encode ROM script address, > + * the RAM script in firmware is mandatory for device tree > + * probe, otherwise it fails. > + */ > + ret = of_property_read_string(np, "fsl,sdma-ram-script-name", > + &fw_name); > + if (ret) > + dev_warn(&pdev->dev, "failed to get firmware name\n"); > + else { > + ret = sdma_get_firmware(sdma, fw_name); > + if (ret) > + dev_warn(&pdev->dev, "failed to get firmware from device > tree\n"); > + } > + } > + > return 0; > > err_register: > -- > 2.17.1