xref: /freebsd/tools/regression/capsicum/syscalls/cap_ioctls_limit.c (revision 2f9966ff63d65bd474478888c9088eeae3f9c669)
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 
46 static void
47 ioctl_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 
127 static void
128 ioctl_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 
173 static void
174 ioctl_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 
212 static void
213 ioctl_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 
241 static void
242 ioctl_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 
313 int
314 main(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