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