1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2022 xiaoshoukui <xiaoshoukui@ruijie.com.cn> 4 */ 5 6/*\ 7 * [Description] 8 * 9 * The VT_DISALLOCATE ioctl can free a virtual console while VT_RESIZEX ioctl is 10 * still running, causing a use-after-free in vt_ioctl(). Because VT_RESIZEX ioctl 11 * have not make sure vc_cons[i].d is not NULL after grabbing console_lock(). 12 * 13 * Fixed by commit: 14 * 15 * commit 6cd1ed50efd88261298577cd92a14f2768eddeeb 16 * Author: Eric Dumazet <edumazet@google.com> 17 * Date: Mon Feb 10 11:07:21 2020 -0800 18 * 19 * vt: vt_ioctl: fix race in VT_RESIZEX 20 */ 21 22#define _GNU_SOURCE 23 24#include <stdlib.h> 25#include <stdio.h> 26#include <errno.h> 27#include <termios.h> 28#include <linux/vt.h> 29#include "lapi/ioctl.h" 30 31#include "tst_test.h" 32#include "tst_safe_stdio.h" 33#include "tst_fuzzy_sync.h" 34 35#define BUF_SIZE 256 36#define MAX_NR_CONSOLES 63 37 38static char tty_path[BUF_SIZE]; 39static int test_tty_port = 8; 40static int fd = -1; 41static struct tst_fzsync_pair fzp; 42 43static struct vt_consize consize; 44static unsigned short vt_active; 45 46static void *open_close(void *unused) 47{ 48 int i; 49 50 while (tst_fzsync_run_b(&fzp)) { 51 tst_fzsync_start_race_b(&fzp); 52 for (i = test_tty_port; i < MAX_NR_CONSOLES; i++) { 53 ioctl(fd, VT_ACTIVATE, i); 54 ioctl(fd, VT_DISALLOCATE, i); 55 } 56 tst_fzsync_end_race_b(&fzp); 57 } 58 59 return unused; 60} 61 62static void do_test(void) 63{ 64 65 tst_fzsync_pair_reset(&fzp, open_close); 66 67 while (tst_fzsync_run_a(&fzp)) { 68 tst_fzsync_start_race_a(&fzp); 69 ioctl(fd, VT_RESIZEX, &consize); 70 tst_fzsync_end_race_a(&fzp); 71 if (tst_taint_check()) { 72 tst_res(TFAIL, "Kernel is buggy"); 73 break; 74 } 75 } 76 tst_res(TPASS, "Did not crash with VT_RESIZE"); 77} 78 79static void setup(void) 80{ 81 struct vt_stat stat; 82 struct winsize wsize; 83 84 sprintf(tty_path, "/dev/tty%d", test_tty_port); 85 if (access(tty_path, F_OK)) 86 tst_brk(TCONF, "TTY (/dev/tty%d) under test not available in system", test_tty_port); 87 88 fd = SAFE_OPEN(tty_path, O_RDWR); 89 SAFE_IOCTL(fd, VT_GETSTATE, &stat); 90 vt_active = stat.v_active; 91 92 tst_res(TINFO, "Saving active console %i", vt_active); 93 94 SAFE_IOCTL(fd, TIOCGWINSZ, &wsize); 95 consize.v_rows = wsize.ws_row; 96 consize.v_cols = wsize.ws_col; 97 tst_fzsync_pair_init(&fzp); 98} 99 100static void cleanup(void) 101{ 102 tst_fzsync_pair_cleanup(&fzp); 103 104 if (fd >= 0) { 105 tst_res(TINFO, "Restoring active console"); 106 SAFE_IOCTL(fd, VT_ACTIVATE, vt_active); 107 SAFE_CLOSE(fd); 108 } 109} 110 111static struct tst_test test = { 112 .test_all = do_test, 113 .setup = setup, 114 .cleanup = cleanup, 115 .needs_root = 1, 116 .taint_check = TST_TAINT_W | TST_TAINT_D, 117 .max_runtime = 150, 118 .tags = (const struct tst_tag[]) { 119 { "linux-git", "6cd1ed50efd8"}, 120 {} 121 } 122}; 123