[PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit

ssrane_b23@ee.vjti.ac.in posted 1 patch 1 week, 5 days ago
drivers/video/fbdev/core/fb_imageblit.h | 66 +++++++++++++++++++++++--
1 file changed, 62 insertions(+), 4 deletions(-)
[PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
Posted by ssrane_b23@ee.vjti.ac.in 1 week, 5 days ago
From: Shaurya Rane <ssrane_b23@ee.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@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a

Signed-off-by: Shaurya Rane <ssrane_b23@ee.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
Re: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
Posted by kernel test robot 5 days, 19 hours ago
Hi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master v6.18-rc7 next-20251126]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/ssrane_b23-ee-vjti-ac-in/fbdev-core-Fix-vmalloc-out-of-bounds-in-fb_imageblit/20251119-215054
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20251119133821.89998-1-ssranevjti%40gmail.com
patch subject: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20251126/202511260749.KJgv3MyF-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251126/202511260749.KJgv3MyF-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511260749.KJgv3MyF-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/video/fbdev/core/cfbimgblt.c:17:
   drivers/video/fbdev/core/fb_imageblit.h: In function 'fb_imageblit':
>> drivers/video/fbdev/core/fb_imageblit.h:490:23: warning: unused variable 'max_offset_bytes' [-Wunused-variable]
     490 |         unsigned long max_offset_bytes;
         |                       ^~~~~~~~~~~~~~~~


vim +/max_offset_bytes +490 drivers/video/fbdev/core/fb_imageblit.h

   480	
   481	static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
   482	{
   483		int bpp = p->var.bits_per_pixel;
   484		unsigned int bits_per_line = BYTES_TO_BITS(p->fix.line_length);
   485		struct fb_address dst = fb_address_init(p);
   486		struct fb_reverse reverse = fb_reverse_init(p);
   487		const u32 *palette = fb_palette(p);
   488		struct fb_image clipped_image;
   489		u32 max_x, max_y;
 > 490		unsigned long max_offset_bytes;

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
Posted by kernel test robot 1 week, 4 days ago
Hi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm-tip/drm-tip linus/master v6.18-rc6 next-20251119]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/ssrane_b23-ee-vjti-ac-in/fbdev-core-Fix-vmalloc-out-of-bounds-in-fb_imageblit/20251119-215054
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20251119133821.89998-1-ssranevjti%40gmail.com
patch subject: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
config: nios2-randconfig-r073-20251120 (https://download.01.org/0day-ci/archive/20251120/202511201752.4fVbQwPc-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 10.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251120/202511201752.4fVbQwPc-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511201752.4fVbQwPc-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/video/fbdev/core/cfbimgblt.c:17:
   drivers/video/fbdev/core/fb_imageblit.h: In function 'fb_imageblit':
>> drivers/video/fbdev/core/fb_imageblit.h:490:16: warning: unused variable 'max_offset_bytes' [-Wunused-variable]
     490 |  unsigned long max_offset_bytes;
         |                ^~~~~~~~~~~~~~~~


vim +/max_offset_bytes +490 drivers/video/fbdev/core/fb_imageblit.h

   480	
   481	static inline void fb_imageblit(struct fb_info *p, const struct fb_image *image)
   482	{
   483		int bpp = p->var.bits_per_pixel;
   484		unsigned int bits_per_line = BYTES_TO_BITS(p->fix.line_length);
   485		struct fb_address dst = fb_address_init(p);
   486		struct fb_reverse reverse = fb_reverse_init(p);
   487		const u32 *palette = fb_palette(p);
   488		struct fb_image clipped_image;
   489		u32 max_x, max_y;
 > 490		unsigned long max_offset_bytes;

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH] fbdev: core: Fix vmalloc-out-of-bounds in fb_imageblit
Posted by Kajtár Zsolt 1 week, 5 days ago
Hello!

> 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.
I know my opinion doesn't count much but would like make a note.

Any bound checks which are applied here or at the entry of the other 2
low level drawing routines are just masking an issue somewhere in the
console code. The text area should be entirely within bounds of the
screen memory. If that's always the case then there shouldn't be any
drawing request outside of the framebuffer either.

Please consider at least to add a warning instead of silent clipping, as
every time such clipping was done it was a result of a bug.

-- 
						    -soci-