From: Slawomir Stepien <sst@poczta.fm>
To: syzbot <syzbot@kernel.org>
Cc: syzkaller-upstream-moderation@googlegroups.com, syzbot@lists.linux.dev
Subject: Re: [PATCH RFC] drm/cirrus-qemu: Use actual VRAM size to prevent out-of-bounds write
Date: Mon, 24 Aug 2026 13:58:44 +0200 [thread overview]
Message-ID: <aowx9LUZgrhDZnSM@nr200> (raw)
In-Reply-To: <6e0e7e49-c50d-472e-9cc2-ceaf814e0fc7@mail.kernel.org>
On sie 16, 2026 23:42, 'syzbot' via syzkaller-upstream-moderation wrote:
> The `cirrus-qemu` driver previously relied on a hardcoded constant
> `CIRRUS_VRAM_SIZE` (4 MB) to validate framebuffer sizes. However, during
> device probe, the driver maps the VRAM using the actual size of the PCI
> device's BAR0.
>
> If a privileged user unbinds a random PCI device with a BAR0 smaller than 4
> MB and binds the `cirrus-qemu` driver to it, the mapped VRAM will be
> smaller than 4 MB. Because the validation checks still used the hardcoded 4
> MB size, the driver would allow the creation of a framebuffer larger than
> the actually mapped VRAM.
>
> When the DRM device is closed, `drm_release()` triggers a full atomic
> commit to restore the fbdev mode. This calls
> `cirrus_primary_plane_helper_atomic_update()`, which uses `drm_fb_memcpy()`
> to copy the framebuffer into the mapped VRAM. Since the mapped VRAM is
> smaller than the framebuffer, `memcpy_toio()` writes past the end of the
> mapped I/O memory, resulting in a supervisor write page fault:
>
> BUG: unable to handle page fault for address: ffffc900033dd000
> #PF: supervisor write access in kernel mode
> #PF: error_code(0x0002) - not-present page
> ...
> RIP: 0010:rep_movs arch/x86/lib/iomem.c:13 [inline]
> RIP: 0010:string_memcpy_toio arch/x86/lib/iomem.c:64 [inline]
> RIP: 0010:memcpy_toio+0x7c/0xe0 arch/x86/lib/iomem.c:110
> ...
> Call Trace:
> <TASK>
> iosys_map_memcpy_to include/linux/iosys-map.h:285 [inline]
> drm_fb_memcpy+0x325/0x5d0 drivers/gpu/drm/drm_format_helper.c:442
> cirrus_primary_plane_helper_atomic_update+0x98a/0xb00
> drivers/gpu/drm/tiny/cirrus-qemu.c:358
> drm_atomic_helper_commit_planes+0x626/0xea0
> drivers/gpu/drm/drm_atomic_helper.c:3038
> drm_atomic_helper_commit_tail+0x60/0x510
> drivers/gpu/drm/drm_atomic_helper.c:1989
> commit_tail+0x2b1/0x3c0 drivers/gpu/drm/drm_atomic_helper.c:2074
> drm_atomic_helper_commit+0xa77/0xb10
> drivers/gpu/drm/drm_atomic_helper.c:2312
> ...
>
> To fix this, remove the hardcoded `CIRRUS_VRAM_SIZE` and dynamically track
> the actual VRAM size in `struct cirrus_device`. Initialize this size from
> the PCI resource length during probe, ensuring it is non-zero. Update the
> validation hooks `cirrus_primary_plane_helper_atomic_check()` and
> `cirrus_mode_config_mode_valid()` to use the dynamically tracked VRAM size,
> ensuring that framebuffers strictly fit within the mapped memory.
>
> Fixes: ab3e023b1b4c ("drm/cirrus: rewrite and modernize driver.")
> Assisted-by: Gemini:gemini-3.6-flash Gemini:gemini-3.1-pro-preview syzbot
> Reported-by: syzbot+2442951a6abb004df963@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=2442951a6abb004df963
> Link: https://syzkaller.appspot.com/ai_job?id=0995d2c9-3eea-4945-84e7-ab3d2acd4f21
> To: "David Airlie" <airlied@gmail.com>
> To: "Dave Airlie" <airlied@redhat.com>
> To: <dri-devel@lists.freedesktop.org>
> To: "Gerd Hoffmann" <kraxel@redhat.com>
> To: "Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>
> To: "Maxime Ripard" <mripard@kernel.org>
> To: "Simona Vetter" <simona@ffwll.ch>
> To: "Thomas Zimmermann" <tzimmermann@suse.de>
> To: <virtualization@lists.linux.dev>
> Cc: "Jani Nikula" <jani.nikula@intel.com>
> Cc: <linux-kernel@vger.kernel.org>
> Cc: "Luca Ceresoli" <luca.ceresoli@bootlin.com>
>
> ---
> diff --git a/drivers/gpu/drm/tiny/cirrus-qemu.c b/drivers/gpu/drm/tiny/cirrus-qemu.c
> index 075221b43..7f8cb3264 100644
> --- a/drivers/gpu/drm/tiny/cirrus-qemu.c
> +++ b/drivers/gpu/drm/tiny/cirrus-qemu.c
> @@ -55,7 +55,6 @@
> #define DRIVER_MINOR 0
>
> #define CIRRUS_MAX_PITCH (0x1FF << 3) /* (4096 - 1) & ~111b bytes */
> -#define CIRRUS_VRAM_SIZE (4 * 1024 * 1024) /* 4 MB */
>
> struct cirrus_device {
> struct drm_device dev;
> @@ -68,6 +67,7 @@ struct cirrus_device {
>
> /* HW resources */
> void __iomem *vram;
> + size_t vram_size;
> void __iomem *mmio;
> };
>
> @@ -298,6 +298,7 @@ static const uint64_t cirrus_primary_plane_format_modifiers[] = {
> static int cirrus_primary_plane_helper_atomic_check(struct drm_plane *plane,
> struct drm_atomic_commit *state)
> {
> + struct cirrus_device *cirrus = to_cirrus(plane->dev);
> struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
> struct drm_framebuffer *fb = new_plane_state->fb;
> struct drm_crtc *new_crtc = new_plane_state->crtc;
> @@ -319,7 +320,7 @@ static int cirrus_primary_plane_helper_atomic_check(struct drm_plane *plane,
> /* validate size constraints */
> if (fb->pitches[0] > CIRRUS_MAX_PITCH)
> return -EINVAL;
> - else if (fb->pitches[0] > CIRRUS_VRAM_SIZE / fb->height)
> + else if (fb->pitches[0] > cirrus->vram_size / fb->height)
> return -EINVAL;
>
> return 0;
> @@ -514,6 +515,7 @@ static int cirrus_pipe_init(struct cirrus_device *cirrus)
> static enum drm_mode_status cirrus_mode_config_mode_valid(struct drm_device *dev,
> const struct drm_display_mode *mode)
> {
> + struct cirrus_device *cirrus = to_cirrus(dev);
> const struct drm_format_info *format = drm_format_info(DRM_FORMAT_XRGB8888);
> u64 pitch;
>
> @@ -525,7 +527,7 @@ static enum drm_mode_status cirrus_mode_config_mode_valid(struct drm_device *dev
> return MODE_BAD_WIDTH;
> if (pitch > CIRRUS_MAX_PITCH)
> return MODE_BAD_WIDTH; /* maximum programmable pitch */
> - if (pitch > CIRRUS_VRAM_SIZE / mode->vdisplay)
> + if (pitch > cirrus->vram_size / mode->vdisplay)
> return MODE_MEM;
>
> return MODE_OK;
> @@ -602,8 +604,12 @@ static int cirrus_pci_probe(struct pci_dev *pdev,
>
> dev = &cirrus->dev;
>
> + if (pci_resource_len(pdev, 0) == 0)
How about checking here also if the returned value is == to CIRRUS_VRAM_SIZE and leave the
CIRRUS_VRAM_SIZE as it is right now? Or even better:
if (pci_resource_len(pdev, 0) != CIRRUS_VRAM_SIZE)
return -ENODEV;
This will make this change a much simpler one!
It seems, after checking the qemu sources, that CLGD5446 must have 4MB and there is not other
option.
> + return -ENODEV;
> +
> + cirrus->vram_size = pci_resource_len(pdev, 0);
> cirrus->vram = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0),
> - pci_resource_len(pdev, 0));
> + cirrus->vram_size);
> if (cirrus->vram == NULL)
> return -ENOMEM;
>
>
>
> base-commit: db2ddb87143519e20a95aa36c60b36107b736a58
--
Slawomir Stepien
prev parent reply other threads:[~2026-08-24 11:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-16 23:42 [PATCH RFC] drm/cirrus-qemu: Use actual VRAM size to prevent out-of-bounds write syzbot
2026-08-24 11:58 ` Slawomir Stepien [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aowx9LUZgrhDZnSM@nr200 \
--to=sst@poczta.fm \
--cc=syzbot@kernel.org \
--cc=syzbot@lists.linux.dev \
--cc=syzkaller-upstream-moderation@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.