DragonFlyBSD Kernel Audit
DF-1947 / 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
@@ -334,6 +334,17 @@
 	cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
 	dmcu_hdr = (const struct dmcu_firmware_header_v1_0 *)ucode->fw->data;
 
+	const struct firmware *fw = ucode->fw;
+	uint32_t fw_size = fw->datasize;
+	uint32_t arr_off = le32_to_cpu(header->ucode_array_offset_bytes);
+	uint32_t ucode_size_bytes = le32_to_cpu(header->ucode_size_bytes);
+
+	/* DF-1947: the firmware source window for every memcpy below is
+	 * fw->data[arr_off .. arr_off+ucode_size). Validate it once before
+	 * any branch uses it. */
+	if (arr_off > fw_size || ucode_size_bytes > fw_size - arr_off)
+		return -EINVAL;
+
 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP ||
 	    (ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1 &&
 	     ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC2 &&
@@ -344,40 +355,52 @@
 	     ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM &&
 		 ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_ERAM &&
 		 ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV)) {
-		ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes);
+		ucode->ucode_size = ucode_size_bytes;
 
-		memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
-					      le32_to_cpu(header->ucode_array_offset_bytes)),
+		memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + arr_off),
 		       ucode->ucode_size);
 	} else if (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1 ||
 		   ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2) {
-		ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes) -
-			le32_to_cpu(cp_hdr->jt_size) * 4;
+		uint32_t jt_size = le32_to_cpu(cp_hdr->jt_size);
+		/* DF-1947: guard the uint32 subtraction against underflow. */
+		if (jt_size > UINT32_MAX / 4 || jt_size * 4 > ucode_size_bytes)
+			return -EINVAL;
+		ucode->ucode_size = ucode_size_bytes - jt_size * 4;
 
-		memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
-					      le32_to_cpu(header->ucode_array_offset_bytes)),
+		memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + arr_off),
 		       ucode->ucode_size);
 	} else if (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT ||
 		   ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT) {
-		ucode->ucode_size = le32_to_cpu(cp_hdr->jt_size) * 4;
+		uint32_t jt_size = le32_to_cpu(cp_hdr->jt_size);
+		uint32_t jt_off  = le32_to_cpu(cp_hdr->jt_offset);
+		if (jt_size > UINT32_MAX / 4 || jt_off > UINT32_MAX / 4)
+			return -EINVAL;
+		ucode->ucode_size = jt_size * 4;
+		if (arr_off > fw_size ||
+		    jt_off * 4 > fw_size - arr_off ||
+		    ucode->ucode_size > (fw_size - arr_off) - jt_off * 4)
+			return -EINVAL;
 
-		memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
-					      le32_to_cpu(header->ucode_array_offset_bytes) +
-					      le32_to_cpu(cp_hdr->jt_offset) * 4),
+		memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data +
+					      arr_off + jt_off * 4),
 		       ucode->ucode_size);
 	} else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCU_ERAM) {
-		ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes) -
-				le32_to_cpu(dmcu_hdr->intv_size_bytes);
+		uint32_t intv_size = le32_to_cpu(dmcu_hdr->intv_size_bytes);
+		/* DF-1947: guard the uint32 subtraction against underflow. */
+		if (intv_size > ucode_size_bytes)
+			return -EINVAL;
+		ucode->ucode_size = ucode_size_bytes - intv_size;
 
-		memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
-					      le32_to_cpu(header->ucode_array_offset_bytes)),
+		memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + arr_off),
 		       ucode->ucode_size);
 	} else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCU_INTV) {
-		ucode->ucode_size = le32_to_cpu(dmcu_hdr->intv_size_bytes);
+		uint32_t intv_off  = le32_to_cpu(dmcu_hdr->intv_offset_bytes);
+		uint32_t intv_size = le32_to_cpu(dmcu_hdr->intv_size_bytes);
+		if (intv_off > fw_size || intv_size > fw_size - intv_off)
+			return -EINVAL;
+		ucode->ucode_size = intv_size;
 
-		memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
-					      le32_to_cpu(header->ucode_array_offset_bytes) +
-					      le32_to_cpu(dmcu_hdr->intv_offset_bytes)),
+		memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + intv_off),
 		       ucode->ucode_size);
 	} else if (ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL) {
 		ucode->ucode_size = adev->gfx.rlc.save_restore_list_cntl_size_bytes;
@@ -407,15 +430,31 @@
 	if (NULL == ucode->fw)
 		return 0;
 
-	comm_hdr = (const struct common_firmware_header *)ucode->fw->data;
-	header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
+	const struct firmware *fw = ucode->fw;
+	uint32_t fw_size = fw->datasize;
+	uint32_t jt_size, jt_off, arr_off, ucode_size_bytes;
+
+	comm_hdr = (const struct common_firmware_header *)fw->data;
+	header = (const struct gfx_firmware_header_v1_0 *)fw->data;
+	jt_size = le32_to_cpu(header->jt_size);
+	jt_off  = le32_to_cpu(header->jt_offset);
+	arr_off = le32_to_cpu(comm_hdr->ucode_array_offset_bytes);
+	ucode_size_bytes = le32_to_cpu(comm_hdr->ucode_size_bytes);
+
+	/* DF-1947: jt_size*4 must not wrap, must fit in source window, and
+	 * the source window itself must lie in fw->data. */
+	if (jt_size > UINT32_MAX / 4 || jt_off > UINT32_MAX / 4)
+		return -EINVAL;
+	if (arr_off > fw_size || ucode_size_bytes > fw_size - arr_off)
+		return -EINVAL;
+	if (jt_off * 4 > ucode_size_bytes ||
+	    jt_size * 4 > ucode_size_bytes - jt_off * 4)
+		return -EINVAL;
+
 	dst_addr = ucode->kaddr +
-			   ALIGN(le32_to_cpu(comm_hdr->ucode_size_bytes),
-			   PAGE_SIZE);
-	src_addr = (uint8_t *)ucode->fw->data +
-			   le32_to_cpu(comm_hdr->ucode_array_offset_bytes) +
-			   (le32_to_cpu(header->jt_offset) * 4);
-	memcpy(dst_addr, src_addr, le32_to_cpu(header->jt_size) * 4);
+		   ALIGN(ucode_size_bytes, PAGE_SIZE);
+	src_addr = (uint8_t *)fw->data + arr_off + jt_off * 4;
+	memcpy(dst_addr, src_addr, jt_size * 4);
 
 	return 0;
 }