]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/cirrus-qemu: Stricter mode validation
authorThomas Zimmermann <tzimmermann@suse.de>
Fri, 28 Mar 2025 09:17:06 +0000 (10:17 +0100)
committerThomas Zimmermann <tzimmermann@suse.de>
Tue, 1 Apr 2025 13:35:12 +0000 (15:35 +0200)
Implement strict checking of a display mode's minimum scanline
pitch in cirrus_mode_config_mode_valid(). Sort out all modes that
possibly overflow the maximum pitch.

The current validation only tests against a display mode's minimum
requirements for video memory. Only atomic_check later tests against
the pitch limit before programming the framebuffer.

The problem is that user-space compositors do not handle this
gracefully. If atomic_check fails to validate the scanline pitch
and returns an error, the compositor, namely Weston, does nothing
and the display remains stale.

Ruling out display modes that possibly overflow the pitch avoids
this problem. With only 4 MiB of video memory available, this
effectively limits horizontal resolution to 800 pixels. But with
cirrus-qemu being low-end and obsolete, this is probably not an
issue in practice. Better alternatives are available in qemu.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Link: https://lore.kernel.org/r/20250328091821.195061-3-tzimmermann@suse.de
drivers/gpu/drm/tiny/cirrus-qemu.c

index a00d3b7ded6c5e64619dbcdb25291b1c009a26db..0306433ec117ccea8ee7e4421cc60b7893a57b66 100644 (file)
@@ -613,9 +613,17 @@ static enum drm_mode_status cirrus_mode_config_mode_valid(struct drm_device *dev
                                                          const struct drm_display_mode *mode)
 {
        const struct drm_format_info *format = drm_format_info(DRM_FORMAT_XRGB8888);
-       uint64_t pitch = drm_format_info_min_pitch(format, 0, mode->hdisplay);
+       u64 pitch;
 
-       if (pitch * mode->vdisplay > CIRRUS_VRAM_SIZE)
+       if (drm_WARN_ON_ONCE(dev, !format))
+               return MODE_ERROR; /* driver bug */
+
+       pitch = drm_format_info_min_pitch(format, 0, mode->hdisplay);
+       if (!pitch)
+               return MODE_BAD_WIDTH;
+       if (pitch > CIRRUS_MAX_PITCH)
+               return MODE_BAD_WIDTH; /* maximum programmable pitch */
+       if (pitch > CIRRUS_VRAM_SIZE / mode->vdisplay)
                return MODE_MEM;
 
        return MODE_OK;