xref: /freebsd/tools/regression/capsicum/syscalls/cap_ioctls_limit.c (revision 5dae51da3da0cc94d17bd67b308fad304ebec7e0)
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 
49 static void
50 ioctl_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 
130 static void
131 ioctl_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 
176 static void
177 ioctl_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 
215 static void
216 ioctl_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 
244 static void
245 ioctl_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 
316 int
317 main(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