1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * CVE-2017-2636
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Check for race between flush_tx_queue() and n_hdlc_send_frames(). Kernel
10f08c3bdfSopenharmony_ci * crash fixed in:
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci *  commit 82f2341c94d270421f383641b7cd670e474db56b
13f08c3bdfSopenharmony_ci *  Author: Alexander Popov <alex.popov@linux.com>
14f08c3bdfSopenharmony_ci *  Date:   Tue Feb 28 19:54:40 2017 +0300
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci *  tty: n_hdlc: get rid of racy n_hdlc.tbuf
17f08c3bdfSopenharmony_ci */
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci#define _GNU_SOURCE
20f08c3bdfSopenharmony_ci#include <termios.h>
21f08c3bdfSopenharmony_ci#include "lapi/ioctl.h"
22f08c3bdfSopenharmony_ci#include "lapi/tty.h"
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_ci#include "tst_test.h"
25f08c3bdfSopenharmony_ci#include "tst_fuzzy_sync.h"
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_ci#define BUF_SIZE 1
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_cistatic struct tst_fzsync_pair fzsync_pair;
30f08c3bdfSopenharmony_cistatic volatile int ptmx = -1;
31f08c3bdfSopenharmony_cistatic char buf[BUF_SIZE];
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic void setup(void)
34f08c3bdfSopenharmony_ci{
35f08c3bdfSopenharmony_ci	fzsync_pair.exec_loops = 100000;
36f08c3bdfSopenharmony_ci	tst_fzsync_pair_init(&fzsync_pair);
37f08c3bdfSopenharmony_ci}
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cistatic void *thread_run(void *arg)
40f08c3bdfSopenharmony_ci{
41f08c3bdfSopenharmony_ci	while (tst_fzsync_run_b(&fzsync_pair)) {
42f08c3bdfSopenharmony_ci		tst_fzsync_start_race_b(&fzsync_pair);
43f08c3bdfSopenharmony_ci		ioctl(ptmx, TCFLSH, TCIOFLUSH);
44f08c3bdfSopenharmony_ci		tst_fzsync_end_race_b(&fzsync_pair);
45f08c3bdfSopenharmony_ci	}
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci	return arg;
48f08c3bdfSopenharmony_ci}
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_cistatic void run(void)
51f08c3bdfSopenharmony_ci{
52f08c3bdfSopenharmony_ci	int ldisc = N_HDLC;
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	while (tst_fzsync_run_a(&fzsync_pair)) {
57f08c3bdfSopenharmony_ci		ptmx = SAFE_OPEN("/dev/ptmx", O_RDWR);
58f08c3bdfSopenharmony_ci		TEST(ioctl(ptmx, TIOCSETD, &ldisc));
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci		if (TST_RET == -1 && TST_ERR == EINVAL) {
61f08c3bdfSopenharmony_ci			tst_brk(TCONF, "HDLC line discipline not available");
62f08c3bdfSopenharmony_ci		} else if (TST_RET == -1) {
63f08c3bdfSopenharmony_ci			tst_brk(TBROK | TTERRNO, "Cannot set line discipline");
64f08c3bdfSopenharmony_ci		} else if (TST_RET != 0) {
65f08c3bdfSopenharmony_ci			tst_brk(TBROK | TTERRNO,
66f08c3bdfSopenharmony_ci				"Invalid ioctl() return value %ld", TST_RET);
67f08c3bdfSopenharmony_ci		}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci		SAFE_IOCTL(ptmx, TCXONC, TCOOFF);
70f08c3bdfSopenharmony_ci		SAFE_WRITE(SAFE_WRITE_ALL, ptmx, buf, BUF_SIZE);
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci		tst_fzsync_start_race_a(&fzsync_pair);
73f08c3bdfSopenharmony_ci		ioctl(ptmx, TCXONC, TCOON);
74f08c3bdfSopenharmony_ci		tst_fzsync_end_race_a(&fzsync_pair);
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci		SAFE_CLOSE(ptmx);
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci		if (tst_taint_check()) {
79f08c3bdfSopenharmony_ci			tst_res(TFAIL, "Kernel is vulnerable");
80f08c3bdfSopenharmony_ci			return;
81f08c3bdfSopenharmony_ci		}
82f08c3bdfSopenharmony_ci	}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	tst_res(TPASS, "Nothing bad happened, probably");
85f08c3bdfSopenharmony_ci}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_cistatic void cleanup(void)
88f08c3bdfSopenharmony_ci{
89f08c3bdfSopenharmony_ci	tst_fzsync_pair_cleanup(&fzsync_pair);
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	if (ptmx >= 0)
92f08c3bdfSopenharmony_ci		SAFE_CLOSE(ptmx);
93f08c3bdfSopenharmony_ci}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic struct tst_test test = {
96f08c3bdfSopenharmony_ci	.test_all = run,
97f08c3bdfSopenharmony_ci	.setup = setup,
98f08c3bdfSopenharmony_ci	.cleanup = cleanup,
99f08c3bdfSopenharmony_ci	.taint_check = TST_TAINT_W | TST_TAINT_D,
100f08c3bdfSopenharmony_ci	.max_runtime = 150,
101f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
102f08c3bdfSopenharmony_ci		{"linux-git", "82f2341c94d27"},
103f08c3bdfSopenharmony_ci		{"CVE", "2017-2636"},
104f08c3bdfSopenharmony_ci		{}
105f08c3bdfSopenharmony_ci	}
106f08c3bdfSopenharmony_ci};
107