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
ioctl_tests_0(int fd)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
ioctl_tests_1(int fd)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
ioctl_tests_2(int fd)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
ioctl_tests_send_0(int sock)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
ioctl_tests_recv_0(int sock)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
main(void)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