⬢ DragonFlyBSD Kernel Audit
DF-4154 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
@@ -1603,6 +1603,7 @@ int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
 	union vram_info *vram_info;
+	u8 *table_end;
 
 	memset(reg_table, 0, sizeof(struct atom_mc_reg_table));
 
@@ -1597,9 +1598,14 @@ int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
 		vram_info = (union vram_info *)
 			(adev->mode_info.atom_context->bios + data_offset);
+		/* DF-4154: all walks must stay inside the declared table */
+		table_end = (u8 *)vram_info + size;
 		switch (frev) {
@@ -1607,6 +1613,10 @@ int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
 				if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
 					ATOM_INIT_REG_BLOCK *reg_block =
 						(ATOM_INIT_REG_BLOCK *)
 						((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));
+					if ((u8 *)reg_block + sizeof(*reg_block) > table_end)
+						return -EINVAL;
 					ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =
 						(ATOM_MEMORY_SETTING_DATA_BLOCK *)
 						((u8 *)reg_block + (2 * sizeof(u16)) +
 						 le16_to_cpu(reg_block->usRegIndexTblSize));
+					if ((u8 *)reg_data + sizeof(u32) > table_end)
+						return -EINVAL;
@@ -1631,12 +1641,18 @@ int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
 					reg_table->last = i;
+					/* DF-4154: zero stride would never terminate */
+					if (le16_to_cpu(reg_block->usRegDataBlkSize) == 0)
+						return -EINVAL;
 					while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&
 					       (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
 						t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK)
 								>> MEM_ID_SHIFT);
 						if (module_index == t_mem_id) {
+							if ((u8 *)reg_data +
+							    4 + reg_table->last * sizeof(u32) > table_end)
+								return -EINVAL;
 							reg_table->mc_reg_table_entry[num_ranges].mclk_max =
 								(u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK)
 								      >> CLOCK_RANGE_SHIFT);
@@ -1651,6 +1667,9 @@ int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
 						}
 						reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
 							((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
+						if ((u8 *)reg_data + sizeof(u32) > table_end)
+							return -EINVAL;
 					}