Commit 81f9ba82 authored by Lucas De Marchi's avatar Lucas De Marchi Committed by Greg Kroah-Hartman

drm/i915/dmc: protect against reading random memory

commit 326fb6dd upstream.

While loading the DMC firmware we were double checking the headers made
sense, but in no place we checked that we were actually reading memory
we were supposed to. This could be wrong in case the firmware file is
truncated or malformed.

Before this patch:
	# ls -l /lib/firmware/i915/icl_dmc_ver1_07.bin
	-rw-r--r-- 1 root root  25716 Feb  1 12:26 icl_dmc_ver1_07.bin
	# truncate -s 25700 /lib/firmware/i915/icl_dmc_ver1_07.bin
	# modprobe i915
	# dmesg| grep -i dmc
	[drm:intel_csr_ucode_init [i915]] Loading i915/icl_dmc_ver1_07.bin
	[drm] Finished loading DMC firmware i915/icl_dmc_ver1_07.bin (v1.7)

i.e. it loads random data. Now it fails like below:
	[drm:intel_csr_ucode_init [i915]] Loading i915/icl_dmc_ver1_07.bin
	[drm:csr_load_work_fn [i915]] *ERROR* Truncated DMC firmware, rejecting.
	i915 0000:00:02.0: Failed to load DMC firmware i915/icl_dmc_ver1_07.bin. Disabling runtime power management.
	i915 0000:00:02.0: DMC firmware homepage: https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915

Before reading any part of the firmware file, validate the input first.

Fixes: eb805623 ("drm/i915/skl: Add support to load SKL CSR firmware.")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190605235535.17791-1-lucas.demarchi@intel.com
(cherry picked from commit bc7b488b)
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 54908d1d
...@@ -300,10 +300,17 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv, ...@@ -300,10 +300,17 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv,
u32 dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; u32 dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes;
u32 i; u32 i;
u32 *dmc_payload; u32 *dmc_payload;
size_t fsize;
if (!fw) if (!fw)
return NULL; return NULL;
fsize = sizeof(struct intel_css_header) +
sizeof(struct intel_package_header) +
sizeof(struct intel_dmc_header);
if (fsize > fw->size)
goto error_truncated;
/* Extract CSS Header information*/ /* Extract CSS Header information*/
css_header = (struct intel_css_header *)fw->data; css_header = (struct intel_css_header *)fw->data;
if (sizeof(struct intel_css_header) != if (sizeof(struct intel_css_header) !=
...@@ -363,6 +370,9 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv, ...@@ -363,6 +370,9 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv,
/* Convert dmc_offset into number of bytes. By default it is in dwords*/ /* Convert dmc_offset into number of bytes. By default it is in dwords*/
dmc_offset *= 4; dmc_offset *= 4;
readcount += dmc_offset; readcount += dmc_offset;
fsize += dmc_offset;
if (fsize > fw->size)
goto error_truncated;
/* Extract dmc_header information. */ /* Extract dmc_header information. */
dmc_header = (struct intel_dmc_header *)&fw->data[readcount]; dmc_header = (struct intel_dmc_header *)&fw->data[readcount];
...@@ -394,6 +404,10 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv, ...@@ -394,6 +404,10 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv,
/* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */
nbytes = dmc_header->fw_size * 4; nbytes = dmc_header->fw_size * 4;
fsize += nbytes;
if (fsize > fw->size)
goto error_truncated;
if (nbytes > csr->max_fw_size) { if (nbytes > csr->max_fw_size) {
DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes); DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes);
return NULL; return NULL;
...@@ -407,6 +421,10 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv, ...@@ -407,6 +421,10 @@ static u32 *parse_csr_fw(struct drm_i915_private *dev_priv,
} }
return memcpy(dmc_payload, &fw->data[readcount], nbytes); return memcpy(dmc_payload, &fw->data[readcount], nbytes);
error_truncated:
DRM_ERROR("Truncated DMC firmware, rejecting.\n");
return NULL;
} }
static void intel_csr_runtime_pm_get(struct drm_i915_private *dev_priv) static void intel_csr_runtime_pm_get(struct drm_i915_private *dev_priv)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment