1 /* $OpenBSD: sigio_common.c,v 1.1 2020/09/16 14:02:23 mpi Exp $ */
2
3 /*
4 * Copyright (c) 2018 Visa Hankala
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/ioctl.h>
20 #include <sys/limits.h>
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <pwd.h>
25 #include <signal.h>
26 #include <unistd.h>
27
28 #include "common.h"
29
30 static char buf[1024];
31
32 int
test_common_badpgid(int fd)33 test_common_badpgid(int fd)
34 {
35 int pgid;
36
37 /* ID of non-existent process */
38 pgid = 1000000;
39 errno = 0;
40 assert(fcntl(fd, F_SETOWN, pgid) == -1);
41 assert(errno == ESRCH);
42 errno = 0;
43 assert(ioctl(fd, FIOSETOWN, &pgid) == -1);
44 assert(errno == ESRCH);
45
46 /* ID of non-existent process group */
47 pgid = -1000000;
48 errno = 0;
49 assert(fcntl(fd, F_SETOWN, pgid) == -1);
50 assert(errno == ESRCH);
51 errno = 0;
52 assert(ioctl(fd, FIOSETOWN, &pgid) == -1);
53 assert(errno == ESRCH);
54
55 return 0;
56 }
57
58 int
test_common_badsession(int fd)59 test_common_badsession(int fd)
60 {
61 int arg, sfd;
62 pid_t pid, ppid;
63
64 /* Ensure this process has its own process group. */
65 assert(setpgid(0, 0) == 0);
66
67 ppid = getpid();
68 if (test_fork(&pid, &sfd) == PARENT) {
69 test_barrier(sfd);
70 } else {
71 assert(setsid() != -1);
72 errno = 0;
73 assert(fcntl(fd, F_SETOWN, ppid) == -1);
74 assert(errno == EPERM);
75 errno = 0;
76 assert(fcntl(fd, F_SETOWN, -ppid) == -1);
77 assert(errno == EPERM);
78 arg = ppid;
79 errno = 0;
80 assert(ioctl(fd, FIOSETOWN, &arg) == -1);
81 assert(errno == EPERM);
82 arg = -ppid;
83 errno = 0;
84 assert(ioctl(fd, FIOSETOWN, &arg) == -1);
85 assert(errno == EPERM);
86 test_barrier(sfd);
87 }
88 return test_wait(pid, sfd);
89 }
90
91 /*
92 * Test that signal is not delivered if there is a privilege mismatch.
93 */
94 int
test_common_cansigio(int * fds)95 test_common_cansigio(int *fds)
96 {
97 struct passwd *pw;
98 int flags, sfd;
99 pid_t pid, ppid;
100
101 assert((pw = getpwnam(SIGIO_REGRESS_USER)) != NULL);
102 assert(pw->pw_uid != getuid());
103
104 flags = fcntl(fds[0], F_GETFL);
105 assert(fcntl(fds[0], F_SETFL, flags | O_ASYNC) == 0);
106
107 ppid = getpid();
108 if (test_fork(&pid, &sfd) == PARENT) {
109 /* Privilege mismatch prevents signal sending. */
110 reject_signal(SIGIO);
111 test_barrier(sfd);
112 test_barrier(sfd);
113 reject_signal(SIGIO);
114 assert(read(fds[0], buf, 1) == 1);
115
116 test_barrier(sfd);
117 assert(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == 0);
118
119 /* Privileges allow signal sending. */
120 reject_signal(SIGIO);
121 test_barrier(sfd);
122 test_barrier(sfd);
123 expect_signal(SIGIO);
124 assert(read(fds[0], buf, 1) == 1);
125 } else {
126 assert(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == 0);
127 assert(fcntl(fds[0], F_SETOWN, ppid) == 0);
128
129 test_barrier(sfd);
130 assert(write(fds[1], buf, 1) == 1);
131 test_barrier(sfd);
132
133 test_barrier(sfd);
134
135 test_barrier(sfd);
136 assert(write(fds[1], buf, 1) == 1);
137 test_barrier(sfd);
138 }
139 return test_wait(pid, sfd);
140 }
141
142 /*
143 * Test that fcntl(fd, F_GETOWN) and ioctl(fd, FIOGETOWN, &arg) reflect
144 * successful fcntl(fd, F_SETOWN, arg) and ioctl(fd, FIOSETOWN, &arg).
145 */
146 int
test_common_getown(int fd)147 test_common_getown(int fd)
148 {
149 int pgid;
150
151 assert(fcntl(fd, F_GETOWN) == 0);
152
153 pgid = getpid();
154 assert(fcntl(fd, F_SETOWN, pgid) == 0);
155 assert(fcntl(fd, F_GETOWN) == pgid);
156
157 pgid = -getpgrp();
158 assert(fcntl(fd, F_SETOWN, pgid) == 0);
159 assert(fcntl(fd, F_GETOWN) == pgid);
160
161 assert(fcntl(fd, F_SETOWN, 0) == 0);
162 assert(fcntl(fd, F_GETOWN) == 0);
163
164 pgid = INT_MIN;
165 assert(ioctl(fd, FIOGETOWN, &pgid) == 0);
166 assert(pgid == 0);
167
168 pgid = getpid();
169 assert(ioctl(fd, FIOSETOWN, &pgid) == 0);
170 pgid = INT_MIN;
171 assert(ioctl(fd, FIOGETOWN, &pgid) == 0);
172 assert(pgid == getpid());
173
174 pgid = -getpgrp();
175 assert(ioctl(fd, FIOSETOWN, &pgid) == 0);
176 pgid = INT_MIN;
177 assert(ioctl(fd, FIOGETOWN, &pgid) == 0);
178 assert(pgid == -getpgrp());
179
180 pgid = 0;
181 assert(ioctl(fd, FIOSETOWN, &pgid) == 0);
182 pgid = INT_MIN;
183 assert(ioctl(fd, FIOGETOWN, &pgid) == 0);
184 assert(pgid == 0);
185
186 return 0;
187 }
188
189 /*
190 * Test that SIGIO gets triggered when data becomes available for reading.
191 */
192 int
test_common_read(int * fds)193 test_common_read(int *fds)
194 {
195 int flags, sfd;
196 pid_t pid;
197
198 flags = fcntl(fds[0], F_GETFL);
199 assert(fcntl(fds[0], F_SETFL, flags | O_ASYNC) == 0);
200
201 assert(fcntl(fds[0], F_SETOWN, getpid()) == 0);
202
203 if (test_fork(&pid, &sfd) == PARENT) {
204 reject_signal(SIGIO);
205 test_barrier(sfd);
206 test_barrier(sfd);
207 expect_signal(SIGIO);
208 assert(read(fds[0], buf, 1) == 1);
209 } else {
210 test_barrier(sfd);
211 assert(write(fds[1], buf, 1) == 1);
212 test_barrier(sfd);
213 }
214 return test_wait(pid, sfd);
215 }
216
217 /*
218 * Test that SIGIO gets triggered when buffer space becomes available
219 * for writing.
220 */
221 int
test_common_write(int * fds)222 test_common_write(int *fds)
223 {
224 ssize_t n;
225 int flags, sfd;
226 pid_t pid;
227
228 flags = fcntl(fds[0], F_GETFL);
229 assert(fcntl(fds[0], F_SETFL, flags | O_ASYNC | O_NONBLOCK) == 0);
230 flags = fcntl(fds[1], F_GETFL);
231 assert(fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == 0);
232
233 assert(fcntl(fds[0], F_SETOWN, getpid()) == 0);
234
235 if (test_fork(&pid, &sfd) == PARENT) {
236 while ((n = write(fds[0], buf, sizeof(buf))) > 0)
237 continue;
238 assert(n == -1);
239 assert(errno == EWOULDBLOCK);
240 reject_signal(SIGIO);
241
242 test_barrier(sfd);
243 test_barrier(sfd);
244 expect_signal(SIGIO);
245 assert(write(fds[0], buf, 1) == 1);
246 } else {
247 test_barrier(sfd);
248 while ((n = read(fds[1], buf, sizeof(buf))) > 0)
249 continue;
250 assert(n == -1);
251 assert(errno == EWOULDBLOCK);
252 test_barrier(sfd);
253 }
254 return test_wait(pid, sfd);
255 }
256