-spi-bcm-qspi-fix-use-after-free-on-unbind.patch
+++ /dev/null
-From foo@baz Tue Nov 24 07:06:21 PM CET 2020
-From: Lukas Wunner <lukas@wunner.de>
-Date: Wed, 11 Nov 2020 20:07:40 +0100
-Subject: spi: bcm-qspi: Fix use-after-free on unbind
-
-From: Lukas Wunner <lukas@wunner.de>
-
-commit 63c5395bb7a9777a33f0e7b5906f2c0170a23692 upstream
-
-bcm_qspi_remove() calls spi_unregister_master() even though
-bcm_qspi_probe() calls devm_spi_register_master(). The spi_master is
-therefore unregistered and freed twice on unbind.
-
-Moreover, since commit 0392727c261b ("spi: bcm-qspi: Handle clock probe
-deferral"), bcm_qspi_probe() leaks the spi_master allocation if the call
-to devm_clk_get_optional() fails.
-
-Fix by switching over to the new devm_spi_alloc_master() helper which
-keeps the private data accessible until the driver has unbound and also
-avoids the spi_master leak on probe.
-
-While at it, fix an ordering issue in bcm_qspi_remove() wherein
-spi_unregister_master() is called after uninitializing the hardware,
-disabling the clock and freeing an IRQ data structure. The correct
-order is to call spi_unregister_master() *before* those teardown steps
-because bus accesses may still be ongoing until that function returns.
-
-Fixes: fa236a7ef240 ("spi: bcm-qspi: Add Broadcom MSPI driver")
-Signed-off-by: Lukas Wunner <lukas@wunner.de>
-Cc: <stable@vger.kernel.org> # v4.9+: 123456789abc: spi: Introduce device-managed SPI controller allocation
-Cc: <stable@vger.kernel.org> # v4.9+
-Cc: Kamal Dasu <kdasu.kdev@gmail.com>
-Acked-by: Florian Fainelli <f.fainelli@gmail.com>
-Tested-by: Florian Fainelli <f.fainelli@gmail.com>
-Link: https://lore.kernel.org/r/5e31a9a59fd1c0d0b795b2fe219f25e5ee855f9d.1605121038.git.lukas@wunner.de
-Signed-off-by: Mark Brown <broonie@kernel.org>
-[sudip: adjust context]
-Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/spi/spi-bcm-qspi.c | 34 ++++++++++++----------------------
- 1 file changed, 12 insertions(+), 22 deletions(-)
-
---- a/drivers/spi/spi-bcm-qspi.c
-+++ b/drivers/spi/spi-bcm-qspi.c
-@@ -1219,7 +1219,7 @@ int bcm_qspi_probe(struct platform_devic
- if (!of_match_node(bcm_qspi_of_match, dev->of_node))
- return -ENODEV;
-
-- master = spi_alloc_master(dev, sizeof(struct bcm_qspi));
-+ master = devm_spi_alloc_master(dev, sizeof(struct bcm_qspi));
- if (!master) {
- dev_err(dev, "error allocating spi_master\n");
- return -ENOMEM;
-@@ -1253,21 +1253,17 @@ int bcm_qspi_probe(struct platform_devic
-
- if (res) {
- qspi->base[MSPI] = devm_ioremap_resource(dev, res);
-- if (IS_ERR(qspi->base[MSPI])) {
-- ret = PTR_ERR(qspi->base[MSPI]);
-- goto qspi_resource_err;
-- }
-+ if (IS_ERR(qspi->base[MSPI]))
-+ return PTR_ERR(qspi->base[MSPI]);
- } else {
-- goto qspi_resource_err;
-+ return 0;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
- if (res) {
- qspi->base[BSPI] = devm_ioremap_resource(dev, res);
-- if (IS_ERR(qspi->base[BSPI])) {
-- ret = PTR_ERR(qspi->base[BSPI]);
-- goto qspi_resource_err;
-- }
-+ if (IS_ERR(qspi->base[BSPI]))
-+ return PTR_ERR(qspi->base[BSPI]);
- qspi->bspi_mode = true;
- } else {
- qspi->bspi_mode = false;
-@@ -1278,18 +1274,14 @@ int bcm_qspi_probe(struct platform_devic
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs_reg");
- if (res) {
- qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res);
-- if (IS_ERR(qspi->base[CHIP_SELECT])) {
-- ret = PTR_ERR(qspi->base[CHIP_SELECT]);
-- goto qspi_resource_err;
-- }
-+ if (IS_ERR(qspi->base[CHIP_SELECT]))
-+ return PTR_ERR(qspi->base[CHIP_SELECT]);
- }
-
- qspi->dev_ids = kcalloc(num_irqs, sizeof(struct bcm_qspi_dev_id),
- GFP_KERNEL);
-- if (!qspi->dev_ids) {
-- ret = -ENOMEM;
-- goto qspi_resource_err;
-- }
-+ if (!qspi->dev_ids)
-+ return -ENOMEM;
-
- for (val = 0; val < num_irqs; val++) {
- irq = -1;
-@@ -1365,7 +1357,7 @@ int bcm_qspi_probe(struct platform_devic
- qspi->xfer_mode.addrlen = -1;
- qspi->xfer_mode.hp = -1;
-
-- ret = devm_spi_register_master(&pdev->dev, master);
-+ ret = spi_register_master(master);
- if (ret < 0) {
- dev_err(dev, "can't register master\n");
- goto qspi_reg_err;
-@@ -1378,8 +1370,6 @@ qspi_reg_err:
- clk_disable_unprepare(qspi->clk);
- qspi_probe_err:
- kfree(qspi->dev_ids);
--qspi_resource_err:
-- spi_master_put(master);
- return ret;
- }
- /* probe function to be called by SoC specific platform driver probe */
-@@ -1389,10 +1379,10 @@ int bcm_qspi_remove(struct platform_devi
- {
- struct bcm_qspi *qspi = platform_get_drvdata(pdev);
-
-+ spi_unregister_master(qspi->master);
- bcm_qspi_hw_uninit(qspi);
- clk_disable_unprepare(qspi->clk);
- kfree(qspi->dev_ids);
-- spi_unregister_master(qspi->master);
-
- return 0;
- }
-spi-bcm-qspi-fix-use-after-free-on-unbind.patch
+++ /dev/null
-From foo@baz Tue Nov 24 07:06:17 PM CET 2020
-From: Lukas Wunner <lukas@wunner.de>
-Date: Wed, 11 Nov 2020 20:07:40 +0100
-Subject: spi: bcm-qspi: Fix use-after-free on unbind
-
-From: Lukas Wunner <lukas@wunner.de>
-
-commit 63c5395bb7a9777a33f0e7b5906f2c0170a23692 upstream
-
-bcm_qspi_remove() calls spi_unregister_master() even though
-bcm_qspi_probe() calls devm_spi_register_master(). The spi_master is
-therefore unregistered and freed twice on unbind.
-
-Moreover, since commit 0392727c261b ("spi: bcm-qspi: Handle clock probe
-deferral"), bcm_qspi_probe() leaks the spi_master allocation if the call
-to devm_clk_get_optional() fails.
-
-Fix by switching over to the new devm_spi_alloc_master() helper which
-keeps the private data accessible until the driver has unbound and also
-avoids the spi_master leak on probe.
-
-While at it, fix an ordering issue in bcm_qspi_remove() wherein
-spi_unregister_master() is called after uninitializing the hardware,
-disabling the clock and freeing an IRQ data structure. The correct
-order is to call spi_unregister_master() *before* those teardown steps
-because bus accesses may still be ongoing until that function returns.
-
-Fixes: fa236a7ef240 ("spi: bcm-qspi: Add Broadcom MSPI driver")
-Signed-off-by: Lukas Wunner <lukas@wunner.de>
-Cc: <stable@vger.kernel.org> # v4.9+: 123456789abc: spi: Introduce device-managed SPI controller allocation
-Cc: <stable@vger.kernel.org> # v4.9+
-Cc: Kamal Dasu <kdasu.kdev@gmail.com>
-Acked-by: Florian Fainelli <f.fainelli@gmail.com>
-Tested-by: Florian Fainelli <f.fainelli@gmail.com>
-Link: https://lore.kernel.org/r/5e31a9a59fd1c0d0b795b2fe219f25e5ee855f9d.1605121038.git.lukas@wunner.de
-Signed-off-by: Mark Brown <broonie@kernel.org>
-[sudip: adjust context]
-Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/spi/spi-bcm-qspi.c | 34 ++++++++++++----------------------
- 1 file changed, 12 insertions(+), 22 deletions(-)
-
---- a/drivers/spi/spi-bcm-qspi.c
-+++ b/drivers/spi/spi-bcm-qspi.c
-@@ -1223,7 +1223,7 @@ int bcm_qspi_probe(struct platform_devic
- if (!of_match_node(bcm_qspi_of_match, dev->of_node))
- return -ENODEV;
-
-- master = spi_alloc_master(dev, sizeof(struct bcm_qspi));
-+ master = devm_spi_alloc_master(dev, sizeof(struct bcm_qspi));
- if (!master) {
- dev_err(dev, "error allocating spi_master\n");
- return -ENOMEM;
-@@ -1257,21 +1257,17 @@ int bcm_qspi_probe(struct platform_devic
-
- if (res) {
- qspi->base[MSPI] = devm_ioremap_resource(dev, res);
-- if (IS_ERR(qspi->base[MSPI])) {
-- ret = PTR_ERR(qspi->base[MSPI]);
-- goto qspi_resource_err;
-- }
-+ if (IS_ERR(qspi->base[MSPI]))
-+ return PTR_ERR(qspi->base[MSPI]);
- } else {
-- goto qspi_resource_err;
-+ return 0;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
- if (res) {
- qspi->base[BSPI] = devm_ioremap_resource(dev, res);
-- if (IS_ERR(qspi->base[BSPI])) {
-- ret = PTR_ERR(qspi->base[BSPI]);
-- goto qspi_resource_err;
-- }
-+ if (IS_ERR(qspi->base[BSPI]))
-+ return PTR_ERR(qspi->base[BSPI]);
- qspi->bspi_mode = true;
- } else {
- qspi->bspi_mode = false;
-@@ -1282,18 +1278,14 @@ int bcm_qspi_probe(struct platform_devic
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs_reg");
- if (res) {
- qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res);
-- if (IS_ERR(qspi->base[CHIP_SELECT])) {
-- ret = PTR_ERR(qspi->base[CHIP_SELECT]);
-- goto qspi_resource_err;
-- }
-+ if (IS_ERR(qspi->base[CHIP_SELECT]))
-+ return PTR_ERR(qspi->base[CHIP_SELECT]);
- }
-
- qspi->dev_ids = kcalloc(num_irqs, sizeof(struct bcm_qspi_dev_id),
- GFP_KERNEL);
-- if (!qspi->dev_ids) {
-- ret = -ENOMEM;
-- goto qspi_resource_err;
-- }
-+ if (!qspi->dev_ids)
-+ return -ENOMEM;
-
- for (val = 0; val < num_irqs; val++) {
- irq = -1;
-@@ -1369,7 +1361,7 @@ int bcm_qspi_probe(struct platform_devic
- qspi->xfer_mode.addrlen = -1;
- qspi->xfer_mode.hp = -1;
-
-- ret = devm_spi_register_master(&pdev->dev, master);
-+ ret = spi_register_master(master);
- if (ret < 0) {
- dev_err(dev, "can't register master\n");
- goto qspi_reg_err;
-@@ -1382,8 +1374,6 @@ qspi_reg_err:
- clk_disable_unprepare(qspi->clk);
- qspi_probe_err:
- kfree(qspi->dev_ids);
--qspi_resource_err:
-- spi_master_put(master);
- return ret;
- }
- /* probe function to be called by SoC specific platform driver probe */
-@@ -1393,10 +1383,10 @@ int bcm_qspi_remove(struct platform_devi
- {
- struct bcm_qspi *qspi = platform_get_drvdata(pdev);
-
-+ spi_unregister_master(qspi->master);
- bcm_qspi_hw_uninit(qspi);
- clk_disable_unprepare(qspi->clk);
- kfree(qspi->dev_ids);
-- spi_unregister_master(qspi->master);
-
- return 0;
- }