DragonFlyBSD Kernel Audit
DF-1470 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/powerplay/hwmgr/processpptables.c b/sys/dev/drm/amd/powerplay/hwmgr/processpptables.c
--- a/sys/dev/drm/amd/powerplay/hwmgr/processpptables.c
+++ b/sys/dev/drm/amd/powerplay/hwmgr/processpptables.c
@@ -45,6 +45,22 @@
 
 #define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
 
+/* DF-1470: VBIOS USHORT offsets are added to the powerplay_table base pointer
+ * and dereferenced as typed struct pointers throughout this file with no check
+ * that the offset lies within [0, soft_pp_table_size). Validate every offset
+ * before deref. */
+static bool pp_offset_in_table(struct pp_hwmgr *hwmgr,
+			       const void *base, uint16_t offset, size_t need)
+{
+	unsigned long start = (unsigned long)base + offset;
+	unsigned long end = start + need;
+	unsigned long table_end = (unsigned long)hwmgr->soft_pp_table +
+				  hwmgr->soft_pp_table_size;
+
+	return (offset > 0 && start >= (unsigned long)hwmgr->soft_pp_table &&
+		end <= table_end);
+}
+
 static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
 			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 {
@@ -56,6 +72,10 @@
 			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
 
 		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
+			if (!pp_offset_in_table(hwmgr, powerplay_table3,
+					le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset),
+					sizeof(ATOM_PPLIB_EXTENDEDHEADER)))
+				return 0;
 			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
 						(const ATOM_PPLIB_EXTENDEDHEADER *)
 						(((unsigned long)powerplay_table3) +