KASAN: use-after-free Read in bit_putcs

54 views
Skip to first unread message

syzbot

unread,
Feb 23, 2020, 12:30:13 PM2/23/20
to b.zoln...@samsung.com, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, syzkall...@googlegroups.com
Hello,

syzbot found the following crash on:

HEAD commit: 0a44cac8 Merge tag 'dma-mapping-5.6' of git://git.infradea..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=11bfb74ee00000
kernel config: https://syzkaller.appspot.com/x/.config?x=a61f2164c515c07f
dashboard link: https://syzkaller.appspot.com/bug?extid=b308f5fd049fbbc6e74f
compiler: clang version 10.0.0 (https://github.com/llvm/llvm-project/ c2443155a0fb245c8f17f2c1c72b6ea391e86e81)

Unfortunately, I don't have any reproducer for this crash yet.

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+b308f5...@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: use-after-free in __fb_pad_aligned_buffer include/linux/fb.h:655 [inline]
BUG: KASAN: use-after-free in bit_putcs_aligned drivers/video/fbdev/core/bitblit.c:96 [inline]
BUG: KASAN: use-after-free in bit_putcs+0x13ee/0x1cc0 drivers/video/fbdev/core/bitblit.c:185
Read of size 1 at addr ffff8880a8087c10 by task syz-executor.2/5278

CPU: 1 PID: 5278 Comm: syz-executor.2 Not tainted 5.6.0-rc2-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0x1fb/0x318 lib/dump_stack.c:118
print_address_description+0x74/0x5c0 mm/kasan/report.c:374
__kasan_report+0x149/0x1c0 mm/kasan/report.c:506
kasan_report+0x26/0x50 mm/kasan/common.c:641
__asan_report_load1_noabort+0x14/0x20 mm/kasan/generic_report.c:132
__fb_pad_aligned_buffer include/linux/fb.h:655 [inline]
bit_putcs_aligned drivers/video/fbdev/core/bitblit.c:96 [inline]
bit_putcs+0x13ee/0x1cc0 drivers/video/fbdev/core/bitblit.c:185
fbcon_putcs+0x7b4/0xad0 drivers/video/fbdev/core/fbcon.c:1360
do_update_region+0x462/0x600 drivers/tty/vt/vt.c:677
redraw_screen+0xcc5/0x1830 drivers/tty/vt/vt.c:1011
vc_do_resize+0x12af/0x1af0 drivers/tty/vt/vt.c:1284
vc_resize+0x4f/0x60 drivers/tty/vt/vt.c:1304
vt_ioctl+0x2fa8/0x3a70 drivers/tty/vt/vt_ioctl.c:887
tty_ioctl+0xee6/0x15c0 drivers/tty/tty_io.c:2660
vfs_ioctl fs/ioctl.c:47 [inline]
ksys_ioctl fs/ioctl.c:763 [inline]
__do_sys_ioctl fs/ioctl.c:772 [inline]
__se_sys_ioctl+0x113/0x190 fs/ioctl.c:770
__x64_sys_ioctl+0x7b/0x90 fs/ioctl.c:770
do_syscall_64+0xf7/0x1c0 arch/x86/entry/common.c:294
entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x45c449
Code: ad b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 7b b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007f74261f2c78 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f74261f36d4 RCX: 000000000045c449
RDX: 0000000020000080 RSI: 000000000000560a RDI: 0000000000000003
RBP: 000000000076bf20 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff
R13: 000000000000066b R14: 00000000004c8fe0 R15: 000000000076bf2c

Allocated by task 2919:
save_stack mm/kasan/common.c:72 [inline]
set_track mm/kasan/common.c:80 [inline]
__kasan_kmalloc+0x118/0x1c0 mm/kasan/common.c:515
kasan_kmalloc+0x9/0x10 mm/kasan/common.c:529
__do_kmalloc_node mm/slab.c:3616 [inline]
__kmalloc_node_track_caller+0x4d/0x60 mm/slab.c:3630
__kmalloc_reserve net/core/skbuff.c:142 [inline]
__alloc_skb+0xe8/0x500 net/core/skbuff.c:210
alloc_skb include/linux/skbuff.h:1051 [inline]
_sctp_make_chunk+0x60/0x460 net/sctp/sm_make_chunk.c:1394
sctp_make_data net/sctp/sm_make_chunk.c:1426 [inline]
sctp_make_datafrag_empty+0xa3/0x5b0 net/sctp/sm_make_chunk.c:740
sctp_datamsg_from_user+0x7a8/0x1020 net/sctp/chunk.c:262
sctp_sendmsg_to_asoc+0x7a9/0x1500 net/sctp/socket.c:1844
sctp_sendmsg+0x15a1/0x3570 net/sctp/socket.c:2016
inet_sendmsg+0x147/0x310 net/ipv4/af_inet.c:807
sock_sendmsg_nosec net/socket.c:652 [inline]
sock_sendmsg net/socket.c:672 [inline]
____sys_sendmsg+0x4f7/0x7f0 net/socket.c:2343
___sys_sendmsg net/socket.c:2397 [inline]
__sys_sendmsg+0x1ed/0x290 net/socket.c:2430
__do_sys_sendmsg net/socket.c:2439 [inline]
__se_sys_sendmsg net/socket.c:2437 [inline]
__x64_sys_sendmsg+0x7f/0x90 net/socket.c:2437
do_syscall_64+0xf7/0x1c0 arch/x86/entry/common.c:294
entry_SYSCALL_64_after_hwframe+0x49/0xbe

Freed by task 2919:
save_stack mm/kasan/common.c:72 [inline]
set_track mm/kasan/common.c:80 [inline]
kasan_set_free_info mm/kasan/common.c:337 [inline]
__kasan_slab_free+0x12e/0x1e0 mm/kasan/common.c:476
kasan_slab_free+0xe/0x10 mm/kasan/common.c:485
__cache_free mm/slab.c:3426 [inline]
kfree+0x10d/0x220 mm/slab.c:3757
skb_free_head net/core/skbuff.c:592 [inline]
skb_release_data+0x72f/0x8c0 net/core/skbuff.c:612
skb_release_all net/core/skbuff.c:666 [inline]
__kfree_skb+0x59/0x1c0 net/core/skbuff.c:680
consume_skb+0x72/0x110 net/core/skbuff.c:839
sctp_chunk_destroy net/sctp/sm_make_chunk.c:1454 [inline]
sctp_chunk_put+0x17b/0x200 net/sctp/sm_make_chunk.c:1481
sctp_chunk_free+0x59/0x60 net/sctp/sm_make_chunk.c:1468
sctp_outq_sack+0x1169/0x16a0 net/sctp/outqueue.c:1352
sctp_cmd_process_sack net/sctp/sm_sideeffect.c:798 [inline]
sctp_cmd_interpreter net/sctp/sm_sideeffect.c:1354 [inline]
sctp_side_effects net/sctp/sm_sideeffect.c:1185 [inline]
sctp_do_sm+0x18f3/0x5840 net/sctp/sm_sideeffect.c:1156
sctp_assoc_bh_rcv+0x494/0x770 net/sctp/associola.c:1044
sctp_inq_push+0x1ab/0x1d0 net/sctp/inqueue.c:80
sctp_backlog_rcv+0x16c/0x4b0 net/sctp/input.c:344
sk_backlog_rcv include/net/sock.h:938 [inline]
__release_sock+0x1c1/0x4b0 net/core/sock.c:2437
release_sock+0x65/0x1c0 net/core/sock.c:2953
sctp_wait_for_connect+0x2f6/0x590 net/sctp/socket.c:9280
sctp_sendmsg_to_asoc+0x11ba/0x1500 net/sctp/socket.c:1870
sctp_sendmsg+0x15a1/0x3570 net/sctp/socket.c:2016
inet_sendmsg+0x147/0x310 net/ipv4/af_inet.c:807
sock_sendmsg_nosec net/socket.c:652 [inline]
sock_sendmsg net/socket.c:672 [inline]
____sys_sendmsg+0x4f7/0x7f0 net/socket.c:2343
___sys_sendmsg net/socket.c:2397 [inline]
__sys_sendmsg+0x1ed/0x290 net/socket.c:2430
__do_sys_sendmsg net/socket.c:2439 [inline]
__se_sys_sendmsg net/socket.c:2437 [inline]
__x64_sys_sendmsg+0x7f/0x90 net/socket.c:2437
do_syscall_64+0xf7/0x1c0 arch/x86/entry/common.c:294
entry_SYSCALL_64_after_hwframe+0x49/0xbe

The buggy address belongs to the object at ffff8880a8087c00
which belongs to the cache kmalloc-512 of size 512
The buggy address is located 16 bytes inside of
512-byte region [ffff8880a8087c00, ffff8880a8087e00)
The buggy address belongs to the page:
page:ffffea0002a021c0 refcount:1 mapcount:0 mapping:ffff8880aa400a80 index:0x0
flags: 0xfffe0000000200(slab)
raw: 00fffe0000000200 ffffea0002431688 ffffea000259d648 ffff8880aa400a80
raw: 0000000000000000 ffff8880a8087000 0000000100000004 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
ffff8880a8087b00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8880a8087b80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff8880a8087c00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff8880a8087c80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8880a8087d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzk...@googlegroups.com.

syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

syzbot

unread,
Sep 25, 2020, 10:03:16 PM9/25/20
to b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, dri-...@lists.freedesktop.org, gre...@linuxfoundation.org, jiri...@kernel.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, penguin...@i-love.sakura.ne.jp, syzkall...@googlegroups.com
syzbot has found a reproducer for the following issue on:

HEAD commit: 171d4ff7 Merge tag 'mmc-v5.9-rc4-2' of git://git.kernel.or..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=13b41d03900000
kernel config: https://syzkaller.appspot.com/x/.config?x=240e2ebab67245c7
dashboard link: https://syzkaller.appspot.com/bug?extid=b308f5fd049fbbc6e74f
compiler: gcc (GCC) 10.1.0-syz 20200507
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=143d11d3900000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=150d16e5900000

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+b308f5...@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: use-after-free in __fb_pad_aligned_buffer include/linux/fb.h:654 [inline]
BUG: KASAN: use-after-free in bit_putcs_aligned drivers/video/fbdev/core/bitblit.c:96 [inline]
BUG: KASAN: use-after-free in bit_putcs+0xbb6/0xd20 drivers/video/fbdev/core/bitblit.c:185
Read of size 1 at addr ffff88809df498fe by task syz-executor859/6860

CPU: 1 PID: 6860 Comm: syz-executor859 Not tainted 5.9.0-rc6-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0x198/0x1fd lib/dump_stack.c:118
print_address_description.constprop.0.cold+0xae/0x497 mm/kasan/report.c:383
__kasan_report mm/kasan/report.c:513 [inline]
kasan_report.cold+0x1f/0x37 mm/kasan/report.c:530
__fb_pad_aligned_buffer include/linux/fb.h:654 [inline]
bit_putcs_aligned drivers/video/fbdev/core/bitblit.c:96 [inline]
bit_putcs+0xbb6/0xd20 drivers/video/fbdev/core/bitblit.c:185
fbcon_putcs+0x35a/0x450 drivers/video/fbdev/core/fbcon.c:1308
con_flush drivers/tty/vt/vt.c:2575 [inline]
do_con_write+0xb6b/0x1dd0 drivers/tty/vt/vt.c:2905
con_write+0x22/0xb0 drivers/tty/vt/vt.c:3250
process_output_block drivers/tty/n_tty.c:595 [inline]
n_tty_write+0x3ce/0xf80 drivers/tty/n_tty.c:2333
do_tty_write drivers/tty/tty_io.c:962 [inline]
tty_write+0x4d9/0x870 drivers/tty/tty_io.c:1046
vfs_write+0x2b0/0x730 fs/read_write.c:576
ksys_write+0x12d/0x250 fs/read_write.c:631
do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x4403c9
Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 db 13 fc ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007ffd97e140c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004403c9
RDX: 0000000000001006 RSI: 0000000020000180 RDI: 0000000000000006
RBP: 00000000006cb018 R08: 00000000004002c8 R09: 00000000004002c8
R10: 000000000000000d R11: 0000000000000246 R12: 0000000000401c30
R13: 0000000000401cc0 R14: 0000000000000000 R15: 0000000000000000

Allocated by task 6860:
kasan_save_stack+0x1b/0x40 mm/kasan/common.c:48
kasan_set_track mm/kasan/common.c:56 [inline]
__kasan_kmalloc.constprop.0+0xbf/0xd0 mm/kasan/common.c:461
__do_kmalloc mm/slab.c:3655 [inline]
__kmalloc+0x1b0/0x360 mm/slab.c:3664
kmalloc include/linux/slab.h:559 [inline]
kzalloc include/linux/slab.h:666 [inline]
tomoyo_init_log+0x1376/0x1ee0 security/tomoyo/audit.c:275
tomoyo_supervisor+0x34d/0xef0 security/tomoyo/common.c:2097
tomoyo_audit_env_log security/tomoyo/environ.c:36 [inline]
tomoyo_env_perm+0x17f/0x1f0 security/tomoyo/environ.c:63
tomoyo_environ security/tomoyo/domain.c:674 [inline]
tomoyo_find_next_domain+0x1438/0x1f77 security/tomoyo/domain.c:881
tomoyo_bprm_check_security security/tomoyo/tomoyo.c:101 [inline]
tomoyo_bprm_check_security+0x121/0x1a0 security/tomoyo/tomoyo.c:91
security_bprm_check+0x45/0xa0 security/security.c:840
search_binary_handler fs/exec.c:1807 [inline]
exec_binprm fs/exec.c:1860 [inline]
bprm_execve+0x879/0x1b10 fs/exec.c:1931
do_execveat_common+0x626/0x7c0 fs/exec.c:2026
do_execve fs/exec.c:2094 [inline]
__do_sys_execve fs/exec.c:2170 [inline]
__se_sys_execve fs/exec.c:2165 [inline]
__x64_sys_execve+0x8f/0xc0 fs/exec.c:2165
do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
entry_SYSCALL_64_after_hwframe+0x44/0xa9

Freed by task 6860:
kasan_save_stack+0x1b/0x40 mm/kasan/common.c:48
kasan_set_track+0x1c/0x30 mm/kasan/common.c:56
kasan_set_free_info+0x1b/0x30 mm/kasan/generic.c:355
__kasan_slab_free+0xd8/0x120 mm/kasan/common.c:422
__cache_free mm/slab.c:3418 [inline]
kfree+0x10e/0x2b0 mm/slab.c:3756
tomoyo_supervisor+0x36e/0xef0 security/tomoyo/common.c:2149
tomoyo_audit_env_log security/tomoyo/environ.c:36 [inline]
tomoyo_env_perm+0x17f/0x1f0 security/tomoyo/environ.c:63
tomoyo_environ security/tomoyo/domain.c:674 [inline]
tomoyo_find_next_domain+0x1438/0x1f77 security/tomoyo/domain.c:881
tomoyo_bprm_check_security security/tomoyo/tomoyo.c:101 [inline]
tomoyo_bprm_check_security+0x121/0x1a0 security/tomoyo/tomoyo.c:91
security_bprm_check+0x45/0xa0 security/security.c:840
search_binary_handler fs/exec.c:1807 [inline]
exec_binprm fs/exec.c:1860 [inline]
bprm_execve+0x879/0x1b10 fs/exec.c:1931
do_execveat_common+0x626/0x7c0 fs/exec.c:2026
do_execve fs/exec.c:2094 [inline]
__do_sys_execve fs/exec.c:2170 [inline]
__se_sys_execve fs/exec.c:2165 [inline]
__x64_sys_execve+0x8f/0xc0 fs/exec.c:2165
do_syscall_64+0x2d/0x70 arch/x86/entry/common.c:46
entry_SYSCALL_64_after_hwframe+0x44/0xa9

The buggy address belongs to the object at ffff88809df49800
which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 254 bytes inside of
1024-byte region [ffff88809df49800, ffff88809df49c00)
The buggy address belongs to the page:
page:000000001b295380 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x9df49
flags: 0xfffe0000000200(slab)
raw: 00fffe0000000200 ffffea00027dc7c8 ffff8880aa041850 ffff8880aa040700
raw: 0000000000000000 ffff88809df49000 0000000100000002 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
ffff88809df49780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff88809df49800: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88809df49880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88809df49900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88809df49980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================

Tetsuo Handa

unread,
Sep 26, 2020, 12:25:30 PM9/26/20
to syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, gre...@linuxfoundation.org, jiri...@kernel.org, syzkall...@googlegroups.com, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org
A simplified reproducer and debug printk() patch shown below reported that
vc_font.height is increased to 9 via ioctl(VT_RESIZEX) after it was once
decreased from 16 to 2 via ioctl(PIO_FONT).



Since vc_resize() with v.v_rows == 0 preserves current vc->vc_rows value,
this reproducer is bypassing

if (v.v_clin) {
int rows = v.v_vlin / v.v_clin;
if (v.v_rows != rows) {
if (v.v_rows) /* Parameters don't add up */
return -EINVAL;
v.v_rows = rows;
}
}

check by setting v.v_vlin == 1 and v.v_clin == 9.

If v.v_vcol > 0 and v.v_vcol != vc->vc_cols (though this reproducer is passing
v.v_vcol == 0), tty_do_resize() from vc_do_resize() from vc_resize() can make
"struct tty_struct"->winsize.ws_ypixel = 1 despite
"struct tty_struct"->winsize.vc->vc_rows = vc->vc_rows (which is usually larger
than 1). Does such winsize (a row has 1 / vc->vc_rows pixel) make sense?



Since I don't know the meaning of "struct vt_consize"->v_clin (which is commented
with "/* number of pixel rows per character */" but does it mean font size ?),
I don't know why we can assign that value to vcp->vc_font.height via

