DragonFlyBSD Kernel Audit
DF-1333 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/rv770_dpm.c b/sys/dev/drm/radeon/rv770_dpm.c
--- a/sys/dev/drm/radeon/rv770_dpm.c
+++ b/sys/dev/drm/radeon/rv770_dpm.c
@@ -2277,11 +2277,11 @@
 	union pplib_clock_info *clock_info;
 	union power_info *power_info;
 	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
-	u16 data_offset;
+	u16 data_offset, data_size;
 	u8 frev, crev;
 	struct rv7xx_ps *ps;
 
-	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+	if (!atom_parse_data_header(mode_info->atom_context, index, &data_size,
 				   &frev, &crev, &data_offset))
 		return -EINVAL;
 	power_info = (union power_info *)((uint8_t*)mode_info->atom_context->bios + data_offset);
@@ -2292,15 +2292,23 @@
 		return -ENOMEM;
 
 	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+		u32 state_off, nc_off;
+
+		state_off = le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+			    i * power_info->pplib.ucStateEntrySize;
+		if (state_off + power_info->pplib.ucStateEntrySize > data_size)
+			break;
 		power_state = (union pplib_power_state *)
 			((uint8_t*)mode_info->atom_context->bios + data_offset +
-			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
-			 i * power_info->pplib.ucStateEntrySize);
+			 state_off);
+		nc_off = le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+			 (power_state->v1.ucNonClockStateIndex *
+			  power_info->pplib.ucNonClockSize);
+		if (nc_off + power_info->pplib.ucNonClockSize > data_size)
+			break;
 		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
 			((uint8_t*)mode_info->atom_context->bios + data_offset +
-			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
-			 (power_state->v1.ucNonClockStateIndex *
-			  power_info->pplib.ucNonClockSize));
+			 nc_off);
 		if (power_info->pplib.ucStateEntrySize - 1) {
 			u8 *idx;
 			ps = kzalloc(sizeof(struct rv7xx_ps), GFP_KERNEL);
@@ -2314,17 +2322,22 @@
 							 power_info->pplib.ucNonClockSize);
 			idx = (u8 *)&power_state->v1.ucClockStateIndices[0];
 			for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+				u32 cl_off;
+
+				cl_off = le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+					 (idx[j] * power_info->pplib.ucClockInfoSize);
+				if (cl_off + power_info->pplib.ucClockInfoSize > data_size)
+					break;
 				clock_info = (union pplib_clock_info *)
 					((uint8_t*)mode_info->atom_context->bios + data_offset +
-					 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
-					 (idx[j] * power_info->pplib.ucClockInfoSize));
+					 cl_off);
 				rv7xx_parse_pplib_clock_info(rdev,
 							     &rdev->pm.dpm.ps[i], j,
 							     clock_info);
 			}
 		}
 	}
-	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+	rdev->pm.dpm.num_ps = i;
 	return 0;
 }