⬢ DragonFlyBSD Kernel Audit
DF-3860 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/amdgpu/amdgpu_device.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_device.c
@@ -1367,18 +1367,45 @@
 	}
 
 	hdr = (const struct gpu_info_firmware_header_v1_0 *)adev->firmware.gpu_info_fw->data;
+
+	/* the common header itself must fit before we dereference it */
+	if (adev->firmware.gpu_info_fw->datasize < sizeof(*hdr)) {
+		dev_err(adev->dev,
+			"gpu_info firmware \"%s\" too small (%zu bytes)\n",
+			fw_name, adev->firmware.gpu_info_fw->datasize);
+		err = -EINVAL;
+		goto out;
+	}
+
 	amdgpu_ucode_print_gpu_info_hdr(&hdr->header);
 
 	switch (hdr->version_major) {
 	case 1:
 	{
-		const struct gpu_info_firmware_v1_0 *gpu_info_fw =
-			(const struct gpu_info_firmware_v1_0 *)(adev->firmware.gpu_info_fw->data +
-								le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+		u64 off = le32_to_cpu(hdr->header.ucode_array_offset_bytes);
+		const struct gpu_info_firmware_v1_0 *gpu_info_fw;
+
+		/* DF-3860: payload must be inside the firmware buffer */
+		if (off > adev->firmware.gpu_info_fw->datasize ||
+		    adev->firmware.gpu_info_fw->datasize - off <
+			    sizeof(struct gpu_info_firmware_v1_0)) {
+			dev_err(adev->dev,
+				"gpu_info payload offset 0x%llx out of range (fw size %zu)\n",
+				(unsigned long long)off,
+				adev->firmware.gpu_info_fw->datasize);
+			err = -EINVAL;
+			goto out;
+		}
+
+		gpu_info_fw = (const struct gpu_info_firmware_v1_0 *)
+			(adev->firmware.gpu_info_fw->data + off);
 
-		adev->gfx.config.max_shader_engines = le32_to_cpu(gpu_info_fw->gc_num_se);
+		/* DF-3698 family: consumers index fixed [4][4] arrays with these */
+		adev->gfx.config.max_shader_engines =
+			min_t(u32, le32_to_cpu(gpu_info_fw->gc_num_se), 4);
 		adev->gfx.config.max_cu_per_sh = le32_to_cpu(gpu_info_fw->gc_num_cu_per_sh);
-		adev->gfx.config.max_sh_per_se = le32_to_cpu(gpu_info_fw->gc_num_sh_per_se);
+		adev->gfx.config.max_sh_per_se =
+			min_t(u32, le32_to_cpu(gpu_info_fw->gc_num_sh_per_se), 4);
 		adev->gfx.config.max_backends_per_se = le32_to_cpu(gpu_info_fw->gc_num_rb_per_se);
 		adev->gfx.config.max_texture_channel_caches =
 			le32_to_cpu(gpu_info_fw->gc_num_tccs);