DF-1894 / fix.diff
diff --git a/sys/dev/drm/i915/intel_csr.c b/sys/dev/drm/i915/intel_csr.c --- a/sys/dev/drm/i915/intel_csr.c +++ b/sys/dev/drm/i915/intel_csr.c @@ -400,8 +400,12 @@ csr->mmiodata[i] = dmc_header->mmiodata[i]; } - /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ - nbytes = dmc_header->fw_size * 4; + /* fw_size is in dwords, so multiplied by 4 to convert into bytes. + * Validate fw_size BEFORE the multiplication to prevent 32-bit + * overflow — e.g. fw_size=0x40000001 wraps nbytes to 4, kmalloc(4) + * succeeds, but csr->dmc_fw_size stores the original 0x40000001 and + * intel_csr_load_program later loops ~10^9 times reading past the + * 4-byte payload into kernel heap and writing each dword to MMIO. */ if (INTEL_GEN(dev_priv) >= 11) max_fw_size = ICL_CSR_MAX_FW_SIZE; else if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) @@ -410,6 +414,12 @@ max_fw_size = BXT_CSR_MAX_FW_SIZE; else MISSING_CASE(INTEL_REVID(dev_priv)); + if (dmc_header->fw_size > max_fw_size / 4) { + DRM_ERROR("DMC FW fw_size %u too large (max %u dwords)\n", + dmc_header->fw_size, max_fw_size / 4); + return NULL; + } + nbytes = dmc_header->fw_size * 4; if (nbytes > max_fw_size) { DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes); return NULL; |