DragonFlyBSD Kernel Audit
DF-1130 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/si.c b/sys/dev/drm/radeon/si.c
--- a/sys/dev/drm/radeon/si.c
+++ b/sys/dev/drm/radeon/si.c
@@ -1574,14 +1574,20 @@
 	if (rdev->new_fw) {
 		const struct mc_firmware_header_v1_0 *hdr =
 			(const struct mc_firmware_header_v1_0 *)rdev->mc_fw->data;
+		u32 io_off = le32_to_cpu(hdr->io_debug_array_offset_bytes);
+		u32 io_size = le32_to_cpu(hdr->io_debug_size_bytes);
+		u32 uc_off = le32_to_cpu(hdr->header.ucode_array_offset_bytes);
+		u32 uc_size = le32_to_cpu(hdr->header.ucode_size_bytes);
+		u32 ds = rdev->mc_fw->datasize;
 
 		radeon_ucode_print_mc_hdr(&hdr->header);
-		regs_size = le32_to_cpu(hdr->io_debug_size_bytes) / (4 * 2);
-		new_io_mc_regs = (const __le32 *)
-			(rdev->mc_fw->data + le32_to_cpu(hdr->io_debug_array_offset_bytes));
-		ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-		new_fw_data = (const __le32 *)
-			(rdev->mc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+		if (io_off > ds || io_size > ds - io_off ||
+		    uc_off > ds || uc_size > ds - uc_off)
+			return -EINVAL;
+		regs_size = io_size / (4 * 2);
+		new_io_mc_regs = (const __le32 *)(rdev->mc_fw->data + io_off);
+		ucode_size = uc_size / 4;
+		new_fw_data = (const __le32 *)(rdev->mc_fw->data + uc_off);
 	} else {
 		ucode_size = rdev->mc_fw->datasize / 4;
 
@@ -3481,33 +3487,46 @@
 			(const struct gfx_firmware_header_v1_0 *)rdev->me_fw->data;
 		const __le32 *fw_data;
 		u32 fw_size;
+		u32 ds_pfp = rdev->pfp_fw->datasize;
+		u32 ds_ce  = rdev->ce_fw->datasize;
+		u32 ds_me  = rdev->me_fw->datasize;
+		u32 off, size;
 
 		radeon_ucode_print_gfx_hdr(&pfp_hdr->header);
 		radeon_ucode_print_gfx_hdr(&ce_hdr->header);
 		radeon_ucode_print_gfx_hdr(&me_hdr->header);
 
 		/* PFP */
-		fw_data = (const __le32 *)
-			(rdev->pfp_fw->data + le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes));
-		fw_size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes) / 4;
+		off = le32_to_cpu(pfp_hdr->header.ucode_array_offset_bytes);
+		size = le32_to_cpu(pfp_hdr->header.ucode_size_bytes);
+		if (off > ds_pfp || size > ds_pfp - off)
+			return -EINVAL;
+		fw_data = (const __le32 *)(rdev->pfp_fw->data + off);
+		fw_size = size / 4;
 		WREG32(CP_PFP_UCODE_ADDR, 0);
 		for (i = 0; i < fw_size; i++)
 			WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++));
 		WREG32(CP_PFP_UCODE_ADDR, 0);
 
 		/* CE */
-		fw_data = (const __le32 *)
-			(rdev->ce_fw->data + le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes));
-		fw_size = le32_to_cpu(ce_hdr->header.ucode_size_bytes) / 4;
+		off = le32_to_cpu(ce_hdr->header.ucode_array_offset_bytes);
+		size = le32_to_cpu(ce_hdr->header.ucode_size_bytes);
+		if (off > ds_ce || size > ds_ce - off)
+			return -EINVAL;
+		fw_data = (const __le32 *)(rdev->ce_fw->data + off);
+		fw_size = size / 4;
 		WREG32(CP_CE_UCODE_ADDR, 0);
 		for (i = 0; i < fw_size; i++)
 			WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++));
 		WREG32(CP_CE_UCODE_ADDR, 0);
 
 		/* ME */
-		fw_data = (const __be32 *)
-			(rdev->me_fw->data + le32_to_cpu(me_hdr->header.ucode_array_offset_bytes));
-		fw_size = le32_to_cpu(me_hdr->header.ucode_size_bytes) / 4;
+		off = le32_to_cpu(me_hdr->header.ucode_array_offset_bytes);
+		size = le32_to_cpu(me_hdr->header.ucode_size_bytes);
+		if (off > ds_me || size > ds_me - off)
+			return -EINVAL;
+		fw_data = (const __le32 *)(rdev->me_fw->data + off);
+		fw_size = size / 4;
 		WREG32(CP_ME_RAM_WADDR, 0);
 		for (i = 0; i < fw_size; i++)
 			WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++));
@@ -5876,11 +5895,17 @@
 	if (rdev->new_fw) {
 		const struct rlc_firmware_header_v1_0 *hdr =
 			(const struct rlc_firmware_header_v1_0 *)rdev->rlc_fw->data;
-		u32 fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-		const __le32 *fw_data = (const __le32 *)
-			(rdev->rlc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+		u32 uc_off = le32_to_cpu(hdr->header.ucode_array_offset_bytes);
+		u32 uc_size = le32_to_cpu(hdr->header.ucode_size_bytes);
+		u32 ds = rdev->rlc_fw->datasize;
+		u32 fw_size;
+		const __le32 *fw_data;
 
 		radeon_ucode_print_rlc_hdr(&hdr->header);
+		if (uc_off > ds || uc_size > ds - uc_off)
+			return -EINVAL;
+		fw_size = uc_size / 4;
+		fw_data = (const __le32 *)(rdev->rlc_fw->data + uc_off);
 
 		for (i = 0; i < fw_size; i++) {
 			WREG32(RLC_UCODE_ADDR, i);