]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Nov 2020 18:08:55 +0000 (19:08 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Nov 2020 18:08:55 +0000 (19:08 +0100)
added patches:
spi-bcm-qspi-fix-use-after-free-on-unbind.patch

queue-4.19/series [new file with mode: 0644]
queue-4.19/spi-bcm-qspi-fix-use-after-free-on-unbind.patch [new file with mode: 0644]

diff --git a/queue-4.19/series b/queue-4.19/series
new file mode 100644 (file)
index 0000000..d4bd8a2
--- /dev/null
@@ -0,0 +1 @@
+spi-bcm-qspi-fix-use-after-free-on-unbind.patch
diff --git a/queue-4.19/spi-bcm-qspi-fix-use-after-free-on-unbind.patch b/queue-4.19/spi-bcm-qspi-fix-use-after-free-on-unbind.patch
new file mode 100644 (file)
index 0000000..f3d7450
--- /dev/null
@@ -0,0 +1,134 @@
+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;
+ }