Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1dfba306 authored by Dan Williams's avatar Dan Williams Committed by John W. Linville
Browse files

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: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e07f01e4
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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)
+2 −6
Original line number Diff line number Diff line
@@ -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);
}


+2 −6
Original line number Diff line number Diff line
@@ -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)
+0 −4
Original line number Diff line number Diff line
@@ -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;
}

+7 −10
Original line number Diff line number Diff line
@@ -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 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
	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 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
		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 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,

		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 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
	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);
}