if (v.v_clin)
vcp->vc_font.height = v.v_clin;

in vt_resizex(). While ioctl(PIO_FONT) needs to pass vc->vc_sw->con_font_set()
check in con_font_set(), ioctl(VT_RESIZEX) does not pass it in vt_resizex()...

Since this problem does not happen if I remove

if (v.v_clin)
vcp->vc_font.height = v.v_clin;

from vt_resizex(), I guess that some variables are getting confused by change
of vc->vc_font.height ...

#define VT_RESIZE 0x5609 /* set kernel's idea of screensize */
#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */

Hmm, what comes to the "+ more" part? Who is using VT_RESIZEX ?
If nobody is using VT_RESIZEX, better to make VT_RESIZEX == VT_RESIZE ?

----------
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <linux/vt.h>

int main(int argc, char *argv[])
{
int fd = open("/dev/tty1", 3);
static char fontdata[8192] = { 2, 3 };
struct vt_consize v_c = { 0, 0, 1, 9, 0, 0 };
ioctl(fd, PIO_FONT, fontdata);
ioctl(fd, VT_RESIZEX, &v_c);
return 0;
}
----------

----------
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index a4e520bdd521..df6b7abd1068 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -769,64 +769,70 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
{
struct vt_consize v;
int i;
+ int ret = 0;

if (copy_from_user(&v, cs, sizeof(struct vt_consize)))
return -EFAULT;

- /* FIXME: Should check the copies properly */
- if (!v.v_vlin)
- v.v_vlin = vc->vc_scan_lines;
+ console_lock();
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ struct vc_data *vcp = vc_cons[i].d;

- if (v.v_clin) {
- int rows = v.v_vlin / v.v_clin;
- if (v.v_rows != rows) {
- if (v.v_rows) /* Parameters don't add up */
- return -EINVAL;
- v.v_rows = rows;
+ if (!vcp)
+ continue;
+ if (v.v_clin) {
+ int rows = (v.v_vlin ? v.v_vlin : vcp->vc_scan_lines) / v.v_clin;
+ if (v.v_rows != rows) {
+ if (v.v_rows) { /* Parameters don't add up */
+ ret = -EINVAL;
+ break;
+ }
+ v.v_rows = rows;
+ }
}
- }
-
- if (v.v_vcol && v.v_ccol) {
- int cols = v.v_vcol / v.v_ccol;
- if (v.v_cols != cols) {
- if (v.v_cols)
- return -EINVAL;
- v.v_cols = cols;
+ if (v.v_vcol && v.v_ccol) {
+ int cols = v.v_vcol / v.v_ccol;
+ if (v.v_cols != cols) {
+ if (v.v_cols) {
+ ret = -EINVAL;
+ break;
+ }
+ v.v_cols = cols;
+ }
+ }
+ if (v.v_clin > 32) {
+ ret = -EINVAL;
+ break;
}
}
+ printk(KERN_INFO "vc=%px v.v_rows=%hu v.v_cols=%hu v.v_vlin=%hu v.v_clin=%u v.v_vcol=%hu v.v_ccol=%hu ret=%d\n", vc, v.v_rows, v.v_cols, v.v_vlin, v.v_clin, v.v_vcol, v.v_ccol, ret);
+ for (i = 0; !ret && i < MAX_NR_CONSOLES; i++) {
+ unsigned int save_scan_lines;
+ unsigned int save_font_height;
+ struct vc_data *vcp = vc_cons[i].d;

- if (v.v_clin > 32)
- return -EINVAL;
-
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- struct vc_data *vcp;
-
- if (!vc_cons[i].d)
+ if (!vcp)
continue;
- console_lock();
- vcp = vc_cons[i].d;
- if (vcp) {
- int ret;
- int save_scan_lines = vcp->vc_scan_lines;
- int save_font_height = vcp->vc_font.height;
-
- if (v.v_vlin)
- vcp->vc_scan_lines = v.v_vlin;
- if (v.v_clin)
- vcp->vc_font.height = v.v_clin;
- vcp->vc_resize_user = 1;
- ret = vc_resize(vcp, v.v_cols, v.v_rows);
- if (ret) {
- vcp->vc_scan_lines = save_scan_lines;
- vcp->vc_font.height = save_font_height;
- console_unlock();
- return ret;
- }
+ save_scan_lines = vcp->vc_scan_lines;
+ save_font_height = vcp->vc_font.height;
+ if (v.v_vlin)
+ vcp->vc_scan_lines = v.v_vlin;
+ if (v.v_clin)
+ vcp->vc_font.height = v.v_clin;
+ printk(KERN_INFO "vcp=%px before: ->vc_rows=%u ->vc_cols=%u ->vc_scan_lines=%u save_scan_lines=%u ->vc_font.height=%u save_font_height=%u\n",
+ vcp, vcp->vc_rows, vcp->vc_cols, vcp->vc_scan_lines, save_scan_lines, vcp->vc_font.height, save_font_height);
+ vcp->vc_resize_user = 1;
+ ret = vc_resize(vcp, v.v_cols, v.v_rows);
+ printk(KERN_INFO "vcp=%px after: ->vc_rows=%u ->vc_cols=%u ->vc_scan_lines=%u save_scan_lines=%u ->vc_font.height=%u save_font_height=%u ret=%d\n",
+ vcp, vcp->vc_rows, vcp->vc_cols, vcp->vc_scan_lines, save_scan_lines, vcp->vc_font.height, save_font_height, ret);
+ if (ret) {
+ vcp->vc_scan_lines = save_scan_lines;
+ vcp->vc_font.height = save_font_height;
}
- console_unlock();
}
+ console_unlock();

- return 0;
+ return ret;
}

/*
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 9725ecd1255b..c1b9f43ff657 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -181,6 +181,8 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
dst = fb_get_buffer_offset(info, &info->pixmap, size);
image.data = dst;

+ printk(KERN_DEBUG "%s: width=%u cellsize=%u count=%d maxcnt=%u scan_align=%u buf_align=%u image.width=%u image.height=%u pitch=%u\n",
+ __func__, width, cellsize, count, maxcnt, scan_align, buf_align, image.width, image.height, pitch);
if (!mod)
bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
width, cellsize, &image, buf, dst);
----------

----------
[ 297.298013] [ T2823] bit_putcs: width=1 cellsize=16 count=80 maxcnt=512 scan_align=0 buf_align=0 image.width=640 image.height=16 pitch=80
[ 297.312092] [ T2823] bit_putcs: width=1 cellsize=16 count=80 maxcnt=512 scan_align=0 buf_align=0 image.width=640 image.height=16 pitch=80
[ 297.324735] [ T2823] bit_putcs: width=1 cellsize=16 count=80 maxcnt=512 scan_align=0 buf_align=0 image.width=640 image.height=16 pitch=80
[ 297.337634] [ T2823] bit_putcs: width=1 cellsize=16 count=80 maxcnt=512 scan_align=0 buf_align=0 image.width=640 image.height=16 pitch=80
[ 297.350185] [ T2823] bit_putcs: width=1 cellsize=16 count=80 maxcnt=512 scan_align=0 buf_align=0 image.width=640 image.height=16 pitch=80
[ 297.361861] [ T2823] bit_putcs: width=1 cellsize=16 count=80 maxcnt=512 scan_align=0 buf_align=0 image.width=640 image.height=16 pitch=80
[ 297.474116] [ T2823] bit_putcs: width=1 cellsize=16 count=28 maxcnt=512 scan_align=0 buf_align=0 image.width=224 image.height=16 pitch=28
[ 297.481866] [ T2823] bit_putcs: width=1 cellsize=16 count=4 maxcnt=512 scan_align=0 buf_align=0 image.width=32 image.height=16 pitch=4
[ 297.483529] [ T2823] bit_putcs: width=1 cellsize=16 count=1 maxcnt=512 scan_align=0 buf_align=0 image.width=8 image.height=16 pitch=1
[ 297.484792] [ T2823] bit_putcs: width=1 cellsize=16 count=7 maxcnt=512 scan_align=0 buf_align=0 image.width=56 image.height=16 pitch=7
[ 357.373828] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.375232] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.376821] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.378256] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.379684] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
(...snipped...)
[ 357.720089] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.721519] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.722962] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.724390] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.725834] [ T2940] bit_putcs: width=1 cellsize=2 count=80 maxcnt=4096 scan_align=0 buf_align=0 image.width=640 image.height=2 pitch=80
[ 357.727876] [ T2940] vc=ffff8880d69b6000 v.v_rows=0 v.v_cols=0 v.v_vlin=1 v.v_clin=9 v.v_vcol=0 v.v_ccol=0 ret=0
[ 357.727933] [ T2940] vcp=ffff8880d69b6000 before: ->vc_rows=240 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=400 ->vc_font.height=9 save_font_height=2
[ 357.727994] [ T2940] vcp=ffff8880d69b6000 after: ->vc_rows=240 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=400 ->vc_font.height=9 save_font_height=2 ret=0
[ 357.728050] [ T2940] vcp=ffff8880d46d9000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 357.728110] [ T2940] vcp=ffff8880d46d9000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 357.728167] [ T2940] vcp=ffff8880d40a8000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 357.728227] [ T2940] vcp=ffff8880d40a8000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 357.728283] [ T2940] vcp=ffff8880d46fb000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 357.728344] [ T2940] vcp=ffff8880d46fb000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 357.728400] [ T2940] vcp=ffff8880d46f9000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 357.728460] [ T2940] vcp=ffff8880d46f9000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 357.728516] [ T2940] vcp=ffff8880ce2d1000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 357.728616] [ T2940] vcp=ffff8880ce2d1000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 357.743762] [ C0] bit_putcs: width=1 cellsize=9 count=68 maxcnt=910 scan_align=0 buf_align=0 image.width=544 image.height=9 pitch=68
[ 357.743783] [ C0] ==================================================================
[ 357.743803] [ C0] BUG: KASAN: slab-out-of-bounds in bit_putcs+0x6a0/0x980
[ 357.743822] [ C0] Read of size 1 at addr ffff8880d46ff343 by task a.out/2940
[ 357.743830] [ C0]
[ 357.743848] [ C0] CPU: 0 PID: 2940 Comm: a.out Not tainted 5.9.0-rc6+ #635
[ 357.743871] [ C0] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 357.743880] [ C0] Call Trace:
[ 357.743891] [ C0] dump_stack+0x161/0x1c3
[ 357.743902] [ C0] ? bit_putcs+0x6a0/0x980
[ 357.743914] [ C0] ? bit_putcs+0x6a0/0x980
[ 357.743932] [ C0] print_address_description.constprop.0.cold+0xd3/0x4c5
[ 357.743944] [ C0] ? log_store.cold+0x16/0x16
[ 357.743956] [ C0] ? vprintk_func+0xe2/0x155
[ 357.743968] [ C0] ? bit_putcs+0x6a0/0x980
[ 357.743979] [ C0] ? bit_putcs+0x6a0/0x980
[ 357.743992] [ C0] kasan_report.cold+0x1f/0x42
[ 357.744003] [ C0] ? bit_putcs+0x6a0/0x980
[ 357.744014] [ C0] bit_putcs+0x6a0/0x980
[ 357.744026] [ C0] ? bit_clear+0x2f0/0x2f0
[ 357.744038] [ C0] ? find_held_lock+0x85/0xa0
[ 357.744052] [ C0] ? raw_notifier_call_chain+0x31/0x40
[ 357.744067] [ C0] ? fb_get_color_depth.part.0+0x57/0xe0
[ 357.744082] [ C0] ? __sanitizer_cov_trace_switch+0x49/0x80
[ 357.744093] [ C0] fbcon_putcs+0x1d8/0x1e0
[ 357.744105] [ C0] ? bit_clear+0x2f0/0x2f0
[ 357.744118] [ C0] vt_console_print+0x72d/0x870
[ 357.744130] [ C0] ? fb_flashcursor+0x230/0x230
[ 357.744144] [ C0] ? screen_glyph_unicode+0x140/0x140
[ 357.744157] [ C0] ? rwlock_bug.part.0+0x50/0x50
[ 357.744171] [ C0] ? screen_glyph_unicode+0x140/0x140
[ 357.744183] [ C0] console_unlock+0x92c/0xb30
[ 357.744195] [ C0] vt_ioctl.cold+0x182/0x3a2
[ 357.744210] [ C0] ? complete_change_console+0x1e0/0x1e0
[ 357.744222] [ C0] ? find_held_lock+0x85/0xa0
[ 357.744237] [ C0] ? debug_check_no_obj_freed+0x18d/0x276
[ 357.744249] [ C0] ? lock_downgrade+0x3e0/0x3e0
[ 357.744261] [ C0] ? find_held_lock+0x85/0xa0
[ 357.744274] [ C0] ? lock_is_held_type+0xbf/0xf0
[ 357.744285] [ C0] ? putname+0xa7/0xc0
[ 357.744296] [ C0] ? putname+0xa7/0xc0
[ 357.744306] [ C0] ? putname+0xa7/0xc0
[ 357.744322] [ C0] ? __sanitizer_cov_trace_switch+0x49/0x80
[ 357.744336] [ C0] ? complete_change_console+0x1e0/0x1e0
[ 357.744361] [ C0] ? tty_ioctl+0x7c4/0xec0
[ 357.744373] [ C0] tty_ioctl+0x7c4/0xec0
[ 357.744387] [ C0] ? kmem_cache_free.part.0+0x1b0/0x1e0
[ 357.744399] [ C0] ? tty_vhangup+0x30/0x30
[ 357.744414] [ C0] ? __sanitizer_cov_trace_switch+0x49/0x80
[ 357.744426] [ C0] ? do_vfs_ioctl+0x224/0xc50
[ 357.744439] [ C0] ? ioctl_file_clone+0x140/0x140
[ 357.744452] [ C0] ? file_open_root+0x420/0x420
[ 357.744467] [ C0] ? check_preemption_disabled+0x50/0x130
[ 357.744479] [ C0] ? lock_is_held_type+0xbf/0xf0
[ 357.744495] [ C0] ? syscall_enter_from_user_mode+0x1c/0x60
[ 357.744509] [ C0] ? rcu_read_lock_sched_held+0xa0/0xd0
[ 357.744521] [ C0] ? mark_held_locks+0x24/0x90
[ 357.744533] [ C0] ? tty_vhangup+0x30/0x30
[ 357.744545] [ C0] __x64_sys_ioctl+0xec/0x140
[ 357.744557] [ C0] do_syscall_64+0x31/0x70
[ 357.744572] [ C0] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 357.744583] [ C0] RIP: 0033:0x7f9b8316150b
[ 357.744632] [ C0] Code: 0f 1e fa 48 8b 05 85 39 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 55 39 0d 00 f7 d8 64 89 01 48
[ 357.744647] [ C0] RSP: 002b:00007ffe190139b8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 357.744680] [ C0] RAX: ffffffffffffffda RBX: 000055dc2ea7b220 RCX: 00007f9b8316150b
[ 357.744701] [ C0] RDX: 00007ffe190139cc RSI: 000000000000560a RDI: 0000000000000003
[ 357.744721] [ C0] RBP: 0000000000000003 R08: 0000000000000000 R09: 00007f9b83257d50
[ 357.744741] [ C0] R10: 0000000000000000 R11: 0000000000000246 R12: 000055dc2ea7b130
[ 357.744762] [ C0] R13: 00007ffe19013ad0 R14: 0000000000000000 R15: 0000000000000000
[ 357.744769] [ C0]
[ 357.744781] [ C0] Allocated by task 2940:
[ 357.744793] [ C0] kasan_save_stack+0x1f/0x40
[ 357.744808] [ C0] __kasan_kmalloc.constprop.0+0xbf/0xd0
[ 357.744819] [ C0] __kmalloc+0x57d/0x9d0
[ 357.744831] [ C0] fbcon_set_font+0x1a6/0x4a0
[ 357.744843] [ C0] con_font_op+0x8e2/0xac0
[ 357.744854] [ C0] vt_ioctl+0x1186/0x21a0
[ 357.744866] [ C0] tty_ioctl+0x7c4/0xec0
[ 357.744878] [ C0] __x64_sys_ioctl+0xec/0x140
[ 357.744889] [ C0] do_syscall_64+0x31/0x70
[ 357.744905] [ C0] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 357.744912] [ C0]
[ 357.744932] [ C0] The buggy address belongs to the object at ffff8880d46ff000
[ 357.744949] [ C0] which belongs to the cache kmalloc-1k of size 1024
[ 357.744967] [ C0] The buggy address is located 835 bytes inside of
[ 357.744985] [ C0] 1024-byte region [ffff8880d46ff000, ffff8880d46ff400)
[ 357.745000] [ C0] The buggy address belongs to the page:
[ 357.745027] [ C0] page:00000000878ccadc refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xd46ff
[ 357.745040] [ C0] flags: 0xfffe0000000200(slab)
[ 357.745063] [ C0] raw: 00fffe0000000200 ffffea00032a0808 ffffea00035ae308 ffff8880d6840700
[ 357.745086] [ C0] raw: 0000000000000000 ffff8880d46ff000 0000000100000002 ffff8880cbe8b281
[ 357.745103] [ C0] page dumped because: kasan: bad access detected
[ 357.745117] [ C0] page->mem_cgroup:ffff8880cbe8b281
[ 357.745125] [ C0]
[ 357.745140] [ C0] Memory state around the buggy address:
[ 357.745162] [ C0] ffff8880d46ff200: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 357.745186] [ C0] ffff8880d46ff280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 357.745208] [ C0] >ffff8880d46ff300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 357.745224] [ C0] ^
[ 357.745246] [ C0] ffff8880d46ff380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 357.745267] [ C0] ffff8880d46ff400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 357.745288] [ C0] ==================================================================
[ 357.745305] [ C0] Disabling lock debugging due to kernel taint
[ 357.745349] [ C0] bit_putcs: width=1 cellsize=9 count=46 maxcnt=910 scan_align=0 buf_align=0 image.width=368 image.height=9 pitch=46
[ 357.759878] [ C0] bit_putcs: width=1 cellsize=9 count=80 maxcnt=910 scan_align=0 buf_align=0 image.width=640 image.height=9 pitch=80
[ 357.759910] [ C0] bit_putcs: width=1 cellsize=9 count=74 maxcnt=910 scan_align=0 buf_align=0 image.width=592 image.height=9 pitch=74
[ 357.775006] [ C0] bit_putcs: width=1 cellsize=9 count=80 maxcnt=910 scan_align=0 buf_align=0 image.width=640 image.height=9 pitch=80
----------

Peilin Ye

unread,
Sep 26, 2020, 3:40:07 PM9/26/20
to Tetsuo Handa, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, gre...@linuxfoundation.org, jiri...@kernel.org, syzkall...@googlegroups.com, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, yepei...@gmail.com
Hi Tetsuo!

> from vt_resizex(), I guess that some variables are getting confused by change
> of vc->vc_font.height ...

Yes, see bit_putcs():

(drivers/video/fbdev/core/bitblit.c)
static void bit_putcs(struct vc_data *vc, struct fb_info *info,
const unsigned short *s, int count, int yy, int xx,
int fg, int bg)
{
struct fb_image image;
u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
u32 cellsize = width * vc->vc_font.height;
^^^^^^^^ ^^^^^^^^^^^^^^

`cellsize` is now too large. Later, in bit_putcs_aligned():

while (cnt--) {
src = vc->vc_font.data + (scr_readw(s++)&
charmask)*cellsize;
^^^^^^^^

`src` goes out of bounds of the data buffer. At first glance I guess
this is an out-of-bound read reported as a use-after-free read? The
crashlog says:

[ 149.732103][ T6693] Allocated by task 6667:
[ 149.732115][ T6693] kasan_save_stack (mm/kasan/common.c:48)
[ 149.732121][ T6693] __kasan_kmalloc.constprop.0 (mm/kasan/common.c:56 mm/kasan/common.c:461)
[ 149.732126][ T6693] __kmalloc (mm/slab.c:3656 mm/slab.c:3664)
[ 149.732133][ T6693] alloc_pipe_info (fs/pipe.c:810)
[ 149.732139][ T6693] create_pipe_files (fs/pipe.c:883 fs/pipe.c:914)
[ 149.732145][ T6693] do_pipe2 (fs/pipe.c:965 fs/pipe.c:1012)

I'm not sure, but I don't think a buffer allocated in fs/pipe.c is
related here. Maybe they just live near each other on the heap?

To resolve this out-of-bound issue for now, I think the easiest way
is to add a range check in bit_putcs(), or bit_putcs_aligned().

...but yeah, that `VT_RESIZEX` ioctl looks really buggy, and is already
causing more issues:

KASAN: global-out-of-bounds Read in fbcon_get_font
Link: https://syzkaller.appspot.com/bug?id=08b8be45afea11888776f897895aef9ad1c3ecfd

This was also caused by `VT_RESIZEX`...

Thank you,
Peilin Ye

Tetsuo Handa

unread,
Sep 26, 2020, 8:25:17 PM9/26/20
to syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, gre...@linuxfoundation.org, jiri...@kernel.org, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org
On 2020/09/27 4:39, Peilin Ye wrote:
> On Sun, Sep 27, 2020 at 01:25:17AM +0900, Tetsuo Handa wrote:
>> Since I don't know the meaning of "struct vt_consize"->v_clin (which is commented
>> with "/* number of pixel rows per character */" but does it mean font size ?),
>> I don't know why we can assign that value to vcp->vc_font.height via
>>
>> if (v.v_clin)
>> vcp->vc_font.height = v.v_clin;
>>
>> in vt_resizex(). While ioctl(PIO_FONT) needs to pass vc->vc_sw->con_font_set()
>> check in con_font_set(), ioctl(VT_RESIZEX) does not pass it in vt_resizex()...
>>
>> Since this problem does not happen if I remove
>>
>> if (v.v_clin)
>> vcp->vc_font.height = v.v_clin;
>
> Hi Tetsuo!
>
>> from vt_resizex(), I guess that some variables are getting confused by change
>> of vc->vc_font.height ...
>
> Yes, see bit_putcs():
>
> (drivers/video/fbdev/core/bitblit.c)
> static void bit_putcs(struct vc_data *vc, struct fb_info *info,
> const unsigned short *s, int count, int yy, int xx,
> int fg, int bg)
> {
> struct fb_image image;
> u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
> u32 cellsize = width * vc->vc_font.height;
> ^^^^^^^^ ^^^^^^^^^^^^^^
>
> `cellsize` is now too large. Later, in bit_putcs_aligned():
>
> while (cnt--) {
> src = vc->vc_font.data + (scr_readw(s++)&
> charmask)*cellsize;
> ^^^^^^^^
>
> `src` goes out of bounds of the data buffer. At first glance I guess
> this is an out-of-bound read reported as a use-after-free read? The
> crashlog says:

How this OOB access is reported varies.

>
> To resolve this out-of-bound issue for now, I think the easiest way
> is to add a range check in bit_putcs(), or bit_putcs_aligned().
>
> ...but yeah, that `VT_RESIZEX` ioctl looks really buggy, and is already
> causing more issues:

At least, since not all fonts have height == 32 (e.g. font_vga_8x8 is height == 8),
allow changing vc->vc_font.height with only

if (v.v_clin > 32)
return -EINVAL;

validation in VT_RESIZEX looks wrong. This needs more validations.



By the way, can we find a user of VT_RESIZEX? As far as I googled with "VT_RESIZEX",
I couldn't find a userspace program; only explanation of VT_RESIZEX and kernel patches
related to VT_RESIZEX are found. Also, while console_ioctl(4) man page says

Any parameter may be set to zero, indicating "no change"

, the assignment

if (!v.v_vlin)
v.v_vlin = vc->vc_scan_lines;

changes the meaning to

If v_vlin parameter is set to zero, the value for associated console is copied
to each console (instead of preserving current value for that console)

. Maybe for now we can try this (effectively making VT_RESIZEX == VT_RESIZE) ?

vt_ioctl.c | 57 ++++++++++-----------------------------------------------
1 file changed, 10 insertions(+), 47 deletions(-)

diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index a4e520bdd521..bc33938e2f20 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -773,58 +773,21 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
if (copy_from_user(&v, cs, sizeof(struct vt_consize)))
return -EFAULT;

- /* FIXME: Should check the copies properly */
- if (!v.v_vlin)
- v.v_vlin = vc->vc_scan_lines;
-
- if (v.v_clin) {
- int rows = v.v_vlin / v.v_clin;
- if (v.v_rows != rows) {
- if (v.v_rows) /* Parameters don't add up */
- return -EINVAL;
- v.v_rows = rows;
- }
- }
-
- if (v.v_vcol && v.v_ccol) {
- int cols = v.v_vcol / v.v_ccol;
- if (v.v_cols != cols) {
- if (v.v_cols)
- return -EINVAL;
- v.v_cols = cols;
- }
- }
-
- if (v.v_clin > 32)
- return -EINVAL;
+ if (v.v_vlin)
+ pr_info_once("\"struct vt_consize\"->v_vlin is ignored. Please report if you need this.\n");
+ if (v.v_clin)
+ pr_info_once("\"struct vt_consize\"->v_clin is ignored. Please report if you need this.\n");

+ console_lock();
for (i = 0; i < MAX_NR_CONSOLES; i++) {
- struct vc_data *vcp;
+ vc = vc_cons[i].d;

- if (!vc_cons[i].d)
- continue;
- console_lock();
- vcp = vc_cons[i].d;
- if (vcp) {
- int ret;
- int save_scan_lines = vcp->vc_scan_lines;
- int save_font_height = vcp->vc_font.height;
-
- if (v.v_vlin)
- vcp->vc_scan_lines = v.v_vlin;
- if (v.v_clin)
- vcp->vc_font.height = v.v_clin;
- vcp->vc_resize_user = 1;
- ret = vc_resize(vcp, v.v_cols, v.v_rows);
- if (ret) {
- vcp->vc_scan_lines = save_scan_lines;
- vcp->vc_font.height = save_font_height;
- console_unlock();
- return ret;
- }
+ if (vc) {
+ vc->vc_resize_user = 1;
+ vc_resize(vc, v.v_cols, v.v_rows);
}
- console_unlock();
}
+ console_unlock();

return 0;
}

Tetsuo Handa

unread,
Sep 27, 2020, 4:28:28 AM9/27/20
to syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, gre...@linuxfoundation.org, jiri...@kernel.org, syzkall...@googlegroups.com, Linus Torvalds, Peilin Ye, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org
Well, vt_io_ioctl(PIO_FONT) initializes "struct console_font_op op;" with

op.width = 8;
op.height = 0;
op.charcount = 256;

and calls con_font_set() from con_font_op(). But the "/* Need to guess font height [compat] */"
chunk in con_font_set() guesses font's height due to being initialized with op.height = 0.
Then, con_font_set() calls fbcon_set_font() via vc->vc_sw->con_font_set(), and fbcon_set_font()
allocates minimal amount of memory for font data based on font's height calcllated by con_font_set().

Therefore, any attempt to change font's height (like vt_resizex()) larger than font's height
calculated by con_font_set() can cause OOB read of memory block for font data. If we allocate
maximal amount of memory for any font, OOB read of memory block for font data should not happen.

----------------------------------------

static char fontdata[8192] = { 2 };

[ 227.065369] bit_putcs: width=1 cellsize=1 count=80 maxcnt=8192 scan_align=0 buf_align=0 image.height=1
[ 227.066254] bit_putcs: width=1 cellsize=1 count=80 maxcnt=8192 scan_align=0 buf_align=0 image.height=1
[ 227.067642] vc=ffff8880d69b4000 v.v_rows=0 v.v_cols=0 v.v_vlin=1 v.v_clin=9 v.v_vcol=0 v.v_ccol=0 ret=0
[ 227.067699] vcp=ffff8880d69b4000 before: ->vc_rows=480 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=400 ->vc_font.height=9 save_font_height=1
[ 227.067774] vcp=ffff8880d69b4000 after: ->vc_rows=480 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=400 ->vc_font.height=9 save_font_height=1 ret=0
[ 227.067831] vcp=ffff8880cac4b000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 227.067891] vcp=ffff8880cac4b000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 227.067947] vcp=ffff8880c6180000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 227.068007] vcp=ffff8880c6180000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 227.068063] vcp=ffff8880d6b84000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 227.068123] vcp=ffff8880d6b84000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 227.068179] vcp=ffff8880ca8c0000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 227.068255] vcp=ffff8880ca8c0000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 227.068455] vcp=ffff8880cbd5d000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 227.068515] vcp=ffff8880cbd5d000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 227.084709] ==================================================================
[ 227.084729] BUG: KASAN: slab-out-of-bounds in soft_cursor+0x34e/0x4a0
[ 227.084748] Read of size 9 at addr ffff8880c98d5930 by task a.out/1662

