1/*-
2 * Copyright (c) 2012 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/param.h>
34#include <sys/capsicum.h>
35#include <sys/ioctl.h>
36#include <sys/procdesc.h>
37#include <sys/socket.h>
38#include <sys/wait.h>
39
40#include <err.h>
41#include <errno.h>
42#include <limits.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <unistd.h>
46
47#include "misc.h"
48
49static void
50ioctl_tests_0(int fd)
51{
52	unsigned long cmds[2];
53
54	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
55
56	CHECK(fcntl(fd, F_GETFD) == 0);
57	CHECK(ioctl(fd, FIOCLEX) == 0);
58	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
59	CHECK(ioctl(fd, FIONCLEX) == 0);
60	CHECK(fcntl(fd, F_GETFD) == 0);
61
62	cmds[0] = FIOCLEX;
63	cmds[1] = FIONCLEX;
64	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
65	cmds[0] = cmds[1] = 0;
66	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
67	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
68	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
69	cmds[0] = FIOCLEX;
70	cmds[1] = FIONCLEX;
71	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
72	cmds[0] = cmds[1] = 0;
73	CHECK(cap_ioctls_get(fd, cmds, 1) == nitems(cmds));
74	CHECK(cmds[0] == FIOCLEX || cmds[0] == FIONCLEX);
75	CHECK(cmds[1] == 0);
76
77	CHECK(fcntl(fd, F_GETFD) == 0);
78	CHECK(ioctl(fd, FIOCLEX) == 0);
79	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
80	CHECK(ioctl(fd, FIONCLEX) == 0);
81	CHECK(fcntl(fd, F_GETFD) == 0);
82
83	cmds[0] = FIOCLEX;
84	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
85	cmds[0] = cmds[1] = 0;
86	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
87	CHECK(cmds[0] == FIOCLEX);
88	cmds[0] = FIOCLEX;
89	cmds[1] = FIONCLEX;
90	errno = 0;
91	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
92	CHECK(errno == ENOTCAPABLE);
93	cmds[0] = cmds[1] = 0;
94	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
95	CHECK(cmds[0] == FIOCLEX);
96
97	CHECK(fcntl(fd, F_GETFD) == 0);
98	CHECK(ioctl(fd, FIOCLEX) == 0);
99	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
100	errno = 0;
101	CHECK(ioctl(fd, FIONCLEX) == -1);
102	CHECK(errno == ENOTCAPABLE);
103	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
104	CHECK(fcntl(fd, F_SETFD, 0) == 0);
105	CHECK(fcntl(fd, F_GETFD) == 0);
106
107	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
108	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
109	cmds[0] = FIOCLEX;
110	errno = 0;
111	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
112	CHECK(errno == ENOTCAPABLE);
113	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
114
115	CHECK(fcntl(fd, F_GETFD) == 0);
116	errno = 0;
117	CHECK(ioctl(fd, FIOCLEX) == -1);
118	CHECK(errno == ENOTCAPABLE);
119	CHECK(fcntl(fd, F_GETFD) == 0);
120	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
121	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
122	errno = 0;
123	CHECK(ioctl(fd, FIONCLEX) == -1);
124	CHECK(errno == ENOTCAPABLE);
125	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
126	CHECK(fcntl(fd, F_SETFD, 0) == 0);
127	CHECK(fcntl(fd, F_GETFD) == 0);
128}
129
130static void
131ioctl_tests_1(int fd)
132{
133	unsigned long cmds[2];
134
135	cmds[0] = FIOCLEX;
136	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
137	cmds[0] = cmds[1] = 0;
138	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
139	CHECK(cmds[0] == FIOCLEX);
140	CHECK(cmds[1] == 0);
141
142	CHECK(cap_rights_limit(fd, CAP_ALL & ~CAP_IOCTL) == 0);
143	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
144
145	cmds[0] = FIOCLEX;
146	cmds[1] = FIONCLEX;
147	errno = 0;
148	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
149	CHECK(errno == ENOTCAPABLE);
150	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
151	cmds[0] = FIOCLEX;
152	errno = 0;
153	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
154	CHECK(errno == ENOTCAPABLE);
155	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
156
157	CHECK(fcntl(fd, F_GETFD) == 0);
158	errno = 0;
159	CHECK(ioctl(fd, FIOCLEX) == -1);
160	CHECK(errno == ENOTCAPABLE);
161	CHECK(fcntl(fd, F_GETFD) == 0);
162	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
163	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
164	errno = 0;
165	CHECK(ioctl(fd, FIONCLEX) == -1);
166	CHECK(errno == ENOTCAPABLE);
167	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
168	CHECK(fcntl(fd, F_SETFD, 0) == 0);
169	CHECK(fcntl(fd, F_GETFD) == 0);
170}
171
172static void
173ioctl_tests_2(int fd)
174{
175	unsigned long cmds[2];
176
177	CHECK(cap_rights_limit(fd, CAP_ALL & ~CAP_IOCTL) == 0);
178	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
179
180	cmds[0] = FIOCLEX;
181	cmds[1] = FIONCLEX;
182	errno = 0;
183	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
184	CHECK(errno == ENOTCAPABLE);
185	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
186	cmds[0] = FIOCLEX;
187	errno = 0;
188	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
189	CHECK(errno == ENOTCAPABLE);
190	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
191
192	CHECK(fcntl(fd, F_GETFD) == 0);
193	errno = 0;
194	CHECK(ioctl(fd, FIOCLEX) == -1);
195	CHECK(errno == ENOTCAPABLE);
196	CHECK(fcntl(fd, F_GETFD) == 0);
197	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
198	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
199	errno = 0;
200	CHECK(ioctl(fd, FIONCLEX) == -1);
201	CHECK(errno == ENOTCAPABLE);
202	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
203	CHECK(fcntl(fd, F_SETFD, 0) == 0);
204	CHECK(fcntl(fd, F_GETFD) == 0);
205}
206
207static void
208ioctl_tests_send_0(int sock)
209{
210	unsigned long cmds[2];
211	int fd;
212
213	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
214	CHECK(descriptor_send(sock, fd) == 0);
215	CHECK(close(fd) == 0);
216
217	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
218	cmds[0] = FIOCLEX;
219	cmds[1] = FIONCLEX;
220	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
221	CHECK(descriptor_send(sock, fd) == 0);
222	CHECK(close(fd) == 0);
223
224	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
225	cmds[0] = FIOCLEX;
226	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
227	CHECK(descriptor_send(sock, fd) == 0);
228	CHECK(close(fd) == 0);
229
230	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
231	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
232	CHECK(descriptor_send(sock, fd) == 0);
233	CHECK(close(fd) == 0);
234}
235
236static void
237ioctl_tests_recv_0(int sock)
238{
239	unsigned long cmds[2];
240	int fd;
241
242	CHECK(descriptor_recv(sock, &fd) == 0);
243
244	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
245
246	CHECK(fcntl(fd, F_GETFD) == 0);
247	CHECK(ioctl(fd, FIOCLEX) == 0);
248	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
249	CHECK(ioctl(fd, FIONCLEX) == 0);
250	CHECK(fcntl(fd, F_GETFD) == 0);
251
252	CHECK(close(fd) == 0);
253
254	CHECK(descriptor_recv(sock, &fd) == 0);
255
256	cmds[0] = cmds[1] = 0;
257	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
258	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
259	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
260
261	CHECK(fcntl(fd, F_GETFD) == 0);
262	CHECK(ioctl(fd, FIOCLEX) == 0);
263	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
264	CHECK(ioctl(fd, FIONCLEX) == 0);
265	CHECK(fcntl(fd, F_GETFD) == 0);
266
267	CHECK(close(fd) == 0);
268
269	CHECK(descriptor_recv(sock, &fd) == 0);
270
271	cmds[0] = cmds[1] = 0;
272	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
273	CHECK(cmds[0] == FIOCLEX);
274
275	CHECK(fcntl(fd, F_GETFD) == 0);
276	CHECK(ioctl(fd, FIOCLEX) == 0);
277	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
278	errno = 0;
279	CHECK(ioctl(fd, FIONCLEX) == -1);
280	CHECK(errno == ENOTCAPABLE);
281	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
282	CHECK(fcntl(fd, F_SETFD, 0) == 0);
283	CHECK(fcntl(fd, F_GETFD) == 0);
284
285	CHECK(close(fd) == 0);
286
287	CHECK(descriptor_recv(sock, &fd) == 0);
288
289	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
290
291	CHECK(fcntl(fd, F_GETFD) == 0);
292	errno = 0;
293	CHECK(ioctl(fd, FIOCLEX) == -1);
294	CHECK(errno == ENOTCAPABLE);
295	CHECK(fcntl(fd, F_GETFD) == 0);
296	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
297	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
298	errno = 0;
299	CHECK(ioctl(fd, FIONCLEX) == -1);
300	CHECK(errno == ENOTCAPABLE);
301	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
302	CHECK(fcntl(fd, F_SETFD, 0) == 0);
303	CHECK(fcntl(fd, F_GETFD) == 0);
304
305	CHECK(close(fd) == 0);
306}
307
308int
309main(void)
310{
311	int fd, pfd, sp[2];
312	pid_t pid;
313
314	printf("1..607\n");
315
316	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
317	ioctl_tests_0(fd);
318	CHECK(close(fd) == 0);
319
320	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
321	ioctl_tests_1(fd);
322	CHECK(close(fd) == 0);
323
324	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
325	ioctl_tests_2(fd);
326	CHECK(close(fd) == 0);
327
328	/* Child inherits descriptor and operates on it first. */
329	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
330	pid = fork();
331	switch (pid) {
332	case -1:
333		err(1, "fork() failed");
334	case 0:
335		ioctl_tests_0(fd);
336		CHECK(close(fd) == 0);
337		exit(0);
338	default:
339		if (waitpid(pid, NULL, 0) == -1)
340			err(1, "waitpid() failed");
341		ioctl_tests_0(fd);
342	}
343	CHECK(close(fd) == 0);
344
345	/* Child inherits descriptor, but operates on it after parent. */
346	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
347	pid = fork();
348	switch (pid) {
349	case -1:
350		err(1, "fork() failed");
351	case 0:
352		sleep(1);
353		ioctl_tests_0(fd);
354		CHECK(close(fd) == 0);
355		exit(0);
356	default:
357		ioctl_tests_0(fd);
358		if (waitpid(pid, NULL, 0) == -1)
359			err(1, "waitpid() failed");
360	}
361	CHECK(close(fd) == 0);
362
363	/* Child inherits descriptor and operates on it first. */
364	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
365	pid = pdfork(&pfd, 0);
366	switch (pid) {
367	case -1:
368		err(1, "pdfork() failed");
369	case 0:
370		ioctl_tests_1(fd);
371		exit(0);
372	default:
373		if (pdwait(pfd) == -1)
374			err(1, "pdwait() failed");
375		close(pfd);
376		ioctl_tests_1(fd);
377	}
378	CHECK(close(fd) == 0);
379
380	/* Child inherits descriptor, but operates on it after parent. */
381	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
382	pid = pdfork(&pfd, 0);
383	switch (pid) {
384	case -1:
385		err(1, "pdfork() failed");
386	case 0:
387		sleep(1);
388		ioctl_tests_1(fd);
389		exit(0);
390	default:
391		ioctl_tests_1(fd);
392		if (pdwait(pfd) == -1)
393			err(1, "pdwait() failed");
394		close(pfd);
395	}
396	CHECK(close(fd) == 0);
397
398	/* Child inherits descriptor and operates on it first. */
399	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
400	pid = fork();
401	switch (pid) {
402	case -1:
403		err(1, "fork() failed");
404	case 0:
405		ioctl_tests_2(fd);
406		exit(0);
407	default:
408		if (waitpid(pid, NULL, 0) == -1)
409			err(1, "waitpid() failed");
410		ioctl_tests_2(fd);
411	}
412	CHECK(close(fd) == 0);
413
414	/* Child inherits descriptor, but operates on it after parent. */
415	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
416	pid = fork();
417	switch (pid) {
418	case -1:
419		err(1, "fork() failed");
420	case 0:
421		sleep(1);
422		ioctl_tests_2(fd);
423		exit(0);
424	default:
425		ioctl_tests_2(fd);
426		if (waitpid(pid, NULL, 0) == -1)
427			err(1, "waitpid() failed");
428	}
429	CHECK(close(fd) == 0);
430
431	/* Send descriptors from parent to child. */
432	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
433	CHECK((pid = fork()) >= 0);
434	if (pid == 0) {
435		CHECK(close(sp[0]) == 0);
436		ioctl_tests_recv_0(sp[1]);
437		CHECK(close(sp[1]) == 0);
438		exit(0);
439	} else {
440		CHECK(close(sp[1]) == 0);
441		ioctl_tests_send_0(sp[0]);
442		CHECK(waitpid(pid, NULL, 0) == pid);
443		CHECK(close(sp[0]) == 0);
444	}
445
446	/* Send descriptors from child to parent. */
447	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
448	CHECK((pid = fork()) >= 0);
449	if (pid == 0) {
450		CHECK(close(sp[0]) == 0);
451		ioctl_tests_send_0(sp[1]);
452		CHECK(close(sp[1]) == 0);
453		exit(0);
454	} else {
455		CHECK(close(sp[1]) == 0);
456		ioctl_tests_recv_0(sp[0]);
457		CHECK(waitpid(pid, NULL, 0) == pid);
458		CHECK(close(sp[0]) == 0);
459	}
460
461	exit(0);
462}
463