xref: /openbsd-src/regress/sys/kern/kqueue/kqueue-regress.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: kqueue-regress.c,v 1.3 2018/08/24 12:46:39 visa Exp $	*/
2 /*
3  *	Written by Anton Lindqvist <anton@openbsd.org> 2018 Public Domain
4  */
5 
6 #include <sys/types.h>
7 #include <sys/event.h>
8 #include <sys/time.h>
9 #include <sys/wait.h>
10 
11 #include <assert.h>
12 #include <err.h>
13 #include <signal.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 
17 #include "main.h"
18 
19 static int do_regress1(void);
20 static int do_regress2(void);
21 static int do_regress3(void);
22 
23 static void make_chain(int);
24 
25 int
26 do_regress(int n)
27 {
28 	switch (n) {
29 	case 1:
30 		return do_regress1();
31 	case 2:
32 		return do_regress2();
33 	case 3:
34 		return do_regress3();
35 	default:
36 		errx(1, "unknown regress test number %d", n);
37 	}
38 }
39 
40 /*
41  * Regression test for NULL-deref in knote_processexit().
42  */
43 static int
44 do_regress1(void)
45 {
46 	struct kevent kev[2];
47 	int kq;
48 
49 	ASS((kq = kqueue()) >= 0,
50 	    warn("kqueue"));
51 
52 	EV_SET(&kev[0], kq, EVFILT_READ, EV_ADD, 0, 0, NULL);
53 	EV_SET(&kev[1], SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
54 	ASS(kevent(kq, kev, 2, NULL, 0, NULL) == 0,
55 	    warn("can't register events on kqueue"));
56 
57 	/* kq intentionally left open */
58 
59 	return 0;
60 }
61 
62 /*
63  * Regression test for use-after-free in kqueue_close().
64  */
65 static int
66 do_regress2(void)
67 {
68 	pid_t pid;
69 	int i, status;
70 
71 	/* Run twice in order to trigger the panic faster, if still present. */
72 	for (i = 0; i < 2; i++) {
73 		pid = fork();
74 		if (pid == -1)
75 			err(1, "fork");
76 
77 		if (pid == 0) {
78 			struct kevent kev[1];
79 			int p0[2], p1[2];
80 			int kq;
81 
82 			if (pipe(p0) == -1)
83 				err(1, "pipe");
84 			if (pipe(p1) == -1)
85 				err(1, "pipe");
86 
87 			kq = kqueue();
88 			if (kq == -1)
89 				err(1, "kqueue");
90 
91 			EV_SET(&kev[0], p0[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
92 			if (kevent(kq, kev, 1, NULL, 0, NULL) == -1)
93 				err(1, "kevent");
94 
95 			EV_SET(&kev[0], p1[1], EVFILT_READ, EV_ADD, 0, 0, NULL);
96 			if (kevent(kq, kev, 1, NULL, 0, NULL) == -1)
97 				err(1, "kevent");
98 
99 			EV_SET(&kev[0], p1[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
100 			if (kevent(kq, kev, 1, NULL, 0, NULL) == -1)
101 				err(1, "kevent");
102 
103 			_exit(0);
104 		}
105 
106 		if (waitpid(pid, &status, 0) == -1)
107 			err(1, "waitpid");
108 		assert(WIFEXITED(status));
109 		assert(WEXITSTATUS(status) == 0);
110 	}
111 
112 	return 0;
113 }
114 
115 /*
116  * Regression test for kernel stack exhaustion.
117  */
118 static int
119 do_regress3(void)
120 {
121 	pid_t pid;
122 	int dir, status;
123 
124 	for (dir = 0; dir < 2; dir++) {
125 		pid = fork();
126 		if (pid == -1)
127 			err(1, "fork");
128 
129 		if (pid == 0) {
130 			make_chain(dir);
131 			_exit(0);
132 		}
133 
134 		if (waitpid(pid, &status, 0) == -1)
135 			err(1, "waitpid");
136 		assert(WIFEXITED(status));
137 		assert(WEXITSTATUS(status) == 0);
138 	}
139 
140 	return 0;
141 }
142 
143 static void
144 make_chain(int dir)
145 {
146 	struct kevent kev[1];
147 	int i, kq, prev;
148 
149 	/*
150 	 * Build a chain of kqueues and leave the files open.
151 	 * If the chain is long enough and properly oriented, a broken kernel
152 	 * can exhaust the stack when this process exits.
153 	 */
154 	for (i = 0, prev = -1; i < 120; i++, prev = kq) {
155 		kq = kqueue();
156 		if (kq == -1)
157 			err(1, "kqueue");
158 		if (prev == -1)
159 			continue;
160 
161 		if (dir == 0) {
162 			EV_SET(&kev[0], prev, EVFILT_READ, EV_ADD, 0, 0, NULL);
163 			if (kevent(kq, kev, 1, NULL, 0, NULL) == -1)
164 				err(1, "kevent");
165 		} else {
166 			EV_SET(&kev[0], kq, EVFILT_READ, EV_ADD, 0, 0, NULL);
167 			if (kevent(prev, kev, 1, NULL, 0, NULL) == -1)
168 				err(1, "kevent");
169 		}
170 	}
171 }
172