[ 227.084786] CPU: 3 PID: 1662 Comm: a.out Not tainted 5.9.0-rc6+ #639
[ 227.084810] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 227.084818] Call Trace:
[ 227.084830] dump_stack+0x161/0x1c3
[ 227.084842] ? soft_cursor+0x34e/0x4a0
[ 227.084854] ? soft_cursor+0x34e/0x4a0
[ 227.084871] print_address_description.constprop.0.cold+0xd3/0x4c5
[ 227.084884] ? lock_is_held_type+0xbf/0xf0
[ 227.084896] ? vprintk_func+0xe2/0x155
[ 227.084908] ? soft_cursor+0x34e/0x4a0
[ 227.084920] ? soft_cursor+0x34e/0x4a0
[ 227.084932] kasan_report.cold+0x1f/0x42
[ 227.084944] ? soft_cursor+0x34e/0x4a0
[ 227.084957] check_memory_region+0x152/0x1b0
[ 227.084967] memcpy+0x24/0x60
[ 227.084979] soft_cursor+0x34e/0x4a0
[ 227.084990] bit_cursor+0x7f6/0xce6
[ 227.085001] ? bit_putcs+0x320/0x320
[ 227.085016] ? fb_get_color_depth.part.0+0x57/0xe0
[ 227.085031] ? __sanitizer_cov_trace_switch+0x49/0x80
[ 227.085042] ? bit_putcs+0x320/0x320
[ 227.085054] fbcon_cursor+0x241/0x2c0
[ 227.085065] hide_cursor+0x58/0x150
[ 227.085077] vt_console_print+0x865/0x870
[ 227.085089] ? lock_release+0x480/0x480
[ 227.085102] ? lock_downgrade+0x3e0/0x3e0
[ 227.085115] ? do_raw_spin_lock+0x110/0x1f0
[ 227.085128] ? screen_glyph_unicode+0x140/0x140
[ 227.085141] ? rwlock_bug.part.0+0x50/0x50
[ 227.085156] ? check_preemption_disabled+0x50/0x130
[ 227.085169] ? screen_glyph_unicode+0x140/0x140
[ 227.085181] console_unlock+0x92c/0xb30
[ 227.085193] vt_ioctl.cold+0x182/0x3a2
[ 227.085207] ? complete_change_console+0x1e0/0x1e0
[ 227.085219] ? find_held_lock+0x85/0xa0
[ 227.085234] ? debug_check_no_obj_freed+0x18d/0x276
[ 227.085246] ? lock_downgrade+0x3e0/0x3e0
[ 227.085258] ? find_held_lock+0x85/0xa0
[ 227.085271] ? lock_is_held_type+0xbf/0xf0
[ 227.085281] ? putname+0xa7/0xc0
[ 227.085292] ? putname+0xa7/0xc0
[ 227.085302] ? putname+0xa7/0xc0
[ 227.085317] ? __sanitizer_cov_trace_switch+0x49/0x80
[ 227.085332] ? complete_change_console+0x1e0/0x1e0
[ 227.085343] ? tty_ioctl+0x7c4/0xec0
[ 227.085368] tty_ioctl+0x7c4/0xec0
[ 227.085383] ? kmem_cache_free.part.0+0x1b0/0x1e0
[ 227.085394] ? tty_vhangup+0x30/0x30
[ 227.085409] ? __sanitizer_cov_trace_switch+0x49/0x80
[ 227.085421] ? do_vfs_ioctl+0x224/0xc50
[ 227.085434] ? ioctl_file_clone+0x140/0x140
[ 227.085449] ? rcu_read_lock_sched_held+0xa0/0xd0
[ 227.085464] ? rcu_read_lock_any_held.part.0+0x30/0x30
[ 227.085479] ? check_preemption_disabled+0x50/0x130
[ 227.085491] ? lock_is_held_type+0xbf/0xf0
[ 227.085506] ? syscall_enter_from_user_mode+0x1c/0x60
[ 227.085520] ? rcu_read_lock_sched_held+0xa0/0xd0
[ 227.085533] ? mark_held_locks+0x24/0x90
[ 227.085544] ? tty_vhangup+0x30/0x30
[ 227.085556] __x64_sys_ioctl+0xec/0x140
[ 227.085568] do_syscall_64+0x31/0x70
[ 227.085583] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 227.085594] RIP: 0033:0x7f261b69e50b
[ 227.085643] Code: 0f 1e fa 48 8b 05 85 39 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 55 39 0d 00 f7 d8 64 89 01 48
[ 227.085658] RSP: 002b:00007fff1894fb98 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 227.085691] RAX: ffffffffffffffda RBX: 0000560076c54220 RCX: 00007f261b69e50b
[ 227.085711] RDX: 00007fff1894fbac RSI: 000000000000560a RDI: 0000000000000003
[ 227.085731] RBP: 0000000000000003 R08: 0000000000000000 R09: 00007f261b794d50
[ 227.085751] R10: 0000000000000000 R11: 0000000000000246 R12: 0000560076c54130
[ 227.085771] R13: 00007fff1894fcb0 R14: 0000000000000000 R15: 0000000000000000

