OSDN Git Service

iwlwifi: fix leaks/bad data after failed firmware load
authorJohannes Berg <johannes.berg@intel.com>
Fri, 10 Dec 2021 09:12:42 +0000 (11:12 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Tue, 21 Dec 2021 10:35:05 +0000 (12:35 +0200)
If firmware load fails after having loaded some parts of the
firmware, e.g. the IML image, then this would leak. For the
host command list we'd end up running into a WARN on the next
attempt to load another firmware image.

Fix this by calling iwl_dealloc_ucode() on failures, and make
that also clear the data so we start fresh on the next round.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20211210110539.1f742f0eb58a.I1315f22f6aa632d94ae2069f85e1bca5e734dce0@changeid
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-drv.c

index 9652da2..4dab1e8 100644 (file)
@@ -130,6 +130,9 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
 
        for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
                iwl_free_fw_img(drv, drv->fw.img + i);
+
+       /* clear the data for the aborted load case */
+       memset(&drv->fw, 0, sizeof(drv->fw));
 }
 
 static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
@@ -1426,6 +1429,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
        int i;
        bool load_module = false;
        bool usniffer_images = false;
+       bool failure = true;
 
        fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH;
        fw->ucode_capa.standard_phy_calibration_size =
@@ -1695,6 +1699,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                                op->name, err);
 #endif
        }
+       failure = false;
        goto free;
 
  try_again:
@@ -1710,6 +1715,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
        complete(&drv->request_firmware_complete);
        device_release_driver(drv->trans->dev);
  free:
+       if (failure)
+               iwl_dealloc_ucode(drv);
+
        if (pieces) {
                for (i = 0; i < ARRAY_SIZE(pieces->img); i++)
                        kfree(pieces->img[i].sec);