DragonFlyBSD Kernel Audit
DF-1946 / 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,27 @@
 {
 	const struct common_firmware_header *hdr =
 		(const struct common_firmware_header *)fw->data;
+	uint32_t size_bytes, ucode_size_bytes, ucode_array_offset_bytes;
 
-	if (fw->datasize == le32_to_cpu(hdr->size_bytes))
-		return 0;
+	/* DF-1946: the buffer must be large enough to even contain the
+	 * common header before we dereference any field of *hdr. */
+	if (fw->datasize < sizeof(*hdr))
+		return -EINVAL;
 
-	return -EINVAL;
+	size_bytes               = le32_to_cpu(hdr->size_bytes);
+	ucode_size_bytes         = le32_to_cpu(hdr->ucode_size_bytes);
+	ucode_array_offset_bytes = le32_to_cpu(hdr->ucode_array_offset_bytes);
+
+	if (fw->datasize != size_bytes)
+		return -EINVAL;
+
+	/* The declared payload must lie entirely within the firmware image.
+	 * Performed in 64-bit to avoid offset+size wrap-around. */
+	if ((uint64_t)ucode_array_offset_bytes + (uint64_t)ucode_size_bytes >
+	    (uint64_t)size_bytes)
+		return -EINVAL;
+
+	return 0;
 }
 
 bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,