[ 227.085791] Allocated by task 1662:
[ 227.085803] kasan_save_stack+0x1f/0x40
[ 227.085817] __kasan_kmalloc.constprop.0+0xbf/0xd0
[ 227.085828] __kmalloc+0x57d/0x9d0
[ 227.085840] fbcon_set_font+0x1a6/0x4a0
[ 227.085852] con_font_op+0x8e2/0xac0
[ 227.085863] vt_ioctl+0x1186/0x21a0
[ 227.085874] tty_ioctl+0x7c4/0xec0
[ 227.085886] __x64_sys_ioctl+0xec/0x140
[ 227.085898] do_syscall_64+0x31/0x70
[ 227.085913] entry_SYSCALL_64_after_hwframe+0x44/0xa9

[ 227.085940] The buggy address belongs to the object at ffff8880c98d5800
[ 227.085957] which belongs to the cache kmalloc-512 of size 512
[ 227.085974] The buggy address is located 304 bytes inside of
[ 227.085992] 512-byte region [ffff8880c98d5800, ffff8880c98d5a00)
[ 227.086007] The buggy address belongs to the page:
[ 227.086033] page:00000000022668f3 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xc98d5
[ 227.086047] flags: 0xfffe0000000200(slab)
[ 227.086081] raw: 00fffe0000000200 ffffea00032c4b08 ffffea0003205748 ffff8880d6840600
[ 227.086104] raw: 0000000000000000 ffff8880c98d5000 0000000100000004 ffff8880d2419241
[ 227.086121] page dumped because: kasan: bad access detected
[ 227.086136] page->mem_cgroup:ffff8880d2419241

