Archive-only list for syzbot
 help / color / mirror / Atom feed
* [PATCH RFC] drm/cirrus-qemu: Use actual VRAM size to prevent out-of-bounds write
@ 2026-08-16 23:42 syzbot
  2026-08-24 11:58 ` Slawomir Stepien
  0 siblings, 1 reply; 2+ messages in thread
From: syzbot @ 2026-08-16 23:42 UTC (permalink / raw)
  To: syzkaller-upstream-moderation; +Cc: syzbot

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)
+		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
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzkaller@googlegroups.com.

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH RFC] drm/cirrus-qemu: Use actual VRAM size to prevent out-of-bounds write
  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
  0 siblings, 0 replies; 2+ messages in thread
From: Slawomir Stepien @ 2026-08-24 11:58 UTC (permalink / raw)
  To: syzbot; +Cc: syzkaller-upstream-moderation, syzbot

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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-24 11:58 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox