DragonFlyBSD Kernel Audit
DF-1894 / fix.diff
← back to finding ↓ download raw
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;