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