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