[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;