Re: [PATCH V3] fbdev: Fix out-of-bounds access when rotating console after font resize
Helge Deller <[email protected]> Fri, 31 Jul 2026 09:31:16 +0200
| Newsgroups | org.kernel.vger.linux-fbdev,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 7/29/26 04:12, Zizhi Wo wrote: > From: Zizhi Wo <[email protected]> >=20 > [BUG] > Recently, we encountered a KASAN warning as follows: >=20 > 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(fu= ll) > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-4.fc4= 1 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 > ... >=20 > reproduce: > 1) issue two ioctls: first a KDFONTOP ioctl with op.op =3D KD_FONT_OP_SE= T, > op.width =3D 1 and op.height =3D 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 =3D KD_FONT_OP_SE= T, > op.width =3D 8 and op.height =3D 1, then a TIOCL_SETSEL ioctl > 4) echo 3 > /sys/devices/virtual/graphics/fbcon/rotate_all >=20 > [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=3D3], this can r= esult > in an out-of-bounds access to "src". This happens because par->rotated.b= uf > is reallocated in fbcon_rotate_font(): > 1) When rotate=3D2, its size is (width + 7) / 8 * height > 2) When rotate=3D3, its size is (height + 7) / 8 * width >=20 > 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: >=20 > rotate_all_store > fbcon_rotate_all > fbcon_set_all_vcs > fbcon_modechanged > set_blitting_type > ... > par->bitops =3D &ccw_fbcon_bitops > vc_resize > ... > clear_selection > highlight > ... > do_update_region > fbcon_putcs > ... > image.dy =3D vyres - ((xx + count) * vc->vc_font.width) [1] // overfl= ow! > ccw_putcs_aligned > // old buf size is still being used during the read! > src =3D 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 =3D (unsigned int)adr->bits + offset > adr->address +=3D (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 =3D kmalloc_array(charcount, d_cellsize, GFP_KERNEL) > // the new size is allocated only here! > par->rotated.buf =3D buf [6] >=20 > [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. >=20 > In [1] it causes an image.dy overflow (ccw_putcs: vyres =3D 768, > image.dy =3D 4294967040), because vc_cols has not been updated in time a= t > this point (it is likewise only updated after clear_selection()). This > allows (xx + count) * width to exceed vyres, causing image.dy to overflo= w. > Subsequently, address in [3] is incremented by an even larger amount, wh= ich > triggers a page fault at [4]. >=20 > 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. >=20 > Signed-off-by: Zizhi Wo <[email protected]> > --- > v3: > Add comments. >=20 > v2: > Fixed the issue by calling clear_selection() earlier, and updated the > related description in the commit message. > https://lore.kernel.org/all/20260722062216.2574546-1-wozizhi@huaweicloud= .com/ >=20 > v1: > https://lore.kernel.org/all/20250905024340.337521-1-wozizhi@huaweicloud.= com/ > --- > --- > drivers/video/fbdev/core/fbcon.c | 25 +++++++++++++++++++++++++ > 1 file changed, 25 insertions(+) patch applied. Thanks! Helge