DragonFlyBSD Kernel Audit
DF-1133 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/amdgpu/gfx_v8_0.c b/sys/dev/drm/amd/amdgpu/gfx_v8_0.c
--- a/sys/dev/drm/amd/amdgpu/gfx_v8_0.c
+++ b/sys/dev/drm/amd/amdgpu/gfx_v8_0.c
@@ -1103,9 +1103,30 @@
 	adev->gfx.rlc.reg_list_size_bytes =
 			le32_to_cpu(rlc_hdr->reg_list_size_bytes);
 
+	/* Both register-list sizes and the array offsets are read from
+	 * the firmware header with no validation beyond
+	 * amdgpu_ucode_validate() (which only checks datasize ==
+	 * size_bytes).  Validate offset+size against the firmware blob
+	 * to prevent OOB reads, and cast to size_t before adding so the
+	 * kmalloc size cannot wrap (u32 + u32) into a tiny allocation. */
+	{
+		u32 fmt_off = le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes);
+		u32 lst_off = le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes);
+		u32 dsize = adev->gfx.rlc_fw->datasize;
+
+		if (fmt_off > dsize ||
+		    adev->gfx.rlc.reg_list_format_size_bytes > dsize - fmt_off ||
+		    lst_off > dsize ||
+		    adev->gfx.rlc.reg_list_size_bytes > dsize - lst_off) {
+			dev_err(adev->dev, "invalid RLC v2.0 register list sizes/offsets\n");
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
 	adev->gfx.rlc.register_list_format =
-			kmalloc(adev->gfx.rlc.reg_list_format_size_bytes +
-					adev->gfx.rlc.reg_list_size_bytes, M_DRM, GFP_KERNEL);
+			kmalloc((size_t)adev->gfx.rlc.reg_list_format_size_bytes +
+					(size_t)adev->gfx.rlc.reg_list_size_bytes, M_DRM, GFP_KERNEL);
 
 	if (!adev->gfx.rlc.register_list_format) {
 		err = -ENOMEM;