1247606Spjd/*-
2247606Spjd * Copyright (c) 2012 The FreeBSD Foundation
3247606Spjd * All rights reserved.
4247606Spjd *
5247606Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6247606Spjd * the FreeBSD Foundation.
7247606Spjd *
8247606Spjd * Redistribution and use in source and binary forms, with or without
9247606Spjd * modification, are permitted provided that the following conditions
10247606Spjd * are met:
11247606Spjd * 1. Redistributions of source code must retain the above copyright
12247606Spjd *    notice, this list of conditions and the following disclaimer.
13247606Spjd * 2. Redistributions in binary form must reproduce the above copyright
14247606Spjd *    notice, this list of conditions and the following disclaimer in the
15247606Spjd *    documentation and/or other materials provided with the distribution.
16247606Spjd *
17247606Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18247606Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19247606Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20247606Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21247606Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22247606Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23247606Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24247606Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25247606Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26247606Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27247606Spjd * SUCH DAMAGE.
28247606Spjd */
29247606Spjd
30247606Spjd#include <sys/cdefs.h>
31247606Spjd__FBSDID("$FreeBSD: releng/11.0/tools/regression/capsicum/syscalls/cap_ioctls_limit.c 263234 2014-03-16 11:04:44Z rwatson $");
32247606Spjd
33247606Spjd#include <sys/param.h>
34263234Srwatson#include <sys/capsicum.h>
35247606Spjd#include <sys/ioctl.h>
36247606Spjd#include <sys/procdesc.h>
37247606Spjd#include <sys/socket.h>
38247606Spjd#include <sys/wait.h>
39247606Spjd
40247606Spjd#include <err.h>
41247606Spjd#include <errno.h>
42247606Spjd#include <limits.h>
43247606Spjd#include <stdio.h>
44247606Spjd#include <stdlib.h>
45247606Spjd#include <unistd.h>
46247606Spjd
47247606Spjd#include "misc.h"
48247606Spjd
49247606Spjdstatic void
50247606Spjdioctl_tests_0(int fd)
51247606Spjd{
52247606Spjd	unsigned long cmds[2];
53247606Spjd
54247676Spjd	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
55247606Spjd
56247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
57247606Spjd	CHECK(ioctl(fd, FIOCLEX) == 0);
58247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
59247606Spjd	CHECK(ioctl(fd, FIONCLEX) == 0);
60247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
61247606Spjd
62247606Spjd	cmds[0] = FIOCLEX;
63247606Spjd	cmds[1] = FIONCLEX;
64247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
65247606Spjd	cmds[0] = cmds[1] = 0;
66247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
67247606Spjd	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
68247606Spjd	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
69247606Spjd	cmds[0] = FIOCLEX;
70247606Spjd	cmds[1] = FIONCLEX;
71247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
72247606Spjd	cmds[0] = cmds[1] = 0;
73247606Spjd	CHECK(cap_ioctls_get(fd, cmds, 1) == nitems(cmds));
74247606Spjd	CHECK(cmds[0] == FIOCLEX || cmds[0] == FIONCLEX);
75247606Spjd	CHECK(cmds[1] == 0);
76247606Spjd
77247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
78247606Spjd	CHECK(ioctl(fd, FIOCLEX) == 0);
79247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
80247606Spjd	CHECK(ioctl(fd, FIONCLEX) == 0);
81247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
82247606Spjd
83247606Spjd	cmds[0] = FIOCLEX;
84247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
85247606Spjd	cmds[0] = cmds[1] = 0;
86247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
87247606Spjd	CHECK(cmds[0] == FIOCLEX);
88247606Spjd	cmds[0] = FIOCLEX;
89247606Spjd	cmds[1] = FIONCLEX;
90247606Spjd	errno = 0;
91247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
92247606Spjd	CHECK(errno == ENOTCAPABLE);
93247606Spjd	cmds[0] = cmds[1] = 0;
94247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
95247606Spjd	CHECK(cmds[0] == FIOCLEX);
96247606Spjd
97247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
98247606Spjd	CHECK(ioctl(fd, FIOCLEX) == 0);
99247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
100247606Spjd	errno = 0;
101247606Spjd	CHECK(ioctl(fd, FIONCLEX) == -1);
102247606Spjd	CHECK(errno == ENOTCAPABLE);
103247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
104247606Spjd	CHECK(fcntl(fd, F_SETFD, 0) == 0);
105247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
106247606Spjd
107247606Spjd	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
108247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
109247606Spjd	cmds[0] = FIOCLEX;
110247606Spjd	errno = 0;
111247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
112247606Spjd	CHECK(errno == ENOTCAPABLE);
113247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
114247606Spjd
115247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
116247606Spjd	errno = 0;
117247606Spjd	CHECK(ioctl(fd, FIOCLEX) == -1);
118247606Spjd	CHECK(errno == ENOTCAPABLE);
119247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
120247606Spjd	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
121247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
122247606Spjd	errno = 0;
123247606Spjd	CHECK(ioctl(fd, FIONCLEX) == -1);
124247606Spjd	CHECK(errno == ENOTCAPABLE);
125247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
126247606Spjd	CHECK(fcntl(fd, F_SETFD, 0) == 0);
127247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
128247606Spjd}
129247606Spjd
130247606Spjdstatic void
131247606Spjdioctl_tests_1(int fd)
132247606Spjd{
133247606Spjd	unsigned long cmds[2];
134247606Spjd
135247606Spjd	cmds[0] = FIOCLEX;
136247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
137247606Spjd	cmds[0] = cmds[1] = 0;
138247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
139247606Spjd	CHECK(cmds[0] == FIOCLEX);
140247606Spjd	CHECK(cmds[1] == 0);
141247606Spjd
142247606Spjd	CHECK(cap_rights_limit(fd, CAP_ALL & ~CAP_IOCTL) == 0);
143247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
144247606Spjd
145247606Spjd	cmds[0] = FIOCLEX;
146247606Spjd	cmds[1] = FIONCLEX;
147247606Spjd	errno = 0;
148247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
149247606Spjd	CHECK(errno == ENOTCAPABLE);
150247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
151247606Spjd	cmds[0] = FIOCLEX;
152247606Spjd	errno = 0;
153247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
154247606Spjd	CHECK(errno == ENOTCAPABLE);
155247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
156247606Spjd
157247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
158247606Spjd	errno = 0;
159247606Spjd	CHECK(ioctl(fd, FIOCLEX) == -1);
160247606Spjd	CHECK(errno == ENOTCAPABLE);
161247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
162247606Spjd	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
163247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
164247606Spjd	errno = 0;
165247606Spjd	CHECK(ioctl(fd, FIONCLEX) == -1);
166247606Spjd	CHECK(errno == ENOTCAPABLE);
167247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
168247606Spjd	CHECK(fcntl(fd, F_SETFD, 0) == 0);
169247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
170247606Spjd}
171247606Spjd
172247606Spjdstatic void
173247606Spjdioctl_tests_2(int fd)
174247606Spjd{
175247606Spjd	unsigned long cmds[2];
176247606Spjd
177247606Spjd	CHECK(cap_rights_limit(fd, CAP_ALL & ~CAP_IOCTL) == 0);
178247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
179247606Spjd
180247606Spjd	cmds[0] = FIOCLEX;
181247606Spjd	cmds[1] = FIONCLEX;
182247606Spjd	errno = 0;
183247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
184247606Spjd	CHECK(errno == ENOTCAPABLE);
185247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
186247606Spjd	cmds[0] = FIOCLEX;
187247606Spjd	errno = 0;
188247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
189247606Spjd	CHECK(errno == ENOTCAPABLE);
190247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
191247606Spjd
192247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
193247606Spjd	errno = 0;
194247606Spjd	CHECK(ioctl(fd, FIOCLEX) == -1);
195247606Spjd	CHECK(errno == ENOTCAPABLE);
196247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
197247606Spjd	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
198247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
199247606Spjd	errno = 0;
200247606Spjd	CHECK(ioctl(fd, FIONCLEX) == -1);
201247606Spjd	CHECK(errno == ENOTCAPABLE);
202247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
203247606Spjd	CHECK(fcntl(fd, F_SETFD, 0) == 0);
204247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
205247606Spjd}
206247606Spjd
207247606Spjdstatic void
208247606Spjdioctl_tests_send_0(int sock)
209247606Spjd{
210247606Spjd	unsigned long cmds[2];
211247606Spjd	int fd;
212247606Spjd
213247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
214247606Spjd	CHECK(descriptor_send(sock, fd) == 0);
215247606Spjd	CHECK(close(fd) == 0);
216247606Spjd
217247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
218247606Spjd	cmds[0] = FIOCLEX;
219247606Spjd	cmds[1] = FIONCLEX;
220247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
221247606Spjd	CHECK(descriptor_send(sock, fd) == 0);
222247606Spjd	CHECK(close(fd) == 0);
223247606Spjd
224247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
225247606Spjd	cmds[0] = FIOCLEX;
226247606Spjd	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
227247606Spjd	CHECK(descriptor_send(sock, fd) == 0);
228247606Spjd	CHECK(close(fd) == 0);
229247606Spjd
230247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
231247606Spjd	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
232247606Spjd	CHECK(descriptor_send(sock, fd) == 0);
233247606Spjd	CHECK(close(fd) == 0);
234247606Spjd}
235247606Spjd
236247606Spjdstatic void
237247606Spjdioctl_tests_recv_0(int sock)
238247606Spjd{
239247606Spjd	unsigned long cmds[2];
240247606Spjd	int fd;
241247606Spjd
242247606Spjd	CHECK(descriptor_recv(sock, &fd) == 0);
243247606Spjd
244247676Spjd	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
245247606Spjd
246247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
247247606Spjd	CHECK(ioctl(fd, FIOCLEX) == 0);
248247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
249247606Spjd	CHECK(ioctl(fd, FIONCLEX) == 0);
250247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
251247606Spjd
252247606Spjd	CHECK(close(fd) == 0);
253247606Spjd
254247606Spjd	CHECK(descriptor_recv(sock, &fd) == 0);
255247606Spjd
256247606Spjd	cmds[0] = cmds[1] = 0;
257247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
258247606Spjd	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
259247606Spjd	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
260247606Spjd
261247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
262247606Spjd	CHECK(ioctl(fd, FIOCLEX) == 0);
263247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
264247606Spjd	CHECK(ioctl(fd, FIONCLEX) == 0);
265247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
266247606Spjd
267247606Spjd	CHECK(close(fd) == 0);
268247606Spjd
269247606Spjd	CHECK(descriptor_recv(sock, &fd) == 0);
270247606Spjd
271247606Spjd	cmds[0] = cmds[1] = 0;
272247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
273247606Spjd	CHECK(cmds[0] == FIOCLEX);
274247606Spjd
275247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
276247606Spjd	CHECK(ioctl(fd, FIOCLEX) == 0);
277247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
278247606Spjd	errno = 0;
279247606Spjd	CHECK(ioctl(fd, FIONCLEX) == -1);
280247606Spjd	CHECK(errno == ENOTCAPABLE);
281247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
282247606Spjd	CHECK(fcntl(fd, F_SETFD, 0) == 0);
283247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
284247606Spjd
285247606Spjd	CHECK(close(fd) == 0);
286247606Spjd
287247606Spjd	CHECK(descriptor_recv(sock, &fd) == 0);
288247606Spjd
289247606Spjd	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
290247606Spjd
291247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
292247606Spjd	errno = 0;
293247606Spjd	CHECK(ioctl(fd, FIOCLEX) == -1);
294247606Spjd	CHECK(errno == ENOTCAPABLE);
295247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
296247606Spjd	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
297247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
298247606Spjd	errno = 0;
299247606Spjd	CHECK(ioctl(fd, FIONCLEX) == -1);
300247606Spjd	CHECK(errno == ENOTCAPABLE);
301247606Spjd	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
302247606Spjd	CHECK(fcntl(fd, F_SETFD, 0) == 0);
303247606Spjd	CHECK(fcntl(fd, F_GETFD) == 0);
304247606Spjd
305247606Spjd	CHECK(close(fd) == 0);
306247606Spjd}
307247606Spjd
308247606Spjdint
309247606Spjdmain(void)
310247606Spjd{
311247606Spjd	int fd, pfd, sp[2];
312247606Spjd	pid_t pid;
313247606Spjd
314247606Spjd	printf("1..607\n");
315247606Spjd
316247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
317247606Spjd	ioctl_tests_0(fd);
318247606Spjd	CHECK(close(fd) == 0);
319247606Spjd
320247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
321247606Spjd	ioctl_tests_1(fd);
322247606Spjd	CHECK(close(fd) == 0);
323247606Spjd
324247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
325247606Spjd	ioctl_tests_2(fd);
326247606Spjd	CHECK(close(fd) == 0);
327247606Spjd
328247606Spjd	/* Child inherits descriptor and operates on it first. */
329247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
330247606Spjd	pid = fork();
331247606Spjd	switch (pid) {
332247606Spjd	case -1:
333247606Spjd		err(1, "fork() failed");
334247606Spjd	case 0:
335247606Spjd		ioctl_tests_0(fd);
336247606Spjd		CHECK(close(fd) == 0);
337247606Spjd		exit(0);
338247606Spjd	default:
339247606Spjd		if (waitpid(pid, NULL, 0) == -1)
340247606Spjd			err(1, "waitpid() failed");
341247606Spjd		ioctl_tests_0(fd);
342247606Spjd	}
343247606Spjd	CHECK(close(fd) == 0);
344247606Spjd
345247606Spjd	/* Child inherits descriptor, but operates on it after parent. */
346247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
347247606Spjd	pid = fork();
348247606Spjd	switch (pid) {
349247606Spjd	case -1:
350247606Spjd		err(1, "fork() failed");
351247606Spjd	case 0:
352247606Spjd		sleep(1);
353247606Spjd		ioctl_tests_0(fd);
354247606Spjd		CHECK(close(fd) == 0);
355247606Spjd		exit(0);
356247606Spjd	default:
357247606Spjd		ioctl_tests_0(fd);
358247606Spjd		if (waitpid(pid, NULL, 0) == -1)
359247606Spjd			err(1, "waitpid() failed");
360247606Spjd	}
361247606Spjd	CHECK(close(fd) == 0);
362247606Spjd
363247606Spjd	/* Child inherits descriptor and operates on it first. */
364247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
365247606Spjd	pid = pdfork(&pfd, 0);
366247606Spjd	switch (pid) {
367247606Spjd	case -1:
368247606Spjd		err(1, "pdfork() failed");
369247606Spjd	case 0:
370247606Spjd		ioctl_tests_1(fd);
371247606Spjd		exit(0);
372247606Spjd	default:
373247606Spjd		if (pdwait(pfd) == -1)
374247606Spjd			err(1, "pdwait() failed");
375247606Spjd		close(pfd);
376247606Spjd		ioctl_tests_1(fd);
377247606Spjd	}
378247606Spjd	CHECK(close(fd) == 0);
379247606Spjd
380247606Spjd	/* Child inherits descriptor, but operates on it after parent. */
381247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
382247606Spjd	pid = pdfork(&pfd, 0);
383247606Spjd	switch (pid) {
384247606Spjd	case -1:
385247606Spjd		err(1, "pdfork() failed");
386247606Spjd	case 0:
387247606Spjd		sleep(1);
388247606Spjd		ioctl_tests_1(fd);
389247606Spjd		exit(0);
390247606Spjd	default:
391247606Spjd		ioctl_tests_1(fd);
392247606Spjd		if (pdwait(pfd) == -1)
393247606Spjd			err(1, "pdwait() failed");
394247606Spjd		close(pfd);
395247606Spjd	}
396247606Spjd	CHECK(close(fd) == 0);
397247606Spjd
398247606Spjd	/* Child inherits descriptor and operates on it first. */
399247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
400247606Spjd	pid = fork();
401247606Spjd	switch (pid) {
402247606Spjd	case -1:
403247606Spjd		err(1, "fork() failed");
404247606Spjd	case 0:
405247606Spjd		ioctl_tests_2(fd);
406247606Spjd		exit(0);
407247606Spjd	default:
408247606Spjd		if (waitpid(pid, NULL, 0) == -1)
409247606Spjd			err(1, "waitpid() failed");
410247606Spjd		ioctl_tests_2(fd);
411247606Spjd	}
412247606Spjd	CHECK(close(fd) == 0);
413247606Spjd
414247606Spjd	/* Child inherits descriptor, but operates on it after parent. */
415247606Spjd	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
416247606Spjd	pid = fork();
417247606Spjd	switch (pid) {
418247606Spjd	case -1:
419247606Spjd		err(1, "fork() failed");
420247606Spjd	case 0:
421247606Spjd		sleep(1);
422247606Spjd		ioctl_tests_2(fd);
423247606Spjd		exit(0);
424247606Spjd	default:
425247606Spjd		ioctl_tests_2(fd);
426247606Spjd		if (waitpid(pid, NULL, 0) == -1)
427247606Spjd			err(1, "waitpid() failed");
428247606Spjd	}
429247606Spjd	CHECK(close(fd) == 0);
430247606Spjd
431247606Spjd	/* Send descriptors from parent to child. */
432247606Spjd	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
433247606Spjd	CHECK((pid = fork()) >= 0);
434247606Spjd	if (pid == 0) {
435247606Spjd		CHECK(close(sp[0]) == 0);
436247606Spjd		ioctl_tests_recv_0(sp[1]);
437247606Spjd		CHECK(close(sp[1]) == 0);
438247606Spjd		exit(0);
439247606Spjd	} else {
440247606Spjd		CHECK(close(sp[1]) == 0);
441247606Spjd		ioctl_tests_send_0(sp[0]);
442247606Spjd		CHECK(waitpid(pid, NULL, 0) == pid);
443247606Spjd		CHECK(close(sp[0]) == 0);
444247606Spjd	}
445247606Spjd
446247606Spjd	/* Send descriptors from child to parent. */
447247606Spjd	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
448247606Spjd	CHECK((pid = fork()) >= 0);
449247606Spjd	if (pid == 0) {
450247606Spjd		CHECK(close(sp[0]) == 0);
451247606Spjd		ioctl_tests_send_0(sp[1]);
452247606Spjd		CHECK(close(sp[1]) == 0);
453247606Spjd		exit(0);
454247606Spjd	} else {
455247606Spjd		CHECK(close(sp[1]) == 0);
456247606Spjd		ioctl_tests_recv_0(sp[0]);
457247606Spjd		CHECK(waitpid(pid, NULL, 0) == pid);
458247606Spjd		CHECK(close(sp[0]) == 0);
459247606Spjd	}
460247606Spjd
461247606Spjd	exit(0);
462247606Spjd}
463