[ 227.086158] Memory state around the buggy address:
[ 227.086179] ffff8880c98d5800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 227.086201] ffff8880c98d5880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 227.086222] >ffff8880c98d5900: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 227.086237] ^
[ 227.086258] ffff8880c98d5980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 227.086279] ffff8880c98d5a00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 227.086301] ==================================================================

----------------------------------------

static char fontdata[8192] = { 2, 3 };

[ 464.415205] vcp=ffff8880d69b4000 before: ->vc_rows=240 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=1 ->vc_font.height=9 save_font_height=2
[ 464.415265] vcp=ffff8880d69b4000 after: ->vc_rows=240 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=1 ->vc_font.height=9 save_font_height=2 ret=0

[ 464.431257] bit_putcs: width=1 cellsize=9 count=68 maxcnt=910 scan_align=0 buf_align=0 image.height=9
[ 464.431279] ==================================================================
[ 464.431299] BUG: KASAN: slab-out-of-bounds in bit_putcs.cold+0x570/0x5aa
[ 464.431319] Read of size 1 at addr ffff8880ca0ccb43 by task a.out/1757

----------------------------------------

static char fontdata[8192] = "0123456789abcdef0123456789abcdef";

[ 300.610119] bit_putcs: width=1 cellsize=32 count=80 maxcnt=256 scan_align=0 buf_align=0 image.height=32
[ 300.630932] bit_putcs: width=1 cellsize=32 count=80 maxcnt=256 scan_align=0 buf_align=0 image.height=32
[ 300.652194] vc=ffff8880d69b4000 v.v_rows=0 v.v_cols=0 v.v_vlin=1 v.v_clin=9 v.v_vcol=0 v.v_ccol=0 ret=0
[ 300.652249] vcp=ffff8880d69b4000 before: ->vc_rows=15 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=400 ->vc_font.height=9 save_font_height=32
[ 300.652308] vcp=ffff8880d69b4000 after: ->vc_rows=15 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=400 ->vc_font.height=9 save_font_height=32 ret=0
[ 300.652500] vcp=ffff8880d55ba000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 300.652559] vcp=ffff8880d55ba000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 300.652613] vcp=ffff8880d4d87000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 300.652690] vcp=ffff8880d4d87000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 300.652767] vcp=ffff8880d546b000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 300.652849] vcp=ffff8880d546b000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 300.652926] vcp=ffff8880c8f85000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 300.653008] vcp=ffff8880c8f85000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 300.653085] vcp=ffff8880d55db000 before: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16
[ 300.653167] vcp=ffff8880d55db000 after: ->vc_rows=30 ->vc_cols=80 ->vc_scan_lines=1 save_scan_lines=0 ->vc_font.height=9 save_font_height=16 ret=0
[ 300.665421] bit_putcs: width=1 cellsize=9 count=68 maxcnt=910 scan_align=0 buf_align=0 image.height=9
[ 300.665450] bit_putcs: width=1 cellsize=9 count=46 maxcnt=910 scan_align=0 buf_align=0 image.height=9

