Validate the conversion of the DMC firmware size from dwords to bytes
using check_mul_overflow() before calculating the firmware payload size.

Reject zero-length payloads and zero MMIO counts in the DMC firmware
header so malformed firmware is caught early. Also set dmc_fw_size only
after the payload allocation succeeds.

Fixes: eb805623d8b1 ("drm/i915/skl: Add support to load SKL CSR firmware.")
Cc: [email protected]
Assisted-by: Claude-Code:Sonnet-5
Signed-off-by: Dibin Moolakadan Subrahmanian 
<[email protected]>
---
 drivers/gpu/drm/i915/display/intel_dmc.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c 
b/drivers/gpu/drm/i915/display/intel_dmc.c
index 051b721a0895..b06143a607eb 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.c
+++ b/drivers/gpu/drm/i915/display/intel_dmc.c
@@ -1170,7 +1170,7 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc,
        }
 
        /* Cache the dmc header info. */
-       if (mmio_count > mmio_count_max) {
+       if (!mmio_count || mmio_count > mmio_count_max) {
                drm_err(display->drm, "DMC firmware has wrong mmio count %u\n", 
mmio_count);
                return 0;
        }
@@ -1178,7 +1178,17 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc,
        rem_size -= header_len_bytes;
 
        /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */
-       payload_size = dmc_header->fw_size * 4;
+       if (check_mul_overflow(dmc_header->fw_size, 4u, &payload_size)) {
+               drm_err(display->drm, "DMC fw_size too large (%u dwords)\n",
+                       dmc_header->fw_size);
+               return 0;
+       }
+
+       if (!payload_size) {
+               drm_err(display->drm, "DMC firmware has empty payload\n");
+               return 0;
+       }
+
        if (rem_size < payload_size)
                goto error_truncated;
 
@@ -1237,12 +1247,12 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc,
        dmc_info->mmio_count = mmio_count;
        dmc_info->start_mmioaddr = start_mmioaddr;
 
-       dmc_info->dmc_fw_size = dmc_header->fw_size;
-
        dmc_info->payload = kmalloc(payload_size, GFP_KERNEL);
        if (!dmc_info->payload)
                return 0;
 
+       dmc_info->dmc_fw_size = dmc_header->fw_size;
+
        payload = (u8 *)(dmc_header) + header_len_bytes;
        memcpy(dmc_info->payload, payload, payload_size);
 
-- 
2.43.0

Reply via email to