2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2021 The FreeBSD Foundation
6 * This software was developed by Mark Johnston under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Basic regression tests for handling of O_PATH descriptors.
35 #include <sys/param.h>
36 #include <sys/capsicum.h>
37 #include <sys/event.h>
38 #include <sys/ioctl.h>
39 #include <sys/memrange.h>
41 #include <sys/socket.h>
58 #define FMT_ERR(s) s ": %s", strerror(errno)
60 #define CHECKED_CLOSE(fd) \
61 ATF_REQUIRE_MSG(close(fd) == 0, FMT_ERR("close"))
63 /* Create a temporary regular file containing some data. */
65 mktfile(char path[PATH_MAX], const char *template)
70 snprintf(path, PATH_MAX, "%s", template);
72 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkstemp"));
73 memset(buf, 0, sizeof(buf));
74 ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
79 /* Make a temporary directory. */
81 mktdir(char path[PATH_MAX], const char *template)
83 snprintf(path, PATH_MAX, "%s", template);
84 ATF_REQUIRE_MSG(mkdtemp(path) == path, FMT_ERR("mkdtemp"));
87 /* Wait for a child process to exit with status 0. */
89 waitchild(pid_t child, int exstatus)
93 error = waitpid(child, &status, 0);
94 ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid"));
95 ATF_REQUIRE_MSG(WIFEXITED(status), "child exited abnormally, status %d",
97 ATF_REQUIRE_MSG(WEXITSTATUS(status) == exstatus,
98 "child exit status is %d, expected %d",
99 WEXITSTATUS(status), exstatus);
102 ATF_TC_WITHOUT_HEAD(path_access);
103 ATF_TC_BODY(path_access, tc)
107 struct timespec ts[2];
108 struct timeval tv[2];
111 mktfile(path, "path_access.XXXXXX");
113 pathfd = open(path, O_PATH);
114 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
116 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0666) == -1);
117 ATF_REQUIRE_ERRNO(EBADF, fchown(pathfd, getuid(), getgid()) == -1);
118 ATF_REQUIRE_ERRNO(EBADF, fchflags(pathfd, UF_NODUMP) == -1);
119 memset(tv, 0, sizeof(tv));
120 ATF_REQUIRE_ERRNO(EBADF, futimes(pathfd, tv) == -1);
121 memset(ts, 0, sizeof(ts));
122 ATF_REQUIRE_ERRNO(EBADF, futimens(pathfd, ts) == -1);
124 /* fpathconf(2) and fstat(2) are permitted. */
125 ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat"));
126 ATF_REQUIRE_MSG(fpathconf(pathfd, _PC_LINK_MAX) != -1,
127 FMT_ERR("fpathconf"));
129 CHECKED_CLOSE(pathfd);
132 /* Basic tests to verify that AIO operations fail. */
133 ATF_TC_WITHOUT_HEAD(path_aio);
134 ATF_TC_BODY(path_aio, tc)
137 char buf[BUFSIZ], path[PATH_MAX];
140 mktfile(path, "path_aio.XXXXXX");
142 pathfd = open(path, O_PATH);
143 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
145 memset(&aio, 0, sizeof(aio));
147 aio.aio_nbytes = sizeof(buf);
148 aio.aio_fildes = pathfd;
151 ATF_REQUIRE_ERRNO(EBADF, aio_read(&aio) == -1);
152 ATF_REQUIRE_ERRNO(EBADF, aio_write(&aio) == -1);
153 ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_SYNC, &aio) == -1);
154 ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_DSYNC, &aio) == -1);
156 CHECKED_CLOSE(pathfd);
159 /* Basic tests to verify that Capsicum restrictions apply to path fds. */
160 ATF_TC_WITHOUT_HEAD(path_capsicum);
161 ATF_TC_BODY(path_capsicum, tc)
168 mktfile(path, "path_capsicum.XXXXXX");
170 /* Make sure that filesystem namespace restrictions apply to O_PATH. */
172 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
174 if (cap_enter() != 0)
176 if (open(path, O_PATH) >= 0)
178 if (errno != ECAPMODE)
180 if (open("/usr/bin/true", O_PATH | O_EXEC) >= 0)
182 if (errno != ECAPMODE)
188 /* Make sure that CAP_FEXECVE is required. */
190 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
192 truefd = open("/usr/bin/true", O_PATH | O_EXEC);
195 cap_rights_init(&rights);
196 if (cap_rights_limit(truefd, &rights) != 0)
198 (void)fexecve(truefd,
199 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
201 if (errno != ENOTCAPABLE)
208 /* Verify operations on directory path descriptors. */
209 ATF_TC_WITHOUT_HEAD(path_directory);
210 ATF_TC_BODY(path_directory, tc)
217 mktdir(path, "path_directory.XXXXXX");
219 pathfd = open(path, O_PATH | O_DIRECTORY);
220 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
222 /* Should not be possible to list directory entries. */
223 ATF_REQUIRE_ERRNO(EBADF,
224 getdirentries(pathfd, (char *)&de, sizeof(de), NULL) == -1);
226 /* It should be possible to create files under pathfd. */
227 fd = openat(pathfd, "test", O_RDWR | O_CREAT, 0600);
228 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
229 ATF_REQUIRE_MSG(fstatat(pathfd, "test", &sb, 0) == 0,
233 /* ... but doing so requires write access. */
234 if (geteuid() != 0) {
235 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
236 ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
237 ATF_REQUIRE_ERRNO(EACCES,
238 openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
241 /* fchdir(2) is permitted. */
242 ATF_REQUIRE_MSG(fchdir(pathfd) == 0, FMT_ERR("fchdir"));
244 CHECKED_CLOSE(pathfd);
247 /* Verify access permission checking for a directory path fd. */
248 ATF_TC_WITH_CLEANUP(path_directory_not_root);
249 ATF_TC_HEAD(path_directory_not_root, tc)
251 atf_tc_set_md_var(tc, "require.user", "unprivileged");
253 ATF_TC_BODY(path_directory_not_root, tc)
258 mktdir(path, "path_directory.XXXXXX");
260 pathfd = open(path, O_PATH | O_DIRECTORY);
261 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
263 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
264 ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
265 ATF_REQUIRE_ERRNO(EACCES,
266 openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
268 CHECKED_CLOSE(pathfd);
270 ATF_TC_CLEANUP(path_directory_not_root, tc)
274 /* Validate system calls that handle AT_EMPTY_PATH. */
275 ATF_TC_WITHOUT_HEAD(path_empty);
276 ATF_TC_BODY(path_empty, tc)
279 struct timespec ts[2];
283 mktfile(path, "path_empty.XXXXXX");
285 pathfd = open(path, O_PATH);
286 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
288 /* Various *at operations should work on path fds. */
289 ATF_REQUIRE_MSG(faccessat(pathfd, "", F_OK, AT_EMPTY_PATH) == 0,
290 FMT_ERR("faccessat"));
291 ATF_REQUIRE_MSG(chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == 0,
292 FMT_ERR("chflagsat"));
293 ATF_REQUIRE_MSG(fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == 0,
294 FMT_ERR("fchmodat"));
295 ATF_REQUIRE_MSG(fchownat(pathfd, "", getuid(), getgid(),
296 AT_EMPTY_PATH) == 0, FMT_ERR("fchownat"));
297 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
299 ATF_REQUIRE_MSG(sb.st_size == BUFSIZ,
300 "unexpected size %ju", (uintmax_t)sb.st_size);
301 memset(ts, 0, sizeof(ts));
302 ATF_REQUIRE_MSG(utimensat(pathfd, "", ts, AT_EMPTY_PATH) == 0,
303 FMT_ERR("utimensat"));
305 CHECKED_CLOSE(pathfd);
308 /* Verify that various operations on a path fd have access checks. */
309 ATF_TC_WITH_CLEANUP(path_empty_not_root);
310 ATF_TC_HEAD(path_empty_not_root, tc)
312 atf_tc_set_md_var(tc, "require.user", "unprivileged");
314 ATF_TC_BODY(path_empty_not_root, tc)
318 pathfd = open("/dev/null", O_PATH);
319 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
321 ATF_REQUIRE_ERRNO(EPERM,
322 chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == -1);
323 ATF_REQUIRE_ERRNO(EPERM,
324 fchownat(pathfd, "", getuid(), getgid(), AT_EMPTY_PATH) == -1);
325 ATF_REQUIRE_ERRNO(EPERM,
326 fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == -1);
327 ATF_REQUIRE_ERRNO(EPERM,
328 linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) == -1);
330 CHECKED_CLOSE(pathfd);
332 ATF_TC_CLEANUP(path_empty_not_root, tc)
336 /* Test linkat(2) with AT_EMPTY_PATH, which requires privileges. */
337 ATF_TC_WITH_CLEANUP(path_empty_root);
338 ATF_TC_HEAD(path_empty_root, tc)
340 atf_tc_set_md_var(tc, "require.user", "root");
342 ATF_TC_BODY(path_empty_root, tc)
348 mktfile(path, "path_empty_root.XXXXXX");
350 pathfd = open(path, O_PATH);
351 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
352 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
355 ATF_REQUIRE_MSG(linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) ==
356 0, FMT_ERR("linkat"));
357 ATF_REQUIRE_MSG(fstatat(AT_FDCWD, "test", &sb2, 0) == 0,
359 ATF_REQUIRE_MSG(sb.st_dev == sb2.st_dev, "st_dev mismatch");
360 ATF_REQUIRE_MSG(sb.st_ino == sb2.st_ino, "st_ino mismatch");
362 CHECKED_CLOSE(pathfd);
365 ATF_TC_CLEANUP(path_empty_root, tc)
369 /* poll(2) never returns an event for path fds, but kevent(2) does. */
370 ATF_TC_WITHOUT_HEAD(path_event);
371 ATF_TC_BODY(path_event, tc)
373 char buf[BUFSIZ], path[PATH_MAX];
375 struct pollfd pollfd;
378 mktfile(path, "path_event.XXXXXX");
380 pathfd = open(path, O_PATH);
381 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
383 /* poll(2) should return POLLNVAL. */
385 pollfd.events = POLLIN;
387 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
388 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
390 pollfd.events = POLLOUT;
392 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
393 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
396 /* Try to get a EVFILT_READ event through a path fd. */
398 ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
399 EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
400 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
402 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
404 ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set");
405 ATF_REQUIRE_MSG(ev.data == sizeof(buf),
406 "data is %jd", (intmax_t)ev.data);
407 EV_SET(&ev, pathfd, EVFILT_READ, EV_DELETE, 0, 0, 0);
408 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
411 /* Try to get a EVFILT_VNODE/NOTE_LINK event through a path fd. */
412 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_LINK, 0, 0);
413 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
415 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
416 FMT_ERR("funlinkat"));
417 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
419 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_DELETE, 0, 0, 0);
420 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
424 CHECKED_CLOSE(pathfd);
427 /* Check various fcntl(2) operations on a path desriptor. */
428 ATF_TC_WITHOUT_HEAD(path_fcntl);
429 ATF_TC_BODY(path_fcntl, tc)
432 int flags, pathfd, pathfd2;
434 mktfile(path, "path_fcntl.XXXXXX");
436 pathfd = open(path, O_PATH);
437 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
439 /* O_PATH should appear in the fd flags. */
440 flags = fcntl(pathfd, F_GETFL);
441 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
442 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
444 ATF_REQUIRE_ERRNO(EBADF,
445 fcntl(pathfd, F_SETFL, flags & ~O_PATH));
446 ATF_REQUIRE_ERRNO(EBADF,
447 fcntl(pathfd, F_SETFL, flags | O_APPEND));
449 /* A dup'ed O_PATH fd had better have O_PATH set too. */
450 pathfd2 = fcntl(pathfd, F_DUPFD, 0);
451 ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("fcntl"));
452 flags = fcntl(pathfd2, F_GETFL);
453 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
454 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
455 CHECKED_CLOSE(pathfd2);
457 /* Double check with dup(2). */
458 pathfd2 = dup(pathfd);
459 ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("dup"));
460 flags = fcntl(pathfd2, F_GETFL);
461 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
462 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
463 CHECKED_CLOSE(pathfd2);
465 /* It should be possible to set O_CLOEXEC. */
466 ATF_REQUIRE_MSG(fcntl(pathfd, F_SETFD, FD_CLOEXEC) == 0,
468 ATF_REQUIRE_MSG(fcntl(pathfd, F_GETFD) == FD_CLOEXEC,
471 CHECKED_CLOSE(pathfd);
474 /* Verify that we can execute a file opened with O_PATH. */
475 ATF_TC_WITHOUT_HEAD(path_fexecve);
476 ATF_TC_BODY(path_fexecve, tc)
483 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
485 pathfd = open("/usr/bin/true", O_PATH | O_EXEC);
489 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
496 * Also verify that access permissions are checked when opening with
499 snprintf(path, sizeof(path), "path_fexecve.XXXXXX");
500 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
502 fd = open(path, O_CREAT | O_RDONLY, 0600);
503 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
505 pathfd = open(path, O_PATH | O_EXEC);
506 ATF_REQUIRE_ERRNO(EACCES, pathfd < 0);
509 /* Files may be unlinked using a path fd. */
510 ATF_TC_WITHOUT_HEAD(path_funlinkat);
511 ATF_TC_BODY(path_funlinkat, tc)
517 mktfile(path, "path_rights.XXXXXX");
519 pathfd = open(path, O_PATH);
520 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
522 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
523 FMT_ERR("funlinkat"));
524 ATF_REQUIRE_ERRNO(ENOENT, stat(path, &sb) == -1);
526 CHECKED_CLOSE(pathfd);
529 /* Verify that various I/O operations fail on an O_PATH descriptor. */
530 ATF_TC_WITHOUT_HEAD(path_io);
531 ATF_TC_BODY(path_io, tc)
533 char path[PATH_MAX], path2[PATH_MAX];
536 int error, fd, pathfd, sd[2];
538 /* It shouldn't be possible to create new files with O_PATH. */
539 snprintf(path, sizeof(path), "path_io.XXXXXX");
540 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
541 ATF_REQUIRE_ERRNO(ENOENT, open(path, O_PATH | O_CREAT, 0600) < 0);
543 /* Create a non-empty file for use in the rest of the tests. */
544 mktfile(path, "path_io.XXXXXX");
546 pathfd = open(path, O_PATH);
547 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
549 /* Make sure that basic I/O operations aren't possible. */
551 iov.iov_len = strlen(path);
552 ATF_REQUIRE_ERRNO(EBADF,
553 write(pathfd, iov.iov_base, iov.iov_len) == -1);
554 ATF_REQUIRE_ERRNO(EBADF,
555 pwrite(pathfd, iov.iov_base, iov.iov_len, 0) == -1);
556 ATF_REQUIRE_ERRNO(EBADF,
557 writev(pathfd, &iov, 1) == -1);
558 ATF_REQUIRE_ERRNO(EBADF,
559 pwritev(pathfd, &iov, 1, 0) == -1);
560 ATF_REQUIRE_ERRNO(EBADF,
561 read(pathfd, path, 1) == -1);
562 ATF_REQUIRE_ERRNO(EBADF,
563 pread(pathfd, path, 1, 0) == -1);
564 ATF_REQUIRE_ERRNO(EBADF,
565 readv(pathfd, &iov, 1) == -1);
566 ATF_REQUIRE_ERRNO(EBADF,
567 preadv(pathfd, &iov, 1, 0) == -1);
569 /* copy_file_range() should not be permitted. */
570 mktfile(path2, "path_io.XXXXXX");
571 fd = open(path2, O_RDWR);
572 ATF_REQUIRE_ERRNO(EBADF,
573 copy_file_range(fd, NULL, pathfd, NULL, sizeof(buf), 0) == -1);
574 ATF_REQUIRE_ERRNO(EBADF,
575 copy_file_range(pathfd, NULL, fd, NULL, sizeof(buf), 0) == -1);
578 /* sendfile() should not be permitted. */
579 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
580 FMT_ERR("socketpair"));
581 ATF_REQUIRE_ERRNO(EBADF,
582 sendfile(pathfd, sd[0], 0, 0, NULL, NULL, 0));
583 CHECKED_CLOSE(sd[0]);
584 CHECKED_CLOSE(sd[1]);
587 ATF_REQUIRE_ERRNO(ESPIPE,
588 lseek(pathfd, 0, SEEK_SET) == -1);
590 /* No operations on the file extent. */
591 ATF_REQUIRE_ERRNO(EINVAL,
592 ftruncate(pathfd, 0) == -1);
593 error = posix_fallocate(pathfd, 0, sizeof(buf) * 2);
594 ATF_REQUIRE_MSG(error == ESPIPE, "posix_fallocate() returned %d", error);
595 error = posix_fadvise(pathfd, 0, sizeof(buf), POSIX_FADV_NORMAL);
596 ATF_REQUIRE_MSG(error == ESPIPE, "posix_fadvise() returned %d", error);
598 /* mmap() is not allowed. */
599 ATF_REQUIRE_ERRNO(ENODEV,
600 mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, pathfd, 0) ==
602 ATF_REQUIRE_ERRNO(ENODEV,
603 mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_SHARED, pathfd, 0) ==
605 ATF_REQUIRE_ERRNO(ENODEV,
606 mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, pathfd, 0) ==
609 /* No fsync() or fdatasync(). */
610 ATF_REQUIRE_ERRNO(EBADF, fsync(pathfd) == -1);
611 ATF_REQUIRE_ERRNO(EBADF, fdatasync(pathfd) == -1);
613 CHECKED_CLOSE(pathfd);
616 /* ioctl(2) is not permitted on path fds. */
617 ATF_TC_WITHOUT_HEAD(path_ioctl);
618 ATF_TC_BODY(path_ioctl, tc)
621 struct mem_extract me;
624 mktfile(path, "path_ioctl.XXXXXX");
626 /* Standard file descriptor ioctls should fail. */
627 pathfd = open(path, O_PATH);
628 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
631 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONBIO, &val) == -1);
632 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONREAD, &val) == -1);
633 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONWRITE, &val) == -1);
634 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONSPACE, &val) == -1);
636 CHECKED_CLOSE(pathfd);
638 /* Device ioctls should fail. */
639 pathfd = open("/dev/mem", O_PATH);
640 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
642 me.me_vaddr = (uintptr_t)&me;
643 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, MEM_EXTRACT_PADDR, &me) == -1);
645 CHECKED_CLOSE(pathfd);
648 ATF_TC_WITHOUT_HEAD(path_lock);
649 ATF_TC_BODY(path_lock, tc)
651 char buf[BUFSIZ], path[PATH_MAX];
655 snprintf(path, sizeof(path), "path_rights.XXXXXX");
656 fd = mkostemp(path, O_SHLOCK);
657 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkostemp"));
658 memset(buf, 0, sizeof(buf));
659 ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
662 /* Verify that O_EXLOCK is ignored when combined with O_PATH. */
663 pathfd = open(path, O_PATH | O_EXLOCK);
664 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
668 /* flock(2) is prohibited. */
669 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH) == -1);
670 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX) == -1);
671 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH | LOCK_NB) == -1);
672 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX | LOCK_NB) == -1);
673 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_UN) == -1);
675 /* fcntl(2) file locks are prohibited. */
676 memset(&flk, 0, sizeof(flk));
677 flk.l_whence = SEEK_CUR;
678 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_GETLK, &flk) == -1);
679 flk.l_type = F_RDLCK;
680 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
681 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
682 flk.l_type = F_WRLCK;
683 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
684 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
686 CHECKED_CLOSE(pathfd);
689 /* Verify that we can send an O_PATH descriptor over a unix socket. */
690 ATF_TC_WITHOUT_HEAD(path_rights);
691 ATF_TC_BODY(path_rights, tc)
694 struct cmsghdr *cmsg;
697 int flags, pathfd, pathfd_copy, sd[2];
700 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
701 FMT_ERR("socketpair"));
703 mktfile(path, "path_rights.XXXXXX");
705 pathfd = open(path, O_PATH);
706 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
708 /* Package up the O_PATH and send it over the socket pair. */
709 cmsg = malloc(CMSG_SPACE(sizeof(pathfd)));
710 ATF_REQUIRE_MSG(cmsg != NULL, FMT_ERR("malloc"));
712 cmsg->cmsg_len = CMSG_LEN(sizeof(pathfd));
713 cmsg->cmsg_level = SOL_SOCKET;
714 cmsg->cmsg_type = SCM_RIGHTS;
715 *(int *)(void *)CMSG_DATA(cmsg) = pathfd;
721 memset(&msg, 0, sizeof(msg));
724 msg.msg_control = cmsg;
725 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
727 ATF_REQUIRE_MSG(sendmsg(sd[0], &msg, 0) == sizeof(c),
730 /* Grab the pathfd copy from the other end of the pair. */
731 memset(&msg, 0, sizeof(msg));
734 msg.msg_control = cmsg;
735 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
737 ATF_REQUIRE_MSG(recvmsg(sd[1], &msg, 0) == 1,
739 pathfd_copy = *(int *)(void *)CMSG_DATA(cmsg);
740 ATF_REQUIRE_MSG(pathfd_copy != pathfd,
741 "pathfd and pathfd_copy are equal");
743 /* Verify that the copy has O_PATH properties. */
744 flags = fcntl(pathfd_copy, F_GETFL);
745 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
746 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH is not set");
747 ATF_REQUIRE_ERRNO(EBADF,
748 read(pathfd_copy, &c, 1) == -1);
749 ATF_REQUIRE_ERRNO(EBADF,
750 write(pathfd_copy, &c, 1) == -1);
752 CHECKED_CLOSE(pathfd);
753 CHECKED_CLOSE(pathfd_copy);
754 CHECKED_CLOSE(sd[0]);
755 CHECKED_CLOSE(sd[1]);
760 ATF_TP_ADD_TC(tp, path_access);
761 ATF_TP_ADD_TC(tp, path_aio);
762 ATF_TP_ADD_TC(tp, path_capsicum);
763 ATF_TP_ADD_TC(tp, path_directory);
764 ATF_TP_ADD_TC(tp, path_directory_not_root);
765 ATF_TP_ADD_TC(tp, path_empty);
766 ATF_TP_ADD_TC(tp, path_empty_not_root);
767 ATF_TP_ADD_TC(tp, path_empty_root);
768 ATF_TP_ADD_TC(tp, path_event);
769 ATF_TP_ADD_TC(tp, path_fcntl);
770 ATF_TP_ADD_TC(tp, path_fexecve);
771 ATF_TP_ADD_TC(tp, path_funlinkat);
772 ATF_TP_ADD_TC(tp, path_io);
773 ATF_TP_ADD_TC(tp, path_ioctl);
774 ATF_TP_ADD_TC(tp, path_lock);
775 ATF_TP_ADD_TC(tp, path_rights);
777 return (atf_no_error());