[PATCH RFC] fbdev: core: Add bounds checking to drawing functions
"syzbot" <[email protected]> Wed, 22 Jul 2026 16:04:26 +0000 (UTC)
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
A vmalloc-out-of-bounds write can occur in the framebuffer drawing
functions. This happens when fbcon ignores a failure from vc_resize()
(e.g., due to a memory allocation failure) and proceeds to draw the console
using the old, larger dimensions that no longer fit within the new, smaller
framebuffer resolution. This mismatch causes the calculated drawing
coordinates to underflow, resulting in massive positive numbers.
Because the low-level drawing functions (fb_imageblit, fb_fillrect, and
fb_copyarea) previously lacked bounds checking, they blindly used these
invalid coordinates to calculate memory addresses, leading to a
vmalloc-out-of-bounds write.
While it might seem tempting to handle the error in fbcon_modechanged(),
doing so cleanly is difficult because the hardware resolution and rotation
state have already been altered by the time the failure occurs. Instead,
the most robust and idiomatic solution is to implement defense-in-depth by
adding bounds checking directly to the low-level drawing functions. This
protects all framebuffer drivers from out-of-bounds accesses, regardless of
whether the invalid coordinates come from fbcon or another source.
Add bounds checks at the beginning of the inline functions in
drivers/video/fbdev/core/fb_imageblit.h, fb_fillrect.h, and fb_copyarea.h.
These checks validate the destination coordinates (dx, dy) and dimensions
(width, height) against the virtual resolution of the framebuffer
(p->var.xres_virtual and p->var.yres_virtual). Because the coordinates and
dimensions are unsigned 32-bit integers (u32), any negative coordinate
resulting from an underflow will wrap around to a huge positive number. The
>= xres_virtual (or yres_virtual) checks safely and correctly catch these
underflows. If the bounds check fails, the function simply returns early,
dropping the invalid drawing operation and protecting kernel memory.
BUG: KASAN: vmalloc-out-of-bounds in fb_write_offset
drivers/video/fbdev/core/sysmem.h:30 [inline]
BUG: KASAN: vmalloc-out-of-bounds in fb_bitmap_2ppw
drivers/video/fbdev/core/fb_imageblit.h:364 [inline]
BUG: KASAN: vmalloc-out-of-bounds in fb_bitmap_imageblit
drivers/video/fbdev/core/fb_imageblit.h:462 [inline]
BUG: KASAN: vmalloc-out-of-bounds in fb_imageblit
drivers/video/fbdev/core/fb_imageblit.h:492 [inline]
BUG: KASAN: vmalloc-out-of-bounds in sys_imageblit+0xff5/0x1e40
drivers/video/fbdev/core/sysimgblt.c:24
Write of size 8 at addr ffffc90005101fc0 by task syz.0.17/6108
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
fb_write_offset drivers/video/fbdev/core/sysmem.h:30 [inline]
fb_bitmap_2ppw drivers/video/fbdev/core/fb_imageblit.h:364 [inline]
fb_bitmap_imageblit drivers/video/fbdev/core/fb_imageblit.h:462 [inline]
fb_imageblit drivers/video/fbdev/core/fb_imageblit.h:492 [inline]
sys_imageblit+0xff5/0x1e40 drivers/video/fbdev/core/sysimgblt.c:24
drm_fbdev_shmem_defio_imageblit+0x2c/0x110
drivers/gpu/drm/drm_fbdev_shmem.c:39
cw_putcs_aligned drivers/video/fbdev/core/fbcon_cw.c:111 [inline]
cw_putcs+0x1626/0x18e0 drivers/video/fbdev/core/fbcon_cw.c:159
fbcon_putcs+0x3c5/0x5a0 drivers/video/fbdev/core/fbcon.c:1392
do_update_region+0x389/0x440 drivers/tty/vt/vt.c:656
redraw_screen+0xa3d/0x1020 drivers/tty/vt/vt.c:1008
fbcon_rotate drivers/video/fbdev/core/fbcon.c:230 [inline]
rotate_store+0x32d/0x500 drivers/video/fbdev/core/fbcon.c:3171
kernfs_fop_write_iter+0x3a4/0x540 fs/kernfs/file.c:345
new_sync_write fs/read_write.c:595 [inline]
vfs_write+0x612/0xba0 fs/read_write.c:687
ksys_write+0x150/0x270 fs/read_write.c:739
Fixes: eabb03293087 ("fbdev: Refactoring the fbcon packed pixel drawing routines")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a
Link: https://syzkaller.appspot.com/ai_job?id=46e0f6f1-3c42-4372-a8ba-1f6573bdc0ae
To: "Helge Deller" <[email protected]>
To: <[email protected]>
To: <[email protected]>
To: "Simona Vetter" <[email protected]>
To: "Zsolt Kajtar" <[email protected]>
Cc: <[email protected]>
---
diff --git a/drivers/video/fbdev/core/fb_copyarea.h b/drivers/video/fbdev/core/fb_copyarea.h
index 53f1d5385..f4fc86a51 100644
--- a/drivers/video/fbdev/core/fb_copyarea.h
+++ b/drivers/video/fbdev/core/fb_copyarea.h
@@ -386,6 +386,16 @@ static inline void fb_copyarea(struct fb_info *p, const struct fb_copyarea *area
struct fb_address src = dst;
bool rev_copy = (dy > sy) || (dy == sy && area->dx > area->sx);
+ if (area->dx >= p->var.xres_virtual ||
+ area->dy >= p->var.yres_virtual ||
+ area->sx >= p->var.xres_virtual ||
+ area->sy >= p->var.yres_virtual ||
+ area->width > p->var.xres_virtual - area->dx ||
+ area->height > p->var.yres_virtual - area->dy ||
+ area->width > p->var.xres_virtual - area->sx ||
+ area->height > p->var.yres_virtual - area->sy)
+ return;
+
if (rev_copy) {
dy += height - 1;
sy += height - 1;
diff --git a/drivers/video/fbdev/core/fb_fillrect.h b/drivers/video/fbdev/core/fb_fillrect.h
index f366670a5..37f55adb2 100644
--- a/drivers/video/fbdev/core/fb_fillrect.h
+++ b/drivers/video/fbdev/core/fb_fillrect.h
@@ -261,6 +261,12 @@ static inline void fb_fillrect(struct fb_info *p, const struct fb_fillrect *rect
struct fb_address dst = fb_address_init(p);
struct fb_pattern pattern;
+ if (rect->dx >= p->var.xres_virtual ||
+ rect->dy >= p->var.yres_virtual ||
+ rect->width > p->var.xres_virtual - rect->dx ||
+ rect->height > p->var.yres_virtual - rect->dy)
+ return;
+
fb_address_forward(&dst, rect->dy * bits_per_line + rect->dx * bpp);
pattern.pixels = pixel_to_pat(bpp, palette ? palette[rect->color] : rect->color);
diff --git a/drivers/video/fbdev/core/fb_imageblit.h b/drivers/video/fbdev/core/fb_imageblit.h
index 3b2bb4946..5ec17d7b9 100644
--- a/drivers/video/fbdev/core/fb_imageblit.h
+++ b/drivers/video/fbdev/core/fb_imageblit.h
@@ -486,6 +486,12 @@ static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
struct fb_reverse reverse = fb_reverse_init(p);
const u32 *palette = fb_palette(p);
+ if (image->dx >= p->var.xres_virtual ||
+ image->dy >= p->var.yres_virtual ||
+ image->width > p->var.xres_virtual - image->dx ||
+ image->height > p->var.yres_virtual - image->dy)
+ return;
+
fb_address_forward(&dst, image->dy * bits_per_line + image->dx * bpp);
if (image->depth == 1)
base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
--
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].