DragonFlyBSD Kernel Audit
DF-1164 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c b/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c
--- a/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c
@@ -252,11 +252,30 @@
 {
 	const struct common_firmware_header *hdr =
 		(const struct common_firmware_header *)fw->data;
+	uint32_t ucode_size;
+	uint32_t ucode_offset;
 
-	if (fw->datasize == le32_to_cpu(hdr->size_bytes))
-		return 0;
+	/* The header itself must fit in the firmware blob. */
+	if (fw->datasize < sizeof(*hdr))
+		return -EINVAL;
 
-	return -EINVAL;
+	if (fw->datasize != le32_to_cpu(hdr->size_bytes))
+		return -EINVAL;
+
+	/*
+	 * The declared ucode payload (offset + size) must lie entirely
+	 * within the firmware blob. Without this check, a crafted header
+	 * with an oversized ucode_size_bytes causes the CP/MEC/RLC/PFP/CE/ME
+	 * loader loops in gfx_v7_0 (and similar) to read past the blob into
+	 * adjacent kernel heap while writing to microcode RAM.
+	 */
+	ucode_size = le32_to_cpu(hdr->ucode_size_bytes);
+	ucode_offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
+	if (ucode_offset > fw->datasize ||
+	    ucode_size > fw->datasize - ucode_offset)
+		return -EINVAL;
+
+	return 0;
 }
 
 bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,