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	cap_rights_t rights;
135
136	cmds[0] = FIOCLEX;
137	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
138	cmds[0] = cmds[1] = 0;
139	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
140	CHECK(cmds[0] == FIOCLEX);
141	CHECK(cmds[1] == 0);
142
143	CAP_ALL(&rights);
144	cap_rights_clear(&rights, CAP_IOCTL);
145
146	CHECK(cap_rights_limit(fd, &rights) == 0);
147	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
148
149	cmds[0] = FIOCLEX;
150	cmds[1] = FIONCLEX;
151	errno = 0;
152	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
153	CHECK(errno == ENOTCAPABLE);
154	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
155	cmds[0] = FIOCLEX;
156	errno = 0;
157	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
158	CHECK(errno == ENOTCAPABLE);
159	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
160
161	CHECK(fcntl(fd, F_GETFD) == 0);
162	errno = 0;
163	CHECK(ioctl(fd, FIOCLEX) == -1);
164	CHECK(errno == ENOTCAPABLE);
165	CHECK(fcntl(fd, F_GETFD) == 0);
166	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
167	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
168	errno = 0;
169	CHECK(ioctl(fd, FIONCLEX) == -1);
170	CHECK(errno == ENOTCAPABLE);
171	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
172	CHECK(fcntl(fd, F_SETFD, 0) == 0);
173	CHECK(fcntl(fd, F_GETFD) == 0);
174}
175
176static void
177ioctl_tests_2(int fd)
178{
179	unsigned long cmds[2];
180	cap_rights_t rights;
181
182	CAP_ALL(&rights);
183	cap_rights_clear(&rights, CAP_IOCTL);
184
185	CHECK(cap_rights_limit(fd, &rights) == 0);
186	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
187
188	cmds[0] = FIOCLEX;
189	cmds[1] = FIONCLEX;
190	errno = 0;
191	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
192	CHECK(errno == ENOTCAPABLE);
193	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
194	cmds[0] = FIOCLEX;
195	errno = 0;
196	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
197	CHECK(errno == ENOTCAPABLE);
198	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
199
200	CHECK(fcntl(fd, F_GETFD) == 0);
201	errno = 0;
202	CHECK(ioctl(fd, FIOCLEX) == -1);
203	CHECK(errno == ENOTCAPABLE);
204	CHECK(fcntl(fd, F_GETFD) == 0);
205	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
206	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
207	errno = 0;
208	CHECK(ioctl(fd, FIONCLEX) == -1);
209	CHECK(errno == ENOTCAPABLE);
210	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
211	CHECK(fcntl(fd, F_SETFD, 0) == 0);
212	CHECK(fcntl(fd, F_GETFD) == 0);
213}
214
215static void
216ioctl_tests_send_0(int sock)
217{
218	unsigned long cmds[2];
219	int fd;
220
221	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
222	CHECK(descriptor_send(sock, fd) == 0);
223	CHECK(close(fd) == 0);
224
225	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
226	cmds[0] = FIOCLEX;
227	cmds[1] = FIONCLEX;
228	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
229	CHECK(descriptor_send(sock, fd) == 0);
230	CHECK(close(fd) == 0);
231
232	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
233	cmds[0] = FIOCLEX;
234	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
235	CHECK(descriptor_send(sock, fd) == 0);
236	CHECK(close(fd) == 0);
237
238	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
239	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
240	CHECK(descriptor_send(sock, fd) == 0);
241	CHECK(close(fd) == 0);
242}
243
244static void
245ioctl_tests_recv_0(int sock)
246{
247	unsigned long cmds[2];
248	int fd;
249
250	CHECK(descriptor_recv(sock, &fd) == 0);
251
252	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
253
254	CHECK(fcntl(fd, F_GETFD) == 0);
255	CHECK(ioctl(fd, FIOCLEX) == 0);
256	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
257	CHECK(ioctl(fd, FIONCLEX) == 0);
258	CHECK(fcntl(fd, F_GETFD) == 0);
259
260	CHECK(close(fd) == 0);
261
262	CHECK(descriptor_recv(sock, &fd) == 0);
263
264	cmds[0] = cmds[1] = 0;
265	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
266	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
267	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
268
269	CHECK(fcntl(fd, F_GETFD) == 0);
270	CHECK(ioctl(fd, FIOCLEX) == 0);
271	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
272	CHECK(ioctl(fd, FIONCLEX) == 0);
273	CHECK(fcntl(fd, F_GETFD) == 0);
274
275	CHECK(close(fd) == 0);
276
277	CHECK(descriptor_recv(sock, &fd) == 0);
278
279	cmds[0] = cmds[1] = 0;
280	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
281	CHECK(cmds[0] == FIOCLEX);
282
283	CHECK(fcntl(fd, F_GETFD) == 0);
284	CHECK(ioctl(fd, FIOCLEX) == 0);
285	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
286	errno = 0;
287	CHECK(ioctl(fd, FIONCLEX) == -1);
288	CHECK(errno == ENOTCAPABLE);
289	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
290	CHECK(fcntl(fd, F_SETFD, 0) == 0);
291	CHECK(fcntl(fd, F_GETFD) == 0);
292
293	CHECK(close(fd) == 0);
294
295	CHECK(descriptor_recv(sock, &fd) == 0);
296
297	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
298
299	CHECK(fcntl(fd, F_GETFD) == 0);
300	errno = 0;
301	CHECK(ioctl(fd, FIOCLEX) == -1);
302	CHECK(errno == ENOTCAPABLE);
303	CHECK(fcntl(fd, F_GETFD) == 0);
304	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
305	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
306	errno = 0;
307	CHECK(ioctl(fd, FIONCLEX) == -1);
308	CHECK(errno == ENOTCAPABLE);
309	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
310	CHECK(fcntl(fd, F_SETFD, 0) == 0);
311	CHECK(fcntl(fd, F_GETFD) == 0);
312
313	CHECK(close(fd) == 0);
314}
315
316int
317main(void)
318{
319	int fd, pfd, sp[2];
320	pid_t pid;
321
322	printf("1..607\n");
323
324	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
325	ioctl_tests_0(fd);
326	CHECK(close(fd) == 0);
327
328	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
329	ioctl_tests_1(fd);
330	CHECK(close(fd) == 0);
331
332	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
333	ioctl_tests_2(fd);
334	CHECK(close(fd) == 0);
335
336	/* Child inherits descriptor and operates on it first. */
337	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
338	pid = fork();
339	switch (pid) {
340	case -1:
341		err(1, "fork() failed");
342	case 0:
343		ioctl_tests_0(fd);
344		CHECK(close(fd) == 0);
345		exit(0);
346	default:
347		if (waitpid(pid, NULL, 0) == -1)
348			err(1, "waitpid() failed");
349		ioctl_tests_0(fd);
350	}
351	CHECK(close(fd) == 0);
352
353	/* Child inherits descriptor, but operates on it after parent. */
354	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
355	pid = fork();
356	switch (pid) {
357	case -1:
358		err(1, "fork() failed");
359	case 0:
360		sleep(1);
361		ioctl_tests_0(fd);
362		CHECK(close(fd) == 0);
363		exit(0);
364	default:
365		ioctl_tests_0(fd);
366		if (waitpid(pid, NULL, 0) == -1)
367			err(1, "waitpid() failed");
368	}
369	CHECK(close(fd) == 0);
370
371	/* Child inherits descriptor and operates on it first. */
372	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
373	pid = pdfork(&pfd, 0);
374	switch (pid) {
375	case -1:
376		err(1, "pdfork() failed");
377	case 0:
378		ioctl_tests_1(fd);
379		exit(0);
380	default:
381		if (pdwait(pfd) == -1)
382			err(1, "pdwait() failed");
383		close(pfd);
384		ioctl_tests_1(fd);
385	}
386	CHECK(close(fd) == 0);
387
388	/* Child inherits descriptor, but operates on it after parent. */
389	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
390	pid = pdfork(&pfd, 0);
391	switch (pid) {
392	case -1:
393		err(1, "pdfork() failed");
394	case 0:
395		sleep(1);
396		ioctl_tests_1(fd);
397		exit(0);
398	default:
399		ioctl_tests_1(fd);
400		if (pdwait(pfd) == -1)
401			err(1, "pdwait() failed");
402		close(pfd);
403	}
404	CHECK(close(fd) == 0);
405
406	/* Child inherits descriptor and operates on it first. */
407	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
408	pid = fork();
409	switch (pid) {
410	case -1:
411		err(1, "fork() failed");
412	case 0:
413		ioctl_tests_2(fd);
414		exit(0);
415	default:
416		if (waitpid(pid, NULL, 0) == -1)
417			err(1, "waitpid() failed");
418		ioctl_tests_2(fd);
419	}
420	CHECK(close(fd) == 0);
421
422	/* Child inherits descriptor, but operates on it after parent. */
423	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
424	pid = fork();
425	switch (pid) {
426	case -1:
427		err(1, "fork() failed");
428	case 0:
429		sleep(1);
430		ioctl_tests_2(fd);
431		exit(0);
432	default:
433		ioctl_tests_2(fd);
434		if (waitpid(pid, NULL, 0) == -1)
435			err(1, "waitpid() failed");
436	}
437	CHECK(close(fd) == 0);
438
439	/* Send descriptors from parent to child. */
440	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
441	CHECK((pid = fork()) >= 0);
442	if (pid == 0) {
443		CHECK(close(sp[0]) == 0);
444		ioctl_tests_recv_0(sp[1]);
445		CHECK(close(sp[1]) == 0);
446		exit(0);
447	} else {
448		CHECK(close(sp[1]) == 0);
449		ioctl_tests_send_0(sp[0]);
450		CHECK(waitpid(pid, NULL, 0) == pid);
451		CHECK(close(sp[0]) == 0);
452	}
453
454	/* Send descriptors from child to parent. */
455	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
456	CHECK((pid = fork()) >= 0);
457	if (pid == 0) {
458		CHECK(close(sp[0]) == 0);
459		ioctl_tests_send_0(sp[1]);
460		CHECK(close(sp[1]) == 0);
461		exit(0);
462	} else {
463		CHECK(close(sp[1]) == 0);
464		ioctl_tests_recv_0(sp[0]);
465		CHECK(waitpid(pid, NULL, 0) == pid);
466		CHECK(close(sp[0]) == 0);
467	}
468
469	exit(0);
470}
471