• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 SUSE
4  *
5  * Test based on Syzkaller reproducer:
6  * https://syzkaller.appspot.com/bug?id=680c24ff647dd7241998e19da52e8136d2fd3523
7  *
8  * The SLIP and SLCAN disciplines can have a race between write_wakeup and
9  * close/hangup. This atleast allows the netdev private data (tty->disc_data)
10  * to be set to NULL or possibly freed while a transmit operation is being
11  * added to a workqueue.
12  *
13  * If the race condition exists, then the most likely result of running this
14  * is a null pointer dereference.
15  *
16  * Note that we must set the line discipline to "mouse" first which, for
17  * whatever reason, results in tty_wakeup being called during the close
18  * operation.
19  *
20  * We also test a selection of other line disciplines, but only SLIP and SLCAN
21  * are known to have the problem.
22  *
23  * Fixed by commit 0ace17d568241:
24  * "can, slip: Protect tty->disc_data in write_wakeup and close with RCU"
25  */
26 
27 #define _GNU_SOURCE
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <termios.h>
32 #include "lapi/ioctl.h"
33 
34 #include "tst_test.h"
35 #include "tst_safe_stdio.h"
36 #include "tst_fuzzy_sync.h"
37 
38 struct ldisc_info {
39 	int n;
40 	char *name;
41 };
42 
43 static struct ldisc_info ldiscs[] = {
44 	{2, "mouse"},
45 
46 	{1, "SLIP"},
47 	{3, "Async PPP"},
48 	{5, "AX25/KISS"},
49 	{13, "HDLC"},
50 	{14, "Sync PPP"},
51 	{17, "SLCAN"},
52 	{18, "PPS"},
53 	{20, "CAIF"},
54 	{21, "GSM"}
55 };
56 
57 static struct tst_fzsync_pair fzp;
58 static volatile int ptmx;
59 
hangup(void * unused)60 static void *hangup(void *unused)
61 {
62 	int i;
63 
64 	while (tst_fzsync_run_b(&fzp)) {
65 		tst_fzsync_start_race_b(&fzp);
66 		for (i = 0; i < 10; i++) {
67 			if (tcflush(ptmx, TCIFLUSH))
68 				tst_brk(TBROK | TERRNO, "tcflush(ptmx, TCIFLUSH)");
69 		}
70 		tst_fzsync_end_race_b(&fzp);
71 	}
72 
73 	return unused;
74 }
75 
set_ldisc(int tty,struct ldisc_info * ldisc)76 static int set_ldisc(int tty, struct ldisc_info *ldisc)
77 {
78 	TEST(ioctl(tty, TIOCSETD, &ldisc->n));
79 
80 	if (!TST_RET)
81 		return 0;
82 
83 	if (TST_ERR == EINVAL) {
84 		tst_res(TCONF | TTERRNO,
85 			"You don't appear to have the %s TTY line discipline",
86 			ldisc->name);
87 	} else {
88 		tst_res(TFAIL | TTERRNO,
89 			"Failed to set the %s line discipline", ldisc->name);
90 	}
91 
92 	return 1;
93 }
94 
do_test(unsigned int n)95 static void do_test(unsigned int n)
96 {
97 	int pts;
98 	char pts_path[PATH_MAX];
99 	struct ldisc_info *ldisc = &ldiscs[n + 1];
100 
101 	tst_res(TINFO, "Creating PTY with %s line discipline", ldisc->name);
102 
103 	tst_fzsync_pair_reset(&fzp, hangup);
104 	while (tst_fzsync_run_a(&fzp)) {
105 		ptmx = SAFE_OPEN("/dev/ptmx", O_RDONLY);
106 		if (grantpt(ptmx))
107 			tst_brk(TBROK | TERRNO, "grantpt(ptmx)");
108 		if (unlockpt(ptmx))
109 			tst_brk(TBROK | TERRNO, "unlockpt(ptmx)");
110 		if (ptsname_r(ptmx, pts_path, sizeof(pts_path)))
111 			tst_brk(TBROK | TERRNO, "ptsname_r(ptmx, ...)");
112 		pts = SAFE_OPEN(pts_path, O_RDONLY);
113 
114 		if (set_ldisc(pts, &ldiscs[0]))
115 			tst_brk(TCONF, "Need to set mouse discipline first");
116 		if (set_ldisc(pts, ldisc))
117 			return;
118 
119 		tst_fzsync_start_race_a(&fzp);
120 		ioctl(pts, TIOCVHANGUP);
121 		tst_fzsync_end_race_a(&fzp);
122 
123 		SAFE_CLOSE(pts);
124 		SAFE_CLOSE(ptmx);
125 	}
126 
127 	tst_res(TPASS, "Did not crash with %s TTY discipline", ldisc->name);
128 }
129 
setup(void)130 static void setup(void)
131 {
132 	fzp.min_samples = 20;
133 	fzp.exec_time_p = 0.1;
134 
135 	tst_fzsync_pair_init(&fzp);
136 }
137 
cleanup(void)138 static void cleanup(void)
139 {
140 	tst_fzsync_pair_cleanup(&fzp);
141 }
142 
143 static struct tst_test test = {
144 	.test = do_test,
145 	.tcnt = 9,
146 	.setup = setup,
147 	.cleanup = cleanup,
148 	.needs_root = 1,
149 	.tags = (const struct tst_tag[]) {
150 		{"linux-git", "0ace17d568241"},
151 		{}
152 	}
153 };
154