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