⬢ DragonFlyBSD Kernel Audit
DF-4224 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/drm_modes.c
+++ b/sys/dev/drm/drm_modes.c
@@ -1460,16 +1460,24 @@ bool drm_mode_parse_command_line_for_con
 		switch (name[i]) {
 		case '@':
 			if (!refresh_specified && !bpp_specified &&
 			    !yres_specified && !cvt && !rb && was_digit) {
-				refresh = simple_strtol(&name[i+1], NULL, 10);
+				long val = simple_strtol(&name[i+1], NULL, 10);
+
+				/* struct drm_cmdline_mode stores refresh/bpp in
+				 * int. Values > INT_MAX (or negative) wrap and
+				 * later drive divide-by-zero panics in
+				 * drm_cvt_mode()/drm_gtf_mode_complex()
+				 * (vfieldrate -> hperiod/hfreq_est math).
+				 */
+				if (val < 0 || val > INT_MAX)
+					goto done;
+				refresh = val;
 				refresh_specified = true;
 				was_digit = false;
 			} else
 				goto done;
 			break;
 		case '-':
 			if (!bpp_specified && !yres_specified && !cvt &&
 			    !rb && was_digit) {
-				bpp = simple_strtol(&name[i+1], NULL, 10);
+				long val = simple_strtol(&name[i+1], NULL, 10);
+
+				if (val < 0 || val > INT_MAX)
+					goto done;
+				bpp = val;
 				bpp_specified = true;
 				was_digit = false;
 			} else
 				goto done;
@@ -171,6 +179,12 @@ struct drm_display_mode *drm_cvt_mode(str
 	/* the required field fresh rate */
 	if (interlaced)
 		vfieldrate = vrefresh * 2;
 	else
 		vfieldrate = vrefresh;
+
+	/* Defensive: reject absurd field rates before the hperiod math.
+	 * Values like 134217728 wrap hfreq/hperiod products to 0 and
+	 * panic on the divisions below.
+	 */
+	if (vfieldrate == 0 || vfieldrate > 1000) {
+		drm_mode_destroy(dev, drm_mode);
+		return NULL;
+	}
 
 	/* horizontal pixels */
 	hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
@@ -415,6 +429,13 @@ drm_gtf_mode_complex(struct drm_device *
 	if (interlaced)
 		vfieldrate_rqd = vrefresh * 2;
 	else
 		vfieldrate_rqd = vrefresh;
+
+	/* Defensive: reject absurd field rates before the hfreq_est math
+	 * (e.g. 134217728 makes tmp2*1000*vfieldrate_rqd wrap to 0, so
+	 * hfreq_est == 0 and the GTF_M_PRIME division traps).
+	 */
+	if (vfieldrate_rqd == 0 || vfieldrate_rqd > 1000) {
+		drm_mode_destroy(dev, drm_mode);
+		return NULL;
+	}
 
 	/* 4. Find number of lines in Top margin: */
 	top_margin = 0;