----------------------------------------

Peilin Ye

unread,
Sep 27, 2020, 5:27:11 AM9/27/20
to Tetsuo Handa, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, gre...@linuxfoundation.org, jiri...@kernel.org, syzkall...@googlegroups.com, Linus Torvalds, Peilin Ye, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org
Very interesting, I remember seeing this on the syzbot dashboard...

Yes, I guess it is this one:
KASAN: slab-out-of-bounds Read in soft_cursor
https://syzkaller.appspot.com/bug?id=6b8355d27b2b94fb5cedf4655e3a59162d9e48e3

There is a `0x560aul` ioctl() in the reproducer, which is `VT_RESIZEX`.

Thank you,
Peilin Ye

Tetsuo Handa

unread,
Sep 27, 2020, 7:46:40 AM9/27/20
to gre...@linuxfoundation.org, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
syzbot is reporting UAF/OOB read at bit_putcs()/soft_cursor() [1][2], for
vt_resizex() from ioctl(VT_RESIZEX) allows setting font height larger than
actual font height calculated by con_font_set() from ioctl(PIO_FONT).
Since fbcon_set_font() from con_font_set() allocates minimal amount of
memory based on actual font height calculated by con_font_set(),
use of vt_resizex() can cause UAF/OOB read for font data.

VT_RESIZEX was introduced in Linux 1.3.3, but it is unclear that what
comes to the "+ more" part, and I couldn't find a user of VT_RESIZEX.

#define VT_RESIZE 0x5609 /* set kernel's idea of screensize */
#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */

So far we are not aware of syzbot reports caused by setting non-zero value
to v_vlin parameter. But given that it is possible that nobody is using
VT_RESIZEX, we can try removing support for v_clin and v_vlin parameters.

