[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20251119133821.89998-1-ssranevjti@gmail.com>
Date: Wed, 19 Nov 2025 19:08:21 +0530
From: ssrane_b23@...vjti.ac.in
To: Zsolt Kajtar <soci@....rulez.org>,
Simona Vetter <simona@...ll.ch>,
Helge Deller <deller@....de>
Cc: Shaurya Rane <ssrane_b23@...vjti.ac.in>,
linux-fbdev@...r.kernel.org,
dri-devel@...ts.freedesktop.org,
linux-kernel@...r.kernel.org,
syzbot+5a40432dfe8f86ee657a@...kaller.appspotmail.com
Subject: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
From: Shaurya Rane <ssrane_b23@...vjti.ac.in>
syzbot reported a vmalloc-out-of-bounds write in fb_imageblit. The crash
occurs when drawing an image at the very end of the framebuffer memory.
The current bounds check in fb_imageblit limits the drawing height (max_y)
by dividing the screen size by the line length. However, this calculation
only ensures that the start of the last line fits within the buffer. It
fails to account for the width of the image on that final line. If the
image width (multiplied by bpp) exceeds the remaining space on the last
line, the drawing routine writes past the end of the allocated video
memory.
This patch replaces the insufficient check with a more precise one. It
calculates the effective width in bytes of the image (accounting for
clipping against xres_virtual) and ensures that the last byte of the
operation falls within the screen buffer. Specifically, it checks if
'(dy + height - 1) * line_length + effective_width_bytes' exceeds
screen_size. If it does, the drawing height max_y is reduced to
prevent the out-of-bounds access.
Reported-by: syzbot+5a40432dfe8f86ee657a@...kaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a
Signed-off-by: Shaurya Rane <ssrane_b23@...vjti.ac.in>
---
drivers/video/fbdev/core/fb_imageblit.h | 66 +++++++++++++++++++++++--
1 file changed, 62 insertions(+), 4 deletions(-)
diff --git a/drivers/video/fbdev/core/fb_imageblit.h b/drivers/video/fbdev/core/fb_imageblit.h
index 3b2bb4946505..0c0d05cff3f8 100644
--- a/drivers/video/fbdev/core/fb_imageblit.h
+++ b/drivers/video/fbdev/core/fb_imageblit.h
@@ -485,11 +485,69 @@ static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
struct fb_address dst = fb_address_init(p);
struct fb_reverse reverse = fb_reverse_init(p);
const u32 *palette = fb_palette(p);
+ struct fb_image clipped_image;
+ u32 max_x, max_y;
+ unsigned long max_offset_bytes;
+
+ /* Validate basic parameters */
+ if (!image || !p->screen_buffer || !p->screen_size ||
+ !image->width || !image->height)
+ return;
+
+ /* Calculate maximum addressable coordinates based on virtual resolution and buffer size */
+ max_x = p->var.xres_virtual;
+ max_y = p->var.yres_virtual;
+
+ /* Check against actual buffer size to prevent vmalloc overflow */
+ {
+ unsigned long effective_width_bytes;
+ u32 right_edge = image->dx + image->width;
+
+ if (right_edge < image->dx)
+ right_edge = max_x;
+ else
+ right_edge = min(right_edge, max_x);
+
+ effective_width_bytes = (unsigned long)right_edge * bpp;
+ effective_width_bytes = (effective_width_bytes + 7) / 8;
+
+ if (effective_width_bytes > p->screen_size) {
+ max_y = 0;
+ } else if (p->fix.line_length) {
+ u32 max_lines = (p->screen_size - effective_width_bytes) /
+ p->fix.line_length + 1;
+ if (max_lines < max_y)
+ max_y = max_lines;
+ }
+ }
+
+ /* If image is completely outside bounds, skip it */
+ if (image->dx >= max_x || image->dy >= max_y)
+ return;
+
+ /* Create clipped image - clip to virtual resolution bounds */
+ clipped_image = *image;
+
+ /* Clip width if it extends beyond right edge */
+ if (clipped_image.dx + clipped_image.width > max_x) {
+ if (clipped_image.dx < max_x)
+ clipped_image.width = max_x - clipped_image.dx;
+ else
+ return; /* completely outside */
+ }
+
+ /* Clip height if it extends beyond bottom edge */
+ if (clipped_image.dy + clipped_image.height > max_y) {
+ if (clipped_image.dy < max_y)
+ clipped_image.height = max_y - clipped_image.dy;
+ else
+ return; /* completely outside */
+ }
- fb_address_forward(&dst, image->dy * bits_per_line + image->dx * bpp);
+ fb_address_forward(&dst, clipped_image.dy * bits_per_line + clipped_image.dx * bpp);
- if (image->depth == 1)
- fb_bitmap_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
+ if (clipped_image.depth == 1)
+ fb_bitmap_imageblit(&clipped_image, &dst, bits_per_line, palette, bpp, reverse);
else
- fb_color_imageblit(image, &dst, bits_per_line, palette, bpp, reverse);
+ fb_color_imageblit(&clipped_image, &dst, bits_per_line, palette, bpp, reverse);
}
--
2.34.1
Powered by blists - more mailing lists