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