Therefore, this patch effectively makes VT_RESIZEX behave like VT_RESIZE,
with emitting a message if somebody is still using v_clin and/or v_vlin
parameters.

[1] https://syzkaller.appspot.com/bug?id=32577e96d88447ded2d3b76d71254fb855245837
[2] https://syzkaller.appspot.com/bug?id=6b8355d27b2b94fb5cedf4655e3a59162d9e48e3

Reported-by: syzbot <syzbot+b308f5...@syzkaller.appspotmail.com>
Reported-by: syzbot <syzbot+16469b...@syzkaller.appspotmail.com>
Signed-off-by: Tetsuo Handa <penguin...@I-love.SAKURA.ne.jp>
---
drivers/tty/vt/vt_ioctl.c | 57 +++++++--------------------------------
--
2.25.1

Greg KH

unread,
Sep 27, 2020, 8:06:50 AM9/27/20
to Tetsuo Handa, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
On Sun, Sep 27, 2020 at 08:46:30PM +0900, Tetsuo Handa wrote:
> syzbot is reporting UAF/OOB read at bit_putcs()/soft_cursor() [1][2], for
> vt_resizex() from ioctl(VT_RESIZEX) allows setting font height larger than
> actual font height calculated by con_font_set() from ioctl(PIO_FONT).
> Since fbcon_set_font() from con_font_set() allocates minimal amount of
> memory based on actual font height calculated by con_font_set(),
> use of vt_resizex() can cause UAF/OOB read for font data.
>
> VT_RESIZEX was introduced in Linux 1.3.3, but it is unclear that what
> comes to the "+ more" part, and I couldn't find a user of VT_RESIZEX.
>
> #define VT_RESIZE 0x5609 /* set kernel's idea of screensize */
> #define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */
>
> So far we are not aware of syzbot reports caused by setting non-zero value
> to v_vlin parameter. But given that it is possible that nobody is using
> VT_RESIZEX, we can try removing support for v_clin and v_vlin parameters.

Debian code search doesn't show any users, and that's usually a good
indication of what userspace ioctls for old things like this, are being
used for.

So this makes sense to me, I'll queue it up, thanks!

greg k-h

Martin Hostettler

unread,
Sep 28, 2020, 1:59:59 PM9/28/20
to Tetsuo Handa, gre...@linuxfoundation.org, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
On Sun, Sep 27, 2020 at 08:46:30PM +0900, Tetsuo Handa wrote:
> VT_RESIZEX was introduced in Linux 1.3.3, but it is unclear that what
> comes to the "+ more" part, and I couldn't find a user of VT_RESIZEX.
>

It seems this is/was used by "svgatextmode" which seems to be at
http://www.ibiblio.org/pub/Linux/utils/console/

Not sure if that kind of software still has a chance to work nowadays.

- Martin Hostettler

Tetsuo Handa

unread,
Sep 28, 2020, 9:13:04 PM9/28/20
to Martin Hostettler, gre...@linuxfoundation.org, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
Thanks for the information.

It seems that v.v_vlin = curr_textmode->VDisplay / (MOFLG_ISSET(curr_textmode, ATTR_DOUBLESCAN) ? 2 : 1)
and v.v_clin = curr_textmode->FontHeight . Thus, v.v_clin is font's height and seems to be non-zero.
But according to https://bugs.gentoo.org/19485 , people are using kernel framebuffer instead.

---------- SVGATextMode-1.10/SVGATextMode.c ----------

/*
* Resize the screen. Still needs LOTS more error checking to avoid dropping out in the middle, leaving
* the user with a garbled screen.
*
* sresize will be TRUE when resizing tty's should be forced (due to the 2nd attempt do_VT_RESIZE will do
* when not enough memory is free).
*
*/

/*
* ALWAYS do a VT_RESIZE, even if we already did a VT_RESIZEX on a 1.3.3 or higher kernel,
* until those kernel programmers make this unambiguous
*/

if (do_VT_RESIZE(curr_textmode->cols, curr_textmode->rows, resize1x1)) sresize=TRUE;

if (check_kernel_version(1,3,3, "VT_RESIZEX"))
{
/*
* VDisplay must de divided by 2 for DoubleScan modes,
* or VT_RESIZEX will fail -- until someone fixes the kernel
* so it understands about doublescan modes.
*/
if (do_VT_RESIZEX(curr_textmode->cols,
curr_textmode->rows,
curr_textmode->VDisplay / (MOFLG_ISSET(curr_textmode, ATTR_DOUBLESCAN) ? 2 : 1),
curr_textmode->FontHeight,
curr_textmode->HDisplay/8*curr_textmode->FontWidth,
curr_textmode->FontWidth, resize1x1)) sresize=TRUE;
}

---------- SVGATextMode-1.10/ttyresize.c ----------

/*
* if VT_RESIZEX not supported (i.e. when compiling on < 1.3.3 kernels), define it.
* this is just te keep the compiler happy
*/

#ifndef VT_RESIZEX
# define VT_RESIZEX 0x560A
typedef struct vt_consize {
ushort v_rows; ushort v_cols; ushort v_vlin; ushort v_clin; ushort v_vcol; ushort v_ccol;
} vt_consize;
#endif


int do_VT_RESIZEX(int cols, int rows, int vlin, int clin, int vcol, int ccol, int allow1x1)
{
struct vt_consize my_vt_size; /* passes the new screen size on to the kernel */
struct vt_consize dummy_vt_size = { 1 , 1 , 1 , 1 , 1 , 1 };
int ram_needed = cols * rows * 2 * MAX_NR_CONSOLES;

my_vt_size.v_rows = rows;
my_vt_size.v_cols = cols;
my_vt_size.v_vlin = vlin;
my_vt_size.v_clin = clin;
my_vt_size.v_vcol = vcol;
my_vt_size.v_ccol = ccol;

PDEBUG(("VT_RESIZEX(cols=%d,rows=%d,vlin=%d,clin=%d,vcol=%d,ccol=%d)\n",cols, rows, vlin, clin, vcol, ccol));

return(generic_VT_RESIZE(&my_vt_size, &dummy_vt_size, allow1x1, ram_needed, VT_RESIZEX, "VT_RESIZEX"));
}

Martin Hostettler

unread,
Sep 29, 2020, 6:52:05 AM9/29/20
to Tetsuo Handa, Martin Hostettler, gre...@linuxfoundation.org, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
On Tue, Sep 29, 2020 at 10:12:46AM +0900, Tetsuo Handa wrote:
> On 2020/09/29 2:59, Martin Hostettler wrote:
> > On Sun, Sep 27, 2020 at 08:46:30PM +0900, Tetsuo Handa wrote:
> >> VT_RESIZEX was introduced in Linux 1.3.3, but it is unclear that what
> >> comes to the "+ more" part, and I couldn't find a user of VT_RESIZEX.
> >>
> >
> > It seems this is/was used by "svgatextmode" which seems to be at
> > http://www.ibiblio.org/pub/Linux/utils/console/
> >
> > Not sure if that kind of software still has a chance to work nowadays.
> >
>
> Thanks for the information.
>
> It seems that v.v_vlin = curr_textmode->VDisplay / (MOFLG_ISSET(curr_textmode, ATTR_DOUBLESCAN) ? 2 : 1)
> and v.v_clin = curr_textmode->FontHeight . Thus, v.v_clin is font's height and seems to be non-zero.
> But according to https://bugs.gentoo.org/19485 , people are using kernel framebuffer instead.
>

Yes, this seems to be from pre framebuffer times.

Back in the days "svga" was the wording you got for "pokes svga card
hardware registers from userspace drivers". And textmode means font
rendering is done via (fixed function in those times) hardware scanout
engine. Of course having only to update 2 bytes per character was a huge
saving early on. Likely this is also before vesa VBE was reliable.

So i guess the point where this all starts going wrong allowing the X parts
of the api to be combined with FB based rendering at all? Sounds the only
user didn't use that combination and so it was never tested?

Then again, this all relates to hardware from 20 years ago...

- Martin Hostettler

Daniel Vetter

unread,
Sep 29, 2020, 12:57:02 PM9/29/20
to Martin Hostettler, Tetsuo Handa, gre...@linuxfoundation.org, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, daniel...@ffwll.ch, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
Imo userspace modesetting should be burned down anywhere we can. We've
gotten away with this in drivers/gpu by just seamlessly transitioning to
kernel drivers.

Since th only userspace we've found seems to be able to cope if this ioctl
doesn't do anything, my vote goes towards ripping it out completely and
doing nothing in there. Only question is whether we should error or fail
with a silent success: Former is safer, latter can avoid a few regression
reports since the userspace tools keep "working", and usually people don't
notice for stuff this old. It worked in drivers/gpu :-)

Cheers, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

Greg KH

unread,
Sep 29, 2020, 1:10:36 PM9/29/20
to Martin Hostettler, Tetsuo Handa, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
This patch just ignores the ioctl and keeps on going, so userspace
"shouldn't" notice it :)

And it's in linux-next now, so all should be good.

thanks,

greg k-h

Maciej W. Rozycki

unread,
Apr 11, 2021, 5:43:51 PM4/11/21
to Greg KH, Martin Hostettler, Tetsuo Handa, jiri...@kernel.org, Peilin Ye, syzbot, b.zoln...@samsung.com, del...@gmx.de, syzkall...@googlegroups.com, Linus Torvalds, dri-...@lists.freedesktop.org, linux...@vger.kernel.org, linux-...@vger.kernel.org, George Kennedy
So it does trigger with vgacon and my old server, which I have started
experimenting with and for a start I have switched to a new kernel for an
unrelated purpose (now that I have relieved it from all its usual tasks
except for the last remaining one for which I haven't got the required
user software ported to the new system yet):

