• Sergei Trofimovich's avatar
    tty/vt: fix write/write race in ioctl(KDSKBSENT) handler · 46ca3f73
    Sergei Trofimovich authored
    The bug manifests as an attempt to access deallocated memory:
    
        BUG: unable to handle kernel paging request at ffff9c8735448000
        #PF error: [PROT] [WRITE]
        PGD 288a05067 P4D 288a05067 PUD 288a07067 PMD 7f60c2063 PTE 80000007f5448161
        Oops: 0003 [#1] PREEMPT SMP
        CPU: 6 PID: 388 Comm: loadkeys Tainted: G         C        5.0.0-rc6-00153-g5ded5871 #91
        Hardware name: Gigabyte Technology Co., Ltd. To be filled by O.E.M./H77M-D3H, BIOS F12 11/14/2013
        RIP: 0010:__memmove+0x81/0x1a0
        Code: 4c 89 4f 10 4c 89 47 18 48 8d 7f 20 73 d4 48 83 c2 20 e9 a2 00 00 00 66 90 48 89 d1 4c 8b 5c 16 f8 4c 8d 54 17 f8 48 c1 e9 03 <f3> 48 a5 4d 89 1a e9 0c 01 00 00 0f 1f 40 00 48 89 d1 4c 8b 1e 49
        RSP: 0018:ffffa1b9002d7d08 EFLAGS: 00010203
        RAX: ffff9c873541af43 RBX: ffff9c873541af43 RCX: 00000c6f105cd6bf
        RDX: 0000637882e986b6 RSI: ffff9c8735447ffb RDI: ffff9c8735447ffb
        RBP: ffff9c8739cd3800 R08: ffff9c873b802f00 R09: 00000000fffff73b
        R10: ffffffffb82b35f1 R11: 00505b1b004d5b1b R12: 0000000000000000
        R13: ffff9c873541af3d R14: 000000000000000b R15: 000000000000000c
        FS:  00007f450c390580(0000) GS:ffff9c873f180000(0000) knlGS:0000000000000000
        CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
        CR2: ffff9c8735448000 CR3: 00000007e213c002 CR4: 00000000000606e0
        Call Trace:
         vt_do_kdgkb_ioctl+0x34d/0x440
         vt_ioctl+0xba3/0x1190
         ? __bpf_prog_run32+0x39/0x60
         ? mem_cgroup_commit_charge+0x7b/0x4e0
         tty_ioctl+0x23f/0x920
         ? preempt_count_sub+0x98/0xe0
         ? __seccomp_filter+0x67/0x600
         do_vfs_ioctl+0xa2/0x6a0
         ? syscall_trace_enter+0x192/0x2d0
         ksys_ioctl+0x3a/0x70
         __x64_sys_ioctl+0x16/0x20
         do_syscall_64+0x54/0xe0
         entry_SYSCALL_64_after_hwframe+0x49/0xbe
    
    The bug manifests on systemd systems with multiple vtcon devices:
      # cat /sys/devices/virtual/vtconsole/vtcon0/name
      (S) dummy device
      # cat /sys/devices/virtual/vtconsole/vtcon1/name
      (M) frame buffer device
    
    There systemd runs 'loadkeys' tool in tapallel for each vtcon
    instance. This causes two parallel ioctl(KDSKBSENT) calls to
    race into adding the same entry into 'func_table' array at:
    
        drivers/tty/vt/keyboard.c:vt_do_kdgkb_ioctl()
    
    The function has no locking around writes to 'func_table'.
    
    The simplest reproducer is to have initrams with the following
    init on a 8-CPU machine x86_64:
    
        #!/bin/sh
    
        loadkeys -q windowkeys ru4 &
        loadkeys -q windowkeys ru4 &
        loadkeys -q windowkeys ru4 &
        loadkeys -q windowkeys ru4 &
    
        loadkeys -q windowkeys ru4 &
        loadkeys -q windowkeys ru4 &
        loadkeys -q windowkeys ru4 &
        loadkeys -q windowkeys ru4 &
        wait
    
    The change adds lock on write path only. Reads are still racy.
    
    CC: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    CC: Jiri Slaby <jslaby@suse.com>
    Link: https://lkml.org/lkml/2019/2/17/256Signed-off-by: default avatarSergei Trofimovich <slyfox@gentoo.org>
    Cc: stable <stable@vger.kernel.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    46ca3f73
keyboard.c 53.2 KB