summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-10-14 17:51:55 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-10-18 14:03:54 -0400
commit1dfba3060fe7ee03ccec25a91d35085142dfc295 (patch)
treec27da4ef59aeaa75b1d39c46af0aeed4f7ba7147
parente07f01e4c7d583adb1ec25e63a52db5fc10a94d3 (diff)
libertas: move firmware lifetime handling to firmware.c
Previously, each bus type was responsible for freeing the firmware structure, but some did that badly. Move responsibility for freeing firmware into firmware.c so that it's done once and correctly, instead of happening in multiple places in bus-specific code. This fixes a use-after-free bug found by Dr. H. Nikolaus Schaller where the SDIO code forgot to NULL priv->helper_fw after freeing it. Signed-off-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/libertas/firmware.c5
-rw-r--r--drivers/net/wireless/libertas/if_cs.c8
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c8
-rw-r--r--drivers/net/wireless/libertas/if_spi.c4
-rw-r--r--drivers/net/wireless/libertas/if_usb.c17
5 files changed, 16 insertions, 26 deletions
diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c
index c0f9e7e862f..51b92b5df11 100644
--- a/drivers/net/wireless/libertas/firmware.c
+++ b/drivers/net/wireless/libertas/firmware.c
@@ -53,6 +53,11 @@ static void main_firmware_cb(const struct firmware *firmware, void *context)
/* Firmware found! */
lbs_fw_loaded(priv, 0, priv->helper_fw, firmware);
+ if (priv->helper_fw) {
+ release_firmware (priv->helper_fw);
+ priv->helper_fw = NULL;
+ }
+ release_firmware (firmware);
}
static void helper_firmware_cb(const struct firmware *firmware, void *context)
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index c94dd680267..ef8c98e2109 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -754,14 +754,14 @@ static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
if (ret == 0 && (card->model != MODEL_8305))
ret = if_cs_prog_real(card, mainfw);
if (ret)
- goto out;
+ return;
/* Now actually get the IRQ */
ret = request_irq(card->p_dev->irq, if_cs_interrupt,
IRQF_SHARED, DRV_NAME, card);
if (ret) {
pr_err("error in request_irq\n");
- goto out;
+ return;
}
/*
@@ -777,10 +777,6 @@ static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
pr_err("could not activate card\n");
free_irq(card->p_dev->irq, card);
}
-
-out:
- release_firmware(helper);
- release_firmware(mainfw);
}
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 45578335e42..991238afd1b 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -708,20 +708,16 @@ static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret,
ret = if_sdio_prog_helper(card, helper);
if (ret)
- goto out;
+ return;
lbs_deb_sdio("Helper firmware loaded\n");
ret = if_sdio_prog_real(card, mainfw);
if (ret)
- goto out;
+ return;
lbs_deb_sdio("Firmware loaded\n");
if_sdio_finish_power_on(card);
-
-out:
- release_firmware(helper);
- release_firmware(mainfw);
}
static int if_sdio_prog_firmware(struct if_sdio_card *card)
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 5d39ec880d8..83669151bb8 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -1094,11 +1094,7 @@ static int if_spi_init_card(struct if_spi_card *card)
goto out;
out:
- release_firmware(helper);
- release_firmware(mainfw);
-
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
-
return err;
}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 27980778d99..dff08a2896a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -844,7 +844,7 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
cardp->fw = fw;
if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
ret = -EINVAL;
- goto release_fw;
+ goto done;
}
/* Cancel any pending usb business */
@@ -861,7 +861,7 @@ restart:
if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
ret = -EIO;
- goto release_fw;
+ goto done;
}
cardp->bootcmdresp = 0;
@@ -883,14 +883,14 @@ restart:
usb_kill_urb(cardp->tx_urb);
if (if_usb_submit_rx_urb(cardp) < 0)
ret = -EIO;
- goto release_fw;
+ goto done;
} else if (cardp->bootcmdresp <= 0) {
if (--reset_count >= 0) {
if_usb_reset_device(cardp);
goto restart;
}
ret = -EIO;
- goto release_fw;
+ goto done;
}
i = 0;
@@ -921,14 +921,14 @@ restart:
pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -EIO;
- goto release_fw;
+ goto done;
}
cardp->priv->fw_ready = 1;
if_usb_submit_rx_urb(cardp);
if (lbs_start_card(priv))
- goto release_fw;
+ goto done;
if_usb_setup_firmware(priv);
@@ -939,11 +939,8 @@ restart:
if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
priv->ehs_remove_supported = false;
- release_fw:
- release_firmware(cardp->fw);
- cardp->fw = NULL;
-
done:
+ cardp->fw = NULL;
lbs_deb_leave(LBS_DEB_USB);
}