"struct vt_consize"->v_vlin is ignored. Please report if you need this.
"struct vt_consize"->v_clin is ignored. Please report if you need this.

It continues using svgatextmode with its glass (CRT) VT to set my usual
80x37 text mode (720x576 pixel resolution) by manipulating the VGA clock
chip and the CRT controller appropriately for a nice refresh rate of 85Hz:

Chipset = `TVGA8900', Textmode clock = 44.90 MHz, 80x37 chars, CharCell = 9x16. Refresh = 52.51kHz/84.7Hz.

Indeed the piece of software became less usable around Y2K as clock chip
support stopped being added to svgatextmode for new video adapters, but
with the advent of LCD technology and its disregard for the refresh rate
previously driven by the pixel clock the program got its second life and I
have used it ever since with its plain VGA driver by just manipulating the
CRTC for the resolution required:

Chipset = `VGA', Textmode clock = 28.32 MHz, 80x37 chars, CharCell = 9x16. Refresh = 31.47kHz/49.0Hz.

(that would still work with a standard 800x600 SVGA CRT, but the refresh
rate would make anyone's eyes cry soon; with LCD it's just awesome, and
the VGA emulation of the actual graphics adapter turns it at the video
output into a 1600x1200 picture at the horizontal and vertical rates of
75KHz and 60Hz respectively, making the text produced on LCD outstanding
while showing about the right amount of it).

But I'm currently ~160km/100mi away from the server I have triggered this
message with, so I cannot easily check what's going on with its VT. And I
can't fiddle with my production laptop (ThinkPad P51) I have with me that
I also use svgatextmode with so much as to reboot it with a new kernel
(plain Debian 4.19.16-1~bpo9+1 still here).

So what's the supposed impact of this change that prompted the inclusion
of the messages? I can port svgatextmode (it's my own compilation anyway)
if that is required for it to continue working correctly, but I need to
understand the circumstances here. I have failed to find a satisfactory
alternative solution to vgacon and svgatextmode; the main showstopper is
the IBM's hardware trick for a 9x16 character cell that I rely on.

Maciej

Linus Torvalds

unread,
Apr 11, 2021, 6:15:54 PM4/11/21
to Maciej W. Rozycki, Greg KH, Martin Hostettler, Tetsuo Handa, Jiri Slaby, Peilin Ye, syzbot, Bartlomiej Zolnierkiewicz, Helge Deller, syzkaller-bugs, dri-devel, Linux Fbdev development list, Linux Kernel Mailing List, George Kennedy
On Sun, Apr 11, 2021 at 2:43 PM Maciej W. Rozycki <ma...@orcam.me.uk> wrote:
>
> So it does trigger with vgacon and my old server, which I have started
> experimenting with and for a start I have switched to a new kernel for an
> unrelated purpose (now that I have relieved it from all its usual tasks
> except for the last remaining one for which I haven't got the required
> user software ported to the new system yet):
>
> "struct vt_consize"->v_vlin is ignored. Please report if you need this.
> "struct vt_consize"->v_clin is ignored. Please report if you need this.

Note that it's entirely possible that things continue to work well
despite this warning. It's unclear to me from your email if you
actually see any difference (and apparently you're not able to see it
right now due to not being close to the machine).

The fact that v_vlin/v_clin are ignored doesn't necessarily mean that
they are different from what they were before, so the warning may be a
non-issue.

> It continues using svgatextmode with its glass (CRT) VT to set my usual
> 80x37 text mode (720x576 pixel resolution) by manipulating the VGA clock
> chip and the CRT controller appropriately for a nice refresh rate of 85Hz:
>
> Chipset = `TVGA8900', Textmode clock = 44.90 MHz, 80x37 chars, CharCell = 9x16. Refresh = 52.51kHz/84.7Hz.

That doesn't seem necessarily wrong to me.

> So what's the supposed impact of this change that prompted the inclusion
> of the messages?

There _may_ be no impact at all apart from the messages.

The code _used_ to set the scan lines (v_vlin) and font height
(v_clin) from those numbers if they were non-zero, and now it just
ignores them and warns instead.

The code now just sets the font height from the actual font size when
the font is set. Which is honestly the only thing that ever made
sense. Trying to set it with v_clin is ignored, but it's entirely
possible - maybe even likely - that your user of VT_RESIZEX sets it to
the same values it already has.

Exactly because setting a font line number to anything else than the
font size isn't exactly sensible.

But if your screen looks different than it used to, that is obviously
interesting and says something actually changed (outside of the
message itself).

Linus

Daniel Vetter

unread,
Apr 12, 2021, 3:01:46 AM4/12/21
to Linus Torvalds, Maciej W. Rozycki, syzbot, Linux Fbdev development list, Bartlomiej Zolnierkiewicz, Tetsuo Handa, Greg KH, Helge Deller, syzkaller-bugs, Linux Kernel Mailing List, dri-devel, Martin Hostettler, George Kennedy, Jiri Slaby, Peilin Ye
On Mon, Apr 12, 2021 at 12:15 AM Linus Torvalds
<torv...@linux-foundation.org> wrote:
>
> On Sun, Apr 11, 2021 at 2:43 PM Maciej W. Rozycki <ma...@orcam.me.uk> wrote:
> >
> > So it does trigger with vgacon and my old server, which I have started
> > experimenting with and for a start I have switched to a new kernel for an
> > unrelated purpose (now that I have relieved it from all its usual tasks
> > except for the last remaining one for which I haven't got the required
> > user software ported to the new system yet):
> >
> > "struct vt_consize"->v_vlin is ignored. Please report if you need this.
> > "struct vt_consize"->v_clin is ignored. Please report if you need this.
>
> Note that it's entirely possible that things continue to work well
> despite this warning. It's unclear to me from your email if you
> actually see any difference (and apparently you're not able to see it
> right now due to not being close to the machine).

Original search didn't turn up any users of VT_RESIZEX, this is the
first. And looking at the source code I think we could outright remove
support for VT_RESIZEX (but make it silent) and everything should keep
working:

/*
* ALWAYS do a VT_RESIZE, even if we already did a VT_RESIZEX
on a 1.3.3 or higher kernel,
* until those kernel programmers make this unambiguous
*/

if (do_VT_RESIZE(curr_textmode->cols, curr_textmode->rows,
resize1x1)) sresize=TRUE;

if (check_kernel_version(1,3,3, "VT_RESIZEX"))
{
/*
* VDisplay must de divided by 2 for DoubleScan modes,
* or VT_RESIZEX will fail -- until someone fixes the kernel
* so it understands about doublescan modes.
*/
if (do_VT_RESIZEX(curr_textmode->cols,
curr_textmode->rows,
curr_textmode->VDisplay /
(MOFLG_ISSET(curr_textmode, ATTR_DOUBLESCAN) ? 2 : 1),
curr_textmode->FontHeight,
curr_textmode->HDisplay/8*curr_textmode->FontWidth,
curr_textmode->FontWidth, resize1x1)) sresize=TRUE;
}

The functions are just straightforward wrappers. There's also no cvs
repo, changelog or old releases before 2000 that would shed some light
on why this code even exists.

I think we can just tune down the pr_info_once to pr_debug and done.
Maybe a comment about where the single user we're aware of is.
-Daniel
> _______________________________________________
> dri-devel mailing list
> dri-...@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

Maciej W. Rozycki

unread,
Apr 12, 2021, 9:30:18 AM4/12/21
to Daniel Vetter, Linus Torvalds, syzbot, Linux Fbdev development list, Bartlomiej Zolnierkiewicz, Tetsuo Handa, Greg KH, Helge Deller, syzkaller-bugs, Linux Kernel Mailing List, dri-devel, Martin Hostettler, George Kennedy, Jiri Slaby, Peilin Ye
I did some archaeology then, using a local copy of the linux-mips.org
Linux tree that has historic information imported from the old oss.sgi.com
MIPS/Linux CVS repo. According to that the ioctl was added with or
shortly before 2.1.14:

commit beb116954b9b7f3bb56412b2494b562f02b864b1
Author: Ralf Baechle <ra...@linux-mips.org>
Date: Tue Jan 7 02:33:00 1997 +0000

Import of Linux/MIPS 2.1.14

and, importantly, it was used to set some parameters:

if ( vlin )
video_scan_lines = vlin;
if ( clin )
video_font_height = clin;

used by `con_adjust_height' in drivers/char/vga.c: `video_scan_lines' to
set the vertical display limit (so that it is a whole multiple of the new
font height) and `video_font_height' to set the cursor scan lines in the
CRTC. The function was used by the PIO_FONTX and PIO_FONTRESET VT ioctls
at that point.

That code was moved to `vgacon_adjust_height' in drivers/video/vgacon.c
and then drivers/video/console/vgacon.c. The code is still there, serving
the KDFONTOP ioctl.

With:

commit 9736a3546de7b6a2b16ad93539e4b3ac72b385bb
Author: Ralf Baechle <ra...@linux-mips.org>
Date: Thu Jun 5 10:06:35 2003 +0000

Merge with Linux 2.5.66.

the parameters were moved into `struct vc_data':

if (vlin)
- video_scan_lines = vlin;
+ vc->vc_scan_lines = vlin;
if (clin)
- video_font_height = clin;
+ vc->vc_font.height = clin;

and this piece of code to set them only removed with the change discussed
here.

So without even looking at the VT, which I'll surely get to eventually, I
conclude this change regresses font resizing (KD_FONT_OP_SET) once a new
resolution has been set with svgatextmode. I think this change needs to
be reverted, especially as the problematic PIO_FONT ioctl referred has
been since removed with commit ff2047fb755d ("vt: drop old FONT ioctls").

Maciej
Reply all
Reply to author
Forward
0 new messages