Search Linux Wireless

[PATCH 3.5] iwlwifi: fix double free/complete in firmware loading

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Johannes Berg <johannes.berg@xxxxxxxxx>

Linus reported that due to mac80211 failing to register
the device (due to WoWLAN) his machine crashed etc. as
we double-freed the vmalloc() firmware area. His patch
to fix it was very similar to this one but I noticed
that there's another bug in the area: we complete the
completion before starting, so since we're running in
a work struct context stop() could be called while in
the middle of start() which will almost certainly lead
to issues.

Make a modification similar to his to avoid the double-
free but also move the completion to another spot so it
is only done after start() either finished or failed so
that stop() can have a consistent state.

Reported-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx>
---
 drivers/net/wireless/iwlwifi/iwl-drv.c |   14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index d742900..1f4d6af 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -861,13 +861,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 
 	/* We have our copies now, allow OS release its copies */
 	release_firmware(ucode_raw);
-	complete(&drv->request_firmware_complete);
 
 	drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw);
 
-	if (!drv->op_mode)
-		goto out_free_fw;
+	if (!drv->op_mode) {
+		complete(&drv->request_firmware_complete);
+		goto out_release_driver;
+	}
 
+	/*
+	 * Complete the firmware request last so that
+	 * a driver unbind (stop) doesn't run while we
+	 * are doing the start() above.
+	 */
+	complete(&drv->request_firmware_complete);
 	return;
 
  try_again:
@@ -883,6 +890,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 	release_firmware(ucode_raw);
  out_unbind:
 	complete(&drv->request_firmware_complete);
+ out_release_driver:
 	device_release_driver(drv->trans->dev);
 }
 
-- 
1.7.10



--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux