Re: [PATCH V3] fbdev: Fix out-of-bounds access when rotating console after font resize

Helge Deller <[email protected]>
Newsgroups org.freedesktop.lists.dri-devel,org.kernel.vger.linux-fbdev,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On 7/29/26 04:12, Zizhi Wo wrote:
> From: Zizhi Wo <[email protected]>
> 
> [BUG]
> Recently, we encountered a KASAN warning as follows:
> 
> BUG: KASAN: slab-out-of-bounds in ccw_putcs+0x8bd/0xa80
> Read of size 1 at addr ff11000110067100 by task bash/1209
> CPU: 10 UID: 0 PID: 1209 Comm: bash Not tainted 7.2.0-rc3 #69 PREEMPT(full)
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-4.fc41 04/01/2014
>   Call Trace:
>    <TASK>
>    ...
>    kasan_report+0xf0/0x120
>    ? ccw_putcs+0x8bd/0xa80
>    ccw_putcs+0x8bd/0xa80
>    ? __pfx_ccw_putcs+0x10/0x10
>    fbcon_putcs+0x338/0x410
>    ? __pfx_ccw_putcs+0x10/0x10
>    do_update_region+0x21d/0x450
>    invert_screen+0x29d/0x5e0
>    ? __kmalloc_noprof+0x493/0x640
>    ? vc_do_resize+0x17c/0xe50
>    clear_selection+0x4c/0x60
>    vc_do_resize+0xaee/0xe50
>    fbcon_modechanged+0x2bd/0x640
>    rotate_all_store+0x298/0x380
>    ...
> 
> reproduce:
> 1) issue two ioctls: first a KDFONTOP ioctl with op.op = KD_FONT_OP_SET,
> op.width = 1 and op.height = 1, then a TIOCL_SETSEL ioctl
> 2) echo 2 > /sys/devices/virtual/graphics/fbcon/rotate_all
> 3) issue two ioctls: first a KDFONTOP ioctl with op.op = KD_FONT_OP_SET,
> op.width = 8 and op.height = 1, then a TIOCL_SETSEL ioctl
> 4) echo 3 > /sys/devices/virtual/graphics/fbcon/rotate_all
> 
> [CAUSE]
> The root cause is that fbcon_modechanged() first sets the current rotate's
> corresponding ops. Subsequently, during vc_resize(), it may trigger
> clear_selection(), and in fbcon_putcs->ccw_putcs[rotate=3], this can result
> in an out-of-bounds access to "src". This happens because par->rotated.buf
> is reallocated in fbcon_rotate_font():
> 1) When rotate=2, its size is (width + 7) / 8 * height
> 2) When rotate=3, its size is (height + 7) / 8 * width
> 
> And the call to fbcon_rotate_font() occurs after clear_selection(). In
> other words, the fontbuffer is allocated using the size calculated from the
> previous rotation 2, but before reallocating it with the new size,
> con_putcs is already using the new rotation 3:
> 
> rotate_all_store
>   fbcon_rotate_all
>    fbcon_set_all_vcs
>     fbcon_modechanged
>      set_blitting_type
>      ...
>       par->bitops = &ccw_fbcon_bitops
>      vc_resize
>      ...
>       clear_selection
>        highlight
>        ...
>         do_update_region
> 	fbcon_putcs
> 	...
> 	 image.dy = vyres - ((xx + count) * vc->vc_font.width) [1]  // overflow!
> 	 ccw_putcs_aligned
> 	  // old buf size is still being used during the read!
> 	  src = par->rotated.buf + (scr_readw(s--) & charmask) * cellsize
> 	  fb_pad_aligned_buffer----[src KASAN!!!]	[2]
> 	  info->fbops->fb_imageblit(info, image)
> 	   sys_imageblit
> 	    fb_imageblit
> 	     fb_address_forward
> 	      // offset: image->dy * bits_per_line + image->dx * bpp
> 	      unsigned int bits = (unsigned int)adr->bits + offset
> 	      adr->address += (bits & ~(BITS_PER_LONG - 1u)) / BITS_PER_BYTE	[3]
> 	     fb_bitmap_imageblit
> 	     ...
> 	      fb_read_offset	// page fault!	[4]
>      update_screen
>       redraw_screen
>       ...
>        ccw_cursor
>         soft_cursor
>          memcpy(src, image->data, dsize)----[src KASAN again!!!]	[5]
>       fbcon_switch
>        fbcon_rotate_font
>         font_data_rotate
> 	dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL)
>         // the new size is allocated only here!
>         par->rotated.buf = buf	[6]
> 
> [FIX]
> A fairly obvious approach is to follow fbcon_switch(): in
> fbcon_modechanged(), call rotate_font() before vc_resize() so that a
> correctly sized buffer is allocated in time, as done in [6]. This fix is
> necessary, but it is not sufficient on its own.
> 
> In [1] it causes an image.dy overflow (ccw_putcs: vyres = 768,
> image.dy = 4294967040), because vc_cols has not been updated in time at
> this point (it is likewise only updated after clear_selection()). This
> allows (xx + count) * width to exceed vyres, causing image.dy to overflow.
> Subsequently, address in [3] is incremented by an even larger amount, which
> triggers a page fault at [4].
> 
> Therefore, a second fix is required in combination with the first: move
> clear_selection() earlier, before set_blitting_type() in
> fbcon_set_all_vcs(), to prevent the out-of-bounds access. fbcon_rotate()
> has a similar problem, so add the same clear there. Since vc_is_sel() is
> not exported, the fbdev side is currently forced to call clear_selection()
> unconditionally, causing the global selection to be cleared prematurely.
> And this will not cause any other significant impact.
> 
> Signed-off-by: Zizhi Wo <[email protected]>
> ---
> v3:
> Add comments.
> 
> v2:
> Fixed the issue by calling clear_selection() earlier, and updated the
> related description in the commit message.
> https://lore.kernel.org/all/[email protected]/
> 
> v1:
> https://lore.kernel.org/all/[email protected]/
> ---
> ---
>   drivers/video/fbdev/core/fbcon.c | 25 +++++++++++++++++++++++++
>   1 file changed, 25 insertions(+)
patch applied.

Thanks!
Helge
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.