libertas: move firmware lifetime handling to firmware.c
authorDan Williams <dcbw@redhat.com>
Mon, 14 Oct 2013 22:51:55 +0000 (17:51 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 18 Oct 2013 18:03:54 +0000 (14:03 -0400)
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>
drivers/net/wireless/libertas/firmware.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/if_usb.c

index c0f9e7e862f66e8bfcb549ae4a7f3ba7425306ae..51b92b5df11956adfedadb5137f8f6b61342b0c4 100644 (file)
@@ -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)
index c94dd6802672a053d795b052710d5ada4ff3e2bb..ef8c98e21098479d231df5844fb2abab8ddab04f 100644 (file)
@@ -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);
 }
 
 
index 45578335e4200f2f47a3fc8284f9bd09127209ee..991238afd1b60c04ae437fafeb7a108713ea3134 100644 (file)
@@ -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)
index 5d39ec880d84350bd270b0115b87574582fa0fed..83669151bb8242e31931735700eb27fe4cd01821 100644 (file)
@@ -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;
 }
 
index 27980778d992db783e58f777446a1cc03d40c28c..dff08a2896a38f644894749c006787e26b1f3ea6 100644 (file)
@@ -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);
 }