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/param.h>
31#include <sys/capsicum.h>
32#include <sys/ioctl.h>
33#include <sys/procdesc.h>
34#include <sys/socket.h>
35#include <sys/wait.h>
36
37#include <err.h>
38#include <errno.h>
39#include <limits.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <unistd.h>
43
44#include "misc.h"
45
46static void
47ioctl_tests_0(int fd)
48{
49	unsigned long cmds[2];
50
51	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
52
53	CHECK(fcntl(fd, F_GETFD) == 0);
54	CHECK(ioctl(fd, FIOCLEX) == 0);
55	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
56	CHECK(ioctl(fd, FIONCLEX) == 0);
57	CHECK(fcntl(fd, F_GETFD) == 0);
58
59	cmds[0] = FIOCLEX;
60	cmds[1] = FIONCLEX;
61	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
62	cmds[0] = cmds[1] = 0;
63	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
64	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
65	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
66	cmds[0] = FIOCLEX;
67	cmds[1] = FIONCLEX;
68	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
69	cmds[0] = cmds[1] = 0;
70	CHECK(cap_ioctls_get(fd, cmds, 1) == nitems(cmds));
71	CHECK(cmds[0] == FIOCLEX || cmds[0] == FIONCLEX);
72	CHECK(cmds[1] == 0);
73
74	CHECK(fcntl(fd, F_GETFD) == 0);
75	CHECK(ioctl(fd, FIOCLEX) == 0);
76	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
77	CHECK(ioctl(fd, FIONCLEX) == 0);
78	CHECK(fcntl(fd, F_GETFD) == 0);
79
80	cmds[0] = FIOCLEX;
81	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
82	cmds[0] = cmds[1] = 0;
83	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
84	CHECK(cmds[0] == FIOCLEX);
85	cmds[0] = FIOCLEX;
86	cmds[1] = FIONCLEX;
87	errno = 0;
88	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
89	CHECK(errno == ENOTCAPABLE);
90	cmds[0] = cmds[1] = 0;
91	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
92	CHECK(cmds[0] == FIOCLEX);
93
94	CHECK(fcntl(fd, F_GETFD) == 0);
95	CHECK(ioctl(fd, FIOCLEX) == 0);
96	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
97	errno = 0;
98	CHECK(ioctl(fd, FIONCLEX) == -1);
99	CHECK(errno == ENOTCAPABLE);
100	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
101	CHECK(fcntl(fd, F_SETFD, 0) == 0);
102	CHECK(fcntl(fd, F_GETFD) == 0);
103
104	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
105	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
106	cmds[0] = FIOCLEX;
107	errno = 0;
108	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
109	CHECK(errno == ENOTCAPABLE);
110	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
111
112	CHECK(fcntl(fd, F_GETFD) == 0);
113	errno = 0;
114	CHECK(ioctl(fd, FIOCLEX) == -1);
115	CHECK(errno == ENOTCAPABLE);
116	CHECK(fcntl(fd, F_GETFD) == 0);
117	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
118	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
119	errno = 0;
120	CHECK(ioctl(fd, FIONCLEX) == -1);
121	CHECK(errno == ENOTCAPABLE);
122	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
123	CHECK(fcntl(fd, F_SETFD, 0) == 0);
124	CHECK(fcntl(fd, F_GETFD) == 0);
125}
126
127static void
128ioctl_tests_1(int fd)
129{
130	unsigned long cmds[2];
131	cap_rights_t rights;
132
133	cmds[0] = FIOCLEX;
134	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
135	cmds[0] = cmds[1] = 0;
136	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
137	CHECK(cmds[0] == FIOCLEX);
138	CHECK(cmds[1] == 0);
139
140	CAP_ALL(&rights);
141	cap_rights_clear(&rights, CAP_IOCTL);
142
143	CHECK(cap_rights_limit(fd, &rights) == 0);
144	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
145
146	cmds[0] = FIOCLEX;
147	cmds[1] = FIONCLEX;
148	errno = 0;
149	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
150	CHECK(errno == ENOTCAPABLE);
151	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
152	cmds[0] = FIOCLEX;
153	errno = 0;
154	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
155	CHECK(errno == ENOTCAPABLE);
156	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
157
158	CHECK(fcntl(fd, F_GETFD) == 0);
159	errno = 0;
160	CHECK(ioctl(fd, FIOCLEX) == -1);
161	CHECK(errno == ENOTCAPABLE);
162	CHECK(fcntl(fd, F_GETFD) == 0);
163	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
164	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
165	errno = 0;
166	CHECK(ioctl(fd, FIONCLEX) == -1);
167	CHECK(errno == ENOTCAPABLE);
168	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
169	CHECK(fcntl(fd, F_SETFD, 0) == 0);
170	CHECK(fcntl(fd, F_GETFD) == 0);
171}
172
173static void
174ioctl_tests_2(int fd)
175{
176	unsigned long cmds[2];
177	cap_rights_t rights;
178
179	CAP_ALL(&rights);
180	cap_rights_clear(&rights, CAP_IOCTL);
181
182	CHECK(cap_rights_limit(fd, &rights) == 0);
183	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
184
185	cmds[0] = FIOCLEX;
186	cmds[1] = FIONCLEX;
187	errno = 0;
188	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);
189	CHECK(errno == ENOTCAPABLE);
190	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
191	cmds[0] = FIOCLEX;
192	errno = 0;
193	CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);
194	CHECK(errno == ENOTCAPABLE);
195	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
196
197	CHECK(fcntl(fd, F_GETFD) == 0);
198	errno = 0;
199	CHECK(ioctl(fd, FIOCLEX) == -1);
200	CHECK(errno == ENOTCAPABLE);
201	CHECK(fcntl(fd, F_GETFD) == 0);
202	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
203	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
204	errno = 0;
205	CHECK(ioctl(fd, FIONCLEX) == -1);
206	CHECK(errno == ENOTCAPABLE);
207	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
208	CHECK(fcntl(fd, F_SETFD, 0) == 0);
209	CHECK(fcntl(fd, F_GETFD) == 0);
210}
211
212static void
213ioctl_tests_send_0(int sock)
214{
215	unsigned long cmds[2];
216	int fd;
217
218	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
219	CHECK(descriptor_send(sock, fd) == 0);
220	CHECK(close(fd) == 0);
221
222	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
223	cmds[0] = FIOCLEX;
224	cmds[1] = FIONCLEX;
225	CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);
226	CHECK(descriptor_send(sock, fd) == 0);
227	CHECK(close(fd) == 0);
228
229	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
230	cmds[0] = FIOCLEX;
231	CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);
232	CHECK(descriptor_send(sock, fd) == 0);
233	CHECK(close(fd) == 0);
234
235	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
236	CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);
237	CHECK(descriptor_send(sock, fd) == 0);
238	CHECK(close(fd) == 0);
239}
240
241static void
242ioctl_tests_recv_0(int sock)
243{
244	unsigned long cmds[2];
245	int fd;
246
247	CHECK(descriptor_recv(sock, &fd) == 0);
248
249	CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);
250
251	CHECK(fcntl(fd, F_GETFD) == 0);
252	CHECK(ioctl(fd, FIOCLEX) == 0);
253	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
254	CHECK(ioctl(fd, FIONCLEX) == 0);
255	CHECK(fcntl(fd, F_GETFD) == 0);
256
257	CHECK(close(fd) == 0);
258
259	CHECK(descriptor_recv(sock, &fd) == 0);
260
261	cmds[0] = cmds[1] = 0;
262	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));
263	CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||
264	    (cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));
265
266	CHECK(fcntl(fd, F_GETFD) == 0);
267	CHECK(ioctl(fd, FIOCLEX) == 0);
268	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
269	CHECK(ioctl(fd, FIONCLEX) == 0);
270	CHECK(fcntl(fd, F_GETFD) == 0);
271
272	CHECK(close(fd) == 0);
273
274	CHECK(descriptor_recv(sock, &fd) == 0);
275
276	cmds[0] = cmds[1] = 0;
277	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);
278	CHECK(cmds[0] == FIOCLEX);
279
280	CHECK(fcntl(fd, F_GETFD) == 0);
281	CHECK(ioctl(fd, FIOCLEX) == 0);
282	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
283	errno = 0;
284	CHECK(ioctl(fd, FIONCLEX) == -1);
285	CHECK(errno == ENOTCAPABLE);
286	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
287	CHECK(fcntl(fd, F_SETFD, 0) == 0);
288	CHECK(fcntl(fd, F_GETFD) == 0);
289
290	CHECK(close(fd) == 0);
291
292	CHECK(descriptor_recv(sock, &fd) == 0);
293
294	CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);
295
296	CHECK(fcntl(fd, F_GETFD) == 0);
297	errno = 0;
298	CHECK(ioctl(fd, FIOCLEX) == -1);
299	CHECK(errno == ENOTCAPABLE);
300	CHECK(fcntl(fd, F_GETFD) == 0);
301	CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);
302	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
303	errno = 0;
304	CHECK(ioctl(fd, FIONCLEX) == -1);
305	CHECK(errno == ENOTCAPABLE);
306	CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);
307	CHECK(fcntl(fd, F_SETFD, 0) == 0);
308	CHECK(fcntl(fd, F_GETFD) == 0);
309
310	CHECK(close(fd) == 0);
311}
312
313int
314main(void)
315{
316	int fd, pfd, sp[2];
317	pid_t pid;
318
319	printf("1..607\n");
320
321	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
322	ioctl_tests_0(fd);
323	CHECK(close(fd) == 0);
324
325	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
326	ioctl_tests_1(fd);
327	CHECK(close(fd) == 0);
328
329	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
330	ioctl_tests_2(fd);
331	CHECK(close(fd) == 0);
332
333	/* Child inherits descriptor and operates on it first. */
334	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
335	pid = fork();
336	switch (pid) {
337	case -1:
338		err(1, "fork() failed");
339	case 0:
340		ioctl_tests_0(fd);
341		CHECK(close(fd) == 0);
342		exit(0);
343	default:
344		if (waitpid(pid, NULL, 0) == -1)
345			err(1, "waitpid() failed");
346		ioctl_tests_0(fd);
347	}
348	CHECK(close(fd) == 0);
349
350	/* Child inherits descriptor, but operates on it after parent. */
351	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
352	pid = fork();
353	switch (pid) {
354	case -1:
355		err(1, "fork() failed");
356	case 0:
357		sleep(1);
358		ioctl_tests_0(fd);
359		CHECK(close(fd) == 0);
360		exit(0);
361	default:
362		ioctl_tests_0(fd);
363		if (waitpid(pid, NULL, 0) == -1)
364			err(1, "waitpid() failed");
365	}
366	CHECK(close(fd) == 0);
367
368	/* Child inherits descriptor and operates on it first. */
369	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
370	pid = pdfork(&pfd, 0);
371	switch (pid) {
372	case -1:
373		err(1, "pdfork() failed");
374	case 0:
375		ioctl_tests_1(fd);
376		exit(0);
377	default:
378		if (pdwait(pfd) == -1)
379			err(1, "pdwait() failed");
380		close(pfd);
381		ioctl_tests_1(fd);
382	}
383	CHECK(close(fd) == 0);
384
385	/* Child inherits descriptor, but operates on it after parent. */
386	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
387	pid = pdfork(&pfd, 0);
388	switch (pid) {
389	case -1:
390		err(1, "pdfork() failed");
391	case 0:
392		sleep(1);
393		ioctl_tests_1(fd);
394		exit(0);
395	default:
396		ioctl_tests_1(fd);
397		if (pdwait(pfd) == -1)
398			err(1, "pdwait() failed");
399		close(pfd);
400	}
401	CHECK(close(fd) == 0);
402
403	/* Child inherits descriptor and operates on it first. */
404	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
405	pid = fork();
406	switch (pid) {
407	case -1:
408		err(1, "fork() failed");
409	case 0:
410		ioctl_tests_2(fd);
411		exit(0);
412	default:
413		if (waitpid(pid, NULL, 0) == -1)
414			err(1, "waitpid() failed");
415		ioctl_tests_2(fd);
416	}
417	CHECK(close(fd) == 0);
418
419	/* Child inherits descriptor, but operates on it after parent. */
420	CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
421	pid = fork();
422	switch (pid) {
423	case -1:
424		err(1, "fork() failed");
425	case 0:
426		sleep(1);
427		ioctl_tests_2(fd);
428		exit(0);
429	default:
430		ioctl_tests_2(fd);
431		if (waitpid(pid, NULL, 0) == -1)
432			err(1, "waitpid() failed");
433	}
434	CHECK(close(fd) == 0);
435
436	/* Send descriptors from parent to child. */
437	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
438	CHECK((pid = fork()) >= 0);
439	if (pid == 0) {
440		CHECK(close(sp[0]) == 0);
441		ioctl_tests_recv_0(sp[1]);
442		CHECK(close(sp[1]) == 0);
443		exit(0);
444	} else {
445		CHECK(close(sp[1]) == 0);
446		ioctl_tests_send_0(sp[0]);
447		CHECK(waitpid(pid, NULL, 0) == pid);
448		CHECK(close(sp[0]) == 0);
449	}
450
451	/* Send descriptors from child to parent. */
452	CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);
453	CHECK((pid = fork()) >= 0);
454	if (pid == 0) {
455		CHECK(close(sp[0]) == 0);
456		ioctl_tests_send_0(sp[1]);
457		CHECK(close(sp[1]) == 0);
458		exit(0);
459	} else {
460		CHECK(close(sp[1]) == 0);
461		ioctl_tests_recv_0(sp[0]);
462		CHECK(waitpid(pid, NULL, 0) == pid);
463		CHECK(close(sp[0]) == 0);
464	}
465
466	exit(0);
467}
468