linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Brian Norris <briannorris@chromium.org>
To: Xinming Hu <huxinming820@gmail.com>
Cc: Linux Wireless <linux-wireless@vger.kernel.org>,
	Kalle Valo <kvalo@qca.qualcomm.com>,
	Dmitry Torokhov <dtor@google.com>,
	Amitkumar Karwar <akarwar@marvell.com>,
	Cathy Luo <cluo@marvell.com>
Subject: Re: [PATCH RESEND v2 03/11] mwifiex: resolve races between async FW init (failure) and device removal
Date: Thu, 10 Nov 2016 10:37:24 -0800	[thread overview]
Message-ID: <20161110183723.GA134624@google.com> (raw)
In-Reply-To: <1478779032-5165-3-git-send-email-huxinming820@marvell.com>

Hi,

On Thu, Nov 10, 2016 at 07:57:04PM +0800, Xinming Hu wrote:
> From: Brian Norris <briannorris@chromium.org>
> 
> It's possible for the FW init sequence to fail, which will trigger a
> device cleanup sequence in mwifiex_fw_dpc(). This sequence can race with
> device suspend() or remove() (e.g., reboot or unbind), and can trigger
> use-after-free issues. Currently, this driver attempts (poorly) to
> synchronize remove() using a semaphore, but it doesn't protect some of
> the critical sections properly. Particularly, we grab a pointer to the
> adapter struct (card->adapter) without checking if it's being freed or
> not. We later do a NULL check on the adapter, but that doesn't work if
> the adapter was freed.
> 
> Also note that the PCIe interface driver doesn't ever set card->adapter
> to NULL, so even if we get the synchronization right, we still might try
> to redo the cleanup in ->remove(), even if the FW init failure sequence
> already did it.
> 
> This patch replaces the static semaphore with a per-device completion
> struct, and uses that completion to synchronize the remove() thread with
> the mwifiex_fw_dpc(). A future patch will utilize this completion to
> synchronize the suspend() thread as well.
> 
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> ---
> v2: Same as v1
> ---
>  drivers/net/wireless/marvell/mwifiex/main.c | 46 ++++++++++-------------------
>  drivers/net/wireless/marvell/mwifiex/main.h | 13 +++++---
>  drivers/net/wireless/marvell/mwifiex/pcie.c | 18 +++++------
>  drivers/net/wireless/marvell/mwifiex/pcie.h |  2 ++
>  drivers/net/wireless/marvell/mwifiex/sdio.c | 18 +++++------
>  drivers/net/wireless/marvell/mwifiex/sdio.h |  2 ++
>  drivers/net/wireless/marvell/mwifiex/usb.c  | 23 +++++++--------
>  drivers/net/wireless/marvell/mwifiex/usb.h  |  2 ++
>  8 files changed, 55 insertions(+), 69 deletions(-)
> 
> diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
> index c710d5e..09d46d6 100644
> --- a/drivers/net/wireless/marvell/mwifiex/main.c
> +++ b/drivers/net/wireless/marvell/mwifiex/main.c
> @@ -521,7 +521,6 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
>  	struct mwifiex_private *priv;
>  	struct mwifiex_adapter *adapter = context;
>  	struct mwifiex_fw_image fw;
> -	struct semaphore *sem = adapter->card_sem;
>  	bool init_failed = false;
>  	struct wireless_dev *wdev;
>  
> @@ -670,7 +669,8 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
>  	}
>  	if (init_failed)
>  		mwifiex_free_adapter(adapter);
> -	up(sem);
> +	/* Tell all current and future waiters we're finished */
> +	complete_all(adapter->fw_done);

This part introduces a new use-after-free. We need to dereference
adapter->fw_done *before* we free the adapter in mwifiex_free_adapter().
So you need a diff that looks something like this:

--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -514,6 +514,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 	struct mwifiex_fw_image fw;
 	bool init_failed = false;
 	struct wireless_dev *wdev;
+	struct completion *fw_done = adapter->fw_done;
 
 	if (!firmware) {
 		mwifiex_dbg(adapter, ERROR,
@@ -654,7 +655,7 @@ done:
 	if (init_failed)
 		mwifiex_free_adapter(adapter);
 	/* Tell all current and future waiters we're finished */
-	complete_all(adapter->fw_done);
+	complete_all(fw_done);
 	return;
 }

 
Brian

>  	return;
>  }
>  
...

  reply	other threads:[~2016-11-10 18:37 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-10 11:57 [PATCH RESEND v2 01/11] mwifiex: check tx_hw_pending before downloading sleep confirm Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 02/11] mwifiex: complete blocked power save handshake in main process Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 03/11] mwifiex: resolve races between async FW init (failure) and device removal Xinming Hu
2016-11-10 18:37   ` Brian Norris [this message]
2016-11-11 13:06     ` Amitkumar Karwar
2016-11-10 11:57 ` [PATCH RESEND v2 04/11] mwifiex: remove redundant pdev check in suspend/resume handlers Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 05/11] mwifiex: don't pretend to resume while remove()'ing Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 06/11] mwifiex: resolve suspend() race with async FW init failure Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 07/11] mwifiex: reset card->adapter during device unregister Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 08/11] mwifiex: usb: handle HS failures Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 09/11] mwifiex: sdio: don't check for NULL sdio_func Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 10/11] mwifiex: stop checking for NULL drvata/intfdata Xinming Hu
2016-11-10 11:57 ` [PATCH RESEND v2 11/11] mwifiex: pcie: stop checking for NULL adapter->card Xinming Hu
2016-11-10 14:06 ` [PATCH RESEND v2 01/11] mwifiex: check tx_hw_pending before downloading sleep confirm Kalle Valo
2016-11-11 13:09   ` Amitkumar Karwar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161110183723.GA134624@google.com \
    --to=briannorris@chromium.org \
    --cc=akarwar@marvell.com \
    --cc=cluo@marvell.com \
    --cc=dtor@google.com \
    --cc=huxinming820@gmail.com \
    --cc=kvalo@qca.qualcomm.com \
    --cc=linux-wireless@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).