linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] mwifiex: fix use-after-free for FW reinit errors
@ 2017-03-28 23:59 Brian Norris
  2017-03-28 23:59 ` [PATCH 2/2] mwifiex: catch mwifiex_fw_dpc() errors properly in reset Brian Norris
  2017-04-05 12:44 ` [1/2] mwifiex: fix use-after-free for FW reinit errors Kalle Valo
  0 siblings, 2 replies; 3+ messages in thread
From: Brian Norris @ 2017-03-28 23:59 UTC (permalink / raw)
  To: Amitkumar Karwar, Nishant Sarmukadam, Ganapathi Bhat, Xinming Hu
  Cc: linux-kernel, Kalle Valo, linux-wireless, Brian Norris

If we fail to reinit the FW when resetting the device (in the
synchronous version of mwifiex_init_hw_fw() -> mwifiex_fw_dpc()),
mwifiex_fw_dpc() will tear down the interface and free up the adapter.
But we don't actually check for all failure cases of mwifiex_fw_dpc(),
so some of them fall through and dereference adapter->fw_done with a
freed adapter, causing a use-after-free bug.

In any case, mwifiex_fw_dpc() will always signal FW completion -- in the
error OR success case -- so at best, this was repeat work. Let's not do
it.

Signed-off-by: Brian Norris <briannorris@chromium.org>
---
 drivers/net/wireless/marvell/mwifiex/main.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 30f49944661f..98c83453ba5b 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -1475,7 +1475,6 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter)
 	}
 	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
 
-	complete_all(adapter->fw_done);
 	return 0;
 
 err_init_fw:
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] mwifiex: catch mwifiex_fw_dpc() errors properly in reset
  2017-03-28 23:59 [PATCH 1/2] mwifiex: fix use-after-free for FW reinit errors Brian Norris
@ 2017-03-28 23:59 ` Brian Norris
  2017-04-05 12:44 ` [1/2] mwifiex: fix use-after-free for FW reinit errors Kalle Valo
  1 sibling, 0 replies; 3+ messages in thread
From: Brian Norris @ 2017-03-28 23:59 UTC (permalink / raw)
  To: Amitkumar Karwar, Nishant Sarmukadam, Ganapathi Bhat, Xinming Hu
  Cc: linux-kernel, Kalle Valo, linux-wireless, Brian Norris

When resetting the device, we take a synchronous firmware-loading code
path, which borrows a lot from the asynchronous path used at probe time.
We don't catch errors correctly though, which means that in the PCIe
driver, we may try to dereference the 'adapter' struct after
mwifiex_fw_dpc() has freed it. See this (erronous) print in
mwifiex_pcie_reset_notify():

	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);

Let's instead refactor the synchronous (or "!req_fw_nowait") path so
that we propagate errors and handle them properly.

This fixes a use-after-free issue in the PCIe driver, as well as a
misleading debug message ("successful"). It looks like the SDIO driver
doesn't have these problems, since it doesn't do anything after
mwifiex_reinit_sw().

Fixes: 4c5dae59d2e9 ("mwifiex: add PCIe function level reset support")
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
 drivers/net/wireless/marvell/mwifiex/main.c | 33 +++++++++++++++++++----------
 drivers/net/wireless/marvell/mwifiex/pcie.c |  7 +++++-
 drivers/net/wireless/marvell/mwifiex/sdio.c |  5 ++++-
 3 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 98c83453ba5b..0dfbac850689 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -512,7 +512,7 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
  *      - Download the correct firmware to card
  *      - Issue the init commands to firmware
  */
-static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
+static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 {
 	int ret;
 	char fmt[64];
@@ -665,11 +665,18 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 		mwifiex_free_adapter(adapter);
 	/* Tell all current and future waiters we're finished */
 	complete_all(fw_done);
-	return;
+
+	return init_failed ? -EIO : 0;
+}
+
+static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
+{
+	_mwifiex_fw_dpc(firmware, context);
 }
 
 /*
- * This function initializes the hardware and gets firmware.
+ * This function gets the firmware and (if called asynchronously) kicks off the
+ * HW init when done.
  */
 static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter,
 			      bool req_fw_nowait)
@@ -692,20 +699,15 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter,
 		ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
 					      adapter->dev, GFP_KERNEL, adapter,
 					      mwifiex_fw_dpc);
-		if (ret < 0)
-			mwifiex_dbg(adapter, ERROR,
-				    "request_firmware_nowait error %d\n", ret);
 	} else {
 		ret = request_firmware(&adapter->firmware,
 				       adapter->fw_name,
 				       adapter->dev);
-		if (ret < 0)
-			mwifiex_dbg(adapter, ERROR,
-				    "request_firmware error %d\n", ret);
-		else
-			mwifiex_fw_dpc(adapter->firmware, (void *)adapter);
 	}
 
