[PATCH] drm/amdgpu/virt: fix integer overflow in size_kb shift

lihaojie <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx,org.freedesktop.lists.dri-devel,org.kernel.vger.stable
Message-ID <[email protected]>
size_kb is uint32_t. The expression "size_kb << 10" is computed in
32-bit arithmetic, which overflows when size_kb >= 0x400000 (4 GB in
KB). This leads to incorrect buffer sizes being passed to kzalloc(),
amdgpu_device_vram_access(), and amdgpu_ttm_init_vram_resv(),
potentially causing undersized allocations and subsequent heap
overflows.

Fix this by casting size_kb to u64 before the shift, matching the
existing correct pattern already used in the same file:

  u64 init_hdr_size = (u64)adev->virt.init_data_header.size_kb << 10;

The affected call sites are:
  - amdgpu_virt_read_exchange_data_from_mem(): dataexchange_size
  - amdgpu_virt_init_data_exchange(): kzalloc size argument
  - amdgpu_virt_init_critical_region(): amdgpu_ttm_init_vram_resv size
  - amdgpu_virt_get_dynamic_data_info(): data_size

Also update the corresponding dev_info/dev_dbg format strings from
0x%x to 0x%llx to match the new u64 type.

Fixes: 07009df6494d ("drm/amdgpu: Introduce SRIOV critical regions v2 during VF init")
Cc: [email protected]
Signed-off-by: lihaojie <[email protected]>
---

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
index 9e8f7d2b898c..51287d2a6d12 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -752,12 +752,12 @@ static int amdgpu_virt_read_exchange_data_from_mem(struct amdgpu_device *adev, u
 {
 	uint32_t dataexchange_offset =
 		adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset;
-	uint32_t dataexchange_size =
-		adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10;
+	u64 dataexchange_size =
+		(u64)adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10;
 	uint64_t pos = 0;
 
 	dev_info(adev->dev,
-			"Got data exchange info from dynamic crit_region_table at offset 0x%x with size of 0x%x bytes.\n",
+			"Got data exchange info from dynamic crit_region_table at offset 0x%x with size of 0x%llx bytes.\n",
 			dataexchange_offset, dataexchange_size);
 
 	if (!IS_ALIGNED(dataexchange_offset, 4) || !IS_ALIGNED(dataexchange_size, 4)) {
@@ -804,7 +804,8 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
 		/* got through this logic in early init stage to get necessary flags, e.g. rlcg_acc related*/
 		if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) {
 			pfvf_data =
-				kzalloc(adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10,
+				kzalloc((u64)adev->virt.crit_regn_tbl
+					[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].size_kb << 10,
 					GFP_KERNEL);
 			if (!pfvf_data) {
 				dev_err(adev->dev, "Failed to allocate memory for pfvf_data\n");
@@ -1161,7 +1162,7 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev)
 	/* reserved memory starts from crit region base offset with the size of 5MB */
 	amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE,
 				  adev->virt.crit_regn.offset,
-				  adev->virt.crit_regn.size_kb << 10, true);
+				  (u64)adev->virt.crit_regn.size_kb << 10, true);
 	dev_info(adev->dev,
 		"critical region v%d requested to reserve memory start at %08llx with %llu KB.\n",
 			init_data_hdr->version,
@@ -1181,14 +1182,14 @@ int amdgpu_virt_get_dynamic_data_info(struct amdgpu_device *adev,
 	int data_id, uint8_t *binary, u32 *size)
 {
 	uint32_t data_offset = 0;
-	uint32_t data_size = 0;
+	u64 data_size = 0;
 	enum amd_sriov_msg_table_id_enum data_table_id = data_id;
 
 	if (data_table_id >= AMD_SRIOV_MSG_MAX_TABLE_ID)
 		return -EINVAL;
 
 	data_offset = adev->virt.crit_regn_tbl[data_table_id].offset;
-	data_size = adev->virt.crit_regn_tbl[data_table_id].size_kb << 10;
+	data_size = (u64)adev->virt.crit_regn_tbl[data_table_id].size_kb << 10;
 
 	/* Validate on input params */
 	if (!binary || !size || *size < (uint64_t)data_size)
@@ -1200,7 +1201,7 @@ int amdgpu_virt_get_dynamic_data_info(struct amdgpu_device *adev,
 	*size = (uint64_t)data_size;
 
 	dev_dbg(adev->dev,
-		"Got %s info from dynamic crit_region_table at offset 0x%x with size of 0x%x bytes.\n",
+		"Got %s info from dynamic crit_region_table at offset 0x%x with size of 0x%llx bytes.\n",
 		amdgpu_virt_dynamic_crit_table_name[data_id], data_offset, data_size);
 
 	return 0;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.