DF-4225 / fix.diff
--- a/sys/dev/drm/drm_modes.c +++ b/sys/dev/drm/drm_modes.c @@ -780,9 +780,9 @@ int drm_mode_vrefresh(const struct drm_display_mode else if (mode->htotal > 0 && mode->vtotal > 0) { - unsigned int num, den; + u64 num, den; - num = mode->clock * 1000; - den = mode->htotal * mode->vtotal; + num = (u64)mode->clock * 1000; + den = (u64)mode->htotal * mode->vtotal; if (mode->flags & DRM_MODE_FLAG_INTERLACE) num *= 2; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) den *= 2; if (mode->vscan > 1) den *= mode->vscan; @@ -1111,6 +1111,15 @@ static enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode) { if (mode->type & ~DRM_MODE_TYPE_ALL) return MODE_BAD; if (mode->flags & ~DRM_MODE_FLAG_ALL) return MODE_BAD; if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) return MODE_BAD; if (mode->clock == 0) return MODE_CLOCK_LOW; + + /* drm_mode_modeinfo carries u32 timings but the core and every + * driver consume them as int; anything above the CRTC hardware + * register width (USHRT_MAX, cf. the WARN in + * drm_mode_convert_to_umode) can wrap products such as + * htotal*vtotal to 0 and trap in drm_mode_vrefresh(). + */ + if (mode->hdisplay > USHRT_MAX || mode->hsync_start > USHRT_MAX || + mode->hsync_end > USHRT_MAX || mode->htotal > USHRT_MAX) + return MODE_BAD_HVALUE; + if (mode->vdisplay > USHRT_MAX || mode->vsync_start > USHRT_MAX || + mode->vsync_end > USHRT_MAX || mode->vtotal > USHRT_MAX) + return MODE_BAD_VVALUE; if (mode->hdisplay == 0 || mode->hsync_start < mode->hdisplay || mode->hsync_end < mode->hsync_start || mode->htotal < mode->hsync_end) |