DragonFlyBSD Kernel Audit
DF-1389 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/i915/intel_bios.c b/sys/dev/drm/i915/intel_bios.c
--- a/sys/dev/drm/i915/intel_bios.c
+++ b/sys/dev/drm/i915/intel_bios.c
@@ -166,12 +166,27 @@
 	 * entry to get the DVO timing entry
 	 */
 
+	u16 data_size;
+	size_t want;
 	int lfp_data_size =
 		lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
 		lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
 	int dvo_timing_offset =
 		lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
 		lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
+
+	/* Mirror the bounds check already done by sibling fn
+	 * get_lvds_fp_timing(). The BDB section size lives in a u16
+	 * header just before the section data. Without this, attacker-
+	 * controlled ptr offsets let lfp_data_size / dvo_timing_offset
+	 * address bytes past the section. */
+	data_size = ((const u16 *)lvds_lfp_data)[-1];
+	want = (size_t)lfp_data_size * (size_t)index + (size_t)dvo_timing_offset;
+	if (lfp_data_size <= 0 || dvo_timing_offset < 0 ||
+	    want > data_size ||
+	    want + sizeof(struct lvds_dvo_timing) > data_size)
+		return NULL;
+
 	char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index;
 
 	return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);