+	if (ret < 0)
+		mwifiex_dbg(adapter, ERROR, "request_firmware%s error %d\n",
+			    req_fw_nowait ? "_nowait" : "", ret);
 	return ret;
 }
 
@@ -1427,6 +1429,8 @@ EXPORT_SYMBOL_GPL(mwifiex_shutdown_sw);
 int
 mwifiex_reinit_sw(struct mwifiex_adapter *adapter)
 {
+	int ret;
+
 	mwifiex_init_lock_list(adapter);
 	if (adapter->if_ops.up_dev)
 		adapter->if_ops.up_dev(adapter);
@@ -1473,6 +1477,13 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter)
 			    "%s: firmware init failed\n", __func__);
 		goto err_init_fw;
 	}
+
+	/* _mwifiex_fw_dpc() does its own cleanup */
+	ret = _mwifiex_fw_dpc(adapter->firmware, adapter);
+	if (ret) {
+		pr_err("Failed to bring up adapter: %d\n", ret);
+		return ret;
+	}
 	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
 
 	return 0;
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index e381deff37f3..f45ab125cd0d 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -350,6 +350,7 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
 {
 	struct pcie_service_card *card = pci_get_drvdata(pdev);
 	struct mwifiex_adapter *adapter = card->adapter;
+	int ret;
 
 	if (!adapter) {
 		dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
@@ -376,7 +377,11 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare)
 		 * and firmware including firmware redownload
 		 */
 		adapter->surprise_removed = false;
-		mwifiex_reinit_sw(adapter);
+		ret = mwifiex_reinit_sw(adapter);
+		if (ret) {
+			dev_err(&pdev->dev, "reinit failed: %d\n", ret);
+			return;
+		}
 	}
 	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
 }
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 58d3da09cfbd..424532b81c2d 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -2196,6 +2196,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
 {
 	struct sdio_mmc_card *card = adapter->card;
 	struct sdio_func *func = card->func;
+	int ret;
 
 	mwifiex_shutdown_sw(adapter);
 
@@ -2210,7 +2211,9 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
 	clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
 	clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
 
-	mwifiex_reinit_sw(adapter);
+	ret = mwifiex_reinit_sw(adapter);
+	if (ret)
+		dev_err(&func->dev, "reinit failed: %d\n", ret);
 }
 
 /* This function read/write firmware */
-- 
2.12.2.564.g063fe858b8-goog

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [1/2] mwifiex: fix use-after-free for FW reinit errors
  2017-03-28 23:59 [PATCH 1/2] mwifiex: fix use-after-free for FW reinit errors Brian Norris
  2017-03-28 23:59 ` [PATCH 2/2] mwifiex: catch mwifiex_fw_dpc() errors properly in reset Brian Norris
@ 2017-04-05 12:44 ` Kalle Valo
  1 sibling, 0 replies; 3+ messages in thread
From: Kalle Valo @ 2017-04-05 12:44 UTC (permalink / raw)
  To: Brian Norris
  Cc: Amitkumar Karwar, Nishant Sarmukadam, Ganapathi Bhat, Xinming Hu,
	linux-kernel, linux-wireless, Brian Norris

Brian Norris <briannorris@chromium.org> wrote:
> If we fail to reinit the FW when resetting the device (in the
> synchronous version of mwifiex_init_hw_fw() -> mwifiex_fw_dpc()),
> mwifiex_fw_dpc() will tear down the interface and free up the adapter.
> But we don't actually check for all failure cases of mwifiex_fw_dpc(),
> so some of them fall through and dereference adapter->fw_done with a
> freed adapter, causing a use-after-free bug.
> 
> In any case, mwifiex_fw_dpc() will always signal FW completion -- in the
> error OR success case -- so at best, this was repeat work. Let's not do
> it.
> 
> Signed-off-by: Brian Norris <briannorris@chromium.org>

2 patches applied to wireless-drivers-next.git, thanks.

ce8fad9a1f09 mwifiex: fix use-after-free for FW reinit errors
755b37c93a06 mwifiex: catch mwifiex_fw_dpc() errors properly in reset

-- 
https://patchwork.kernel.org/patch/9650725/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-04-05 12:44 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-03-28 23:59 [PATCH 1/2] mwifiex: fix use-after-free for FW reinit errors Brian Norris
2017-03-28 23:59 ` [PATCH 2/2] mwifiex: catch mwifiex_fw_dpc() errors properly in reset Brian Norris
2017-04-05 12:44 ` [1/2] mwifiex: fix use-after-free for FW reinit errors Kalle Valo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).