[PATCH RFC] drm/cirrus-qemu: Use actual VRAM size to prevent out-of-bounds write

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
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: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=2442951a6abb004df963
Link: https://syzkaller.appspot.com/ai_job?id=0995d2c9-3eea-4945-84e7-ab3d2acd4f21
To: "David Airlie" <[email protected]>
To: "Dave Airlie" <[email protected]>
To: <[email protected]>
To: "Gerd Hoffmann" <[email protected]>
To: "Maarten Lankhorst" <[email protected]>
To: "Maxime Ripard" <[email protected]>
To: "Simona Vetter" <[email protected]>
To: "Thomas Zimmermann" <[email protected]>
To: <[email protected]>
Cc: "Jani Nikula" <[email protected]>
Cc: <[email protected]>
Cc: "Luca Ceresoli" <[email protected]>

---
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 [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.