]> Git Repo - linux.git/commitdiff
drm/i915/uc: Fix two issues with over-size firmware files
authorJohn Harrison <[email protected]>
Wed, 21 Dec 2022 19:30:31 +0000 (11:30 -0800)
committerRodrigo Vivi <[email protected]>
Fri, 30 Dec 2022 08:04:45 +0000 (03:04 -0500)
In the case where a firmware file is too large (e.g. someone
downloaded a web page ASCII dump from github...), the firmware object
is released but the pointer is not zerod. If no other firmware file
was found then release would be called again leading to a double kfree.

Also, the size check was only being applied to the initial firmware
load not any of the subsequent attempts. So move the check into a
wrapper that is used for all loads.

Fixes: 016241168dc5 ("drm/i915/uc: use different ggtt pin offsets for uc loads")
Signed-off-by: John Harrison <[email protected]>
Reviewed-by: Daniele Ceraolo Spurio <[email protected]>
Cc: Alan Previn <[email protected]>
Cc: Rodrigo Vivi <[email protected]>
Cc: Matt Roper <[email protected]>
Cc: Jani Nikula <[email protected]>
Cc: Matthew Auld <[email protected]>
Cc: "Thomas Hellström" <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
(cherry picked from commit 4071d98b296a5bc5fd4b15ec651bd05800ec9510)
Signed-off-by: Rodrigo Vivi <[email protected]>
drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c

index 0c80ba51a4bdce745b119b0e104b41b9adfa0bd2..2bcdd192f8147176877294659727d58b9e6754f4 100644 (file)
@@ -545,6 +545,32 @@ static int check_ccs_header(struct intel_gt *gt,
        return 0;
 }
 
+static int try_firmware_load(struct intel_uc_fw *uc_fw, const struct firmware **fw)
+{
+       struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
+       struct device *dev = gt->i915->drm.dev;
+       int err;
+
+       err = firmware_request_nowarn(fw, uc_fw->file_selected.path, dev);
+
+       if (err)
+               return err;
+
+       if ((*fw)->size > INTEL_UC_RSVD_GGTT_PER_FW) {
+               drm_err(&gt->i915->drm,
+                       "%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n",
+                       intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
+                       (*fw)->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K);
+
+               /* try to find another blob to load */
+               release_firmware(*fw);
+               *fw = NULL;
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
 /**
  * intel_uc_fw_fetch - fetch uC firmware
  * @uc_fw: uC firmware
@@ -558,7 +584,6 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
        struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
        struct drm_i915_private *i915 = gt->i915;
        struct intel_uc_fw_file file_ideal;
-       struct device *dev = i915->drm.dev;
        struct drm_i915_gem_object *obj;
        const struct firmware *fw = NULL;
        bool old_ver = false;
@@ -574,20 +599,9 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
        __force_fw_fetch_failures(uc_fw, -EINVAL);
        __force_fw_fetch_failures(uc_fw, -ESTALE);
 
-       err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
+       err = try_firmware_load(uc_fw, &fw);
        memcpy(&file_ideal, &uc_fw->file_wanted, sizeof(file_ideal));
 
-       if (!err && fw->size > INTEL_UC_RSVD_GGTT_PER_FW) {
-               drm_err(&i915->drm,
-                       "%s firmware %s: size (%zuKB) exceeds max supported size (%uKB)\n",
-                       intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
-                       fw->size / SZ_1K, INTEL_UC_RSVD_GGTT_PER_FW / SZ_1K);
-
-               /* try to find another blob to load */
-               release_firmware(fw);
-               err = -ENOENT;
-       }
-
        /* Any error is terminal if overriding. Don't bother searching for older versions */
        if (err && intel_uc_fw_is_overridden(uc_fw))
                goto fail;
@@ -608,7 +622,7 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
                        break;
                }
 
-               err = firmware_request_nowarn(&fw, uc_fw->file_selected.path, dev);
+               err = try_firmware_load(uc_fw, &fw);
        }
 
        if (err)
This page took 0.062222 seconds and 4 git commands to generate.