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/ptrace.h>
42 #include <sys/socket.h>
61 #define FMT_ERR(s) s ": %s", strerror(errno)
63 #define CHECKED_CLOSE(fd) \
64 ATF_REQUIRE_MSG(close(fd) == 0, FMT_ERR("close"))
67 * Verify fstatat(AT_EMPTY_PATH) on non-regular dirfd.
68 * Verify that fstatat(AT_EMPTY_PATH) on NULL path returns EFAULT.
70 ATF_TC_WITHOUT_HEAD(path_pipe_fstatat);
71 ATF_TC_BODY(path_pipe_fstatat, tc)
76 ATF_REQUIRE_MSG(pipe(fd) == 0, FMT_ERR("pipe"));
77 ATF_REQUIRE_MSG(fstatat(fd[0], "", &sb, AT_EMPTY_PATH) == 0,
78 FMT_ERR("fstatat pipe"));
79 ATF_REQUIRE_ERRNO(EFAULT, fstatat(fd[0], NULL, &sb,
80 AT_EMPTY_PATH) == -1);
85 /* Create a temporary regular file containing some data. */
87 mktfile(char path[PATH_MAX], const char *template)
92 snprintf(path, PATH_MAX, "%s", template);
94 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkstemp"));
95 memset(buf, 0, sizeof(buf));
96 ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
101 /* Make a temporary directory. */
103 mktdir(char path[PATH_MAX], const char *template)
105 snprintf(path, PATH_MAX, "%s", template);
106 ATF_REQUIRE_MSG(mkdtemp(path) == path, FMT_ERR("mkdtemp"));
109 /* Wait for a child process to exit with status 0. */
111 waitchild(pid_t child, int exstatus)
115 error = waitpid(child, &status, 0);
116 ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid"));
117 ATF_REQUIRE_MSG(WIFEXITED(status), "child exited abnormally, status %d",
119 ATF_REQUIRE_MSG(WEXITSTATUS(status) == exstatus,
120 "child exit status is %d, expected %d",
121 WEXITSTATUS(status), exstatus);
124 ATF_TC_WITHOUT_HEAD(path_access);
125 ATF_TC_BODY(path_access, tc)
129 struct timespec ts[2];
130 struct timeval tv[2];
133 mktfile(path, "path_access.XXXXXX");
135 pathfd = open(path, O_PATH);
136 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
138 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0666) == -1);
139 ATF_REQUIRE_ERRNO(EBADF, fchown(pathfd, getuid(), getgid()) == -1);
140 ATF_REQUIRE_ERRNO(EBADF, fchflags(pathfd, UF_NODUMP) == -1);
141 memset(tv, 0, sizeof(tv));
142 ATF_REQUIRE_ERRNO(EBADF, futimes(pathfd, tv) == -1);
143 memset(ts, 0, sizeof(ts));
144 ATF_REQUIRE_ERRNO(EBADF, futimens(pathfd, ts) == -1);
146 /* fpathconf(2) and fstat(2) are permitted. */
147 ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat"));
148 ATF_REQUIRE_MSG(fpathconf(pathfd, _PC_LINK_MAX) != -1,
149 FMT_ERR("fpathconf"));
151 CHECKED_CLOSE(pathfd);
154 /* Basic tests to verify that AIO operations fail. */
155 ATF_TC_WITHOUT_HEAD(path_aio);
156 ATF_TC_BODY(path_aio, tc)
159 char buf[BUFSIZ], path[PATH_MAX];
162 mktfile(path, "path_aio.XXXXXX");
164 pathfd = open(path, O_PATH);
165 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
167 memset(&aio, 0, sizeof(aio));
169 aio.aio_nbytes = sizeof(buf);
170 aio.aio_fildes = pathfd;
173 ATF_REQUIRE_ERRNO(EBADF, aio_read(&aio) == -1);
174 ATF_REQUIRE_ERRNO(EBADF, aio_write(&aio) == -1);
175 ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_SYNC, &aio) == -1);
176 ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_DSYNC, &aio) == -1);
178 CHECKED_CLOSE(pathfd);
181 /* Basic tests to verify that Capsicum restrictions apply to path fds. */
182 ATF_TC_WITHOUT_HEAD(path_capsicum);
183 ATF_TC_BODY(path_capsicum, tc)
190 mktfile(path, "path_capsicum.XXXXXX");
192 /* Make sure that filesystem namespace restrictions apply to O_PATH. */
194 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
196 if (cap_enter() != 0)
198 if (open(path, O_PATH) >= 0)
200 if (errno != ECAPMODE)
202 if (open("/usr/bin/true", O_PATH | O_EXEC) >= 0)
204 if (errno != ECAPMODE)
210 /* Make sure that CAP_FEXECVE is required. */
212 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
214 truefd = open("/usr/bin/true", O_PATH | O_EXEC);
217 cap_rights_init(&rights);
218 if (cap_rights_limit(truefd, &rights) != 0)
220 (void)fexecve(truefd,
221 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
223 if (errno != ENOTCAPABLE)
230 /* Make sure that ptrace(PT_COREDUMP) cannot be used to write to a path fd. */
231 ATF_TC_WITHOUT_HEAD(path_coredump);
232 ATF_TC_BODY(path_coredump, tc)
235 struct ptrace_coredump pc;
236 int error, pathfd, status;
239 mktdir(path, "path_coredump.XXXXXX");
242 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
248 pathfd = open(path, O_PATH);
249 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
251 error = ptrace(PT_ATTACH, child, 0, 0);
252 ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace"));
253 error = waitpid(child, &status, 0);
254 ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid"));
255 ATF_REQUIRE_MSG(WIFSTOPPED(status), "unexpected status %d", status);
260 error = ptrace(PT_COREDUMP, child, (void *)&pc, sizeof(pc));
261 ATF_REQUIRE_ERRNO(EBADF, error == -1);
263 error = ptrace(PT_DETACH, child, 0, 0);
264 ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace"));
266 ATF_REQUIRE_MSG(kill(child, SIGKILL) == 0, FMT_ERR("kill"));
268 CHECKED_CLOSE(pathfd);
271 /* Verify operations on directory path descriptors. */
272 ATF_TC_WITHOUT_HEAD(path_directory);
273 ATF_TC_BODY(path_directory, tc)
280 mktdir(path, "path_directory.XXXXXX");
282 pathfd = open(path, O_PATH | O_DIRECTORY);
283 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
285 /* Should not be possible to list directory entries. */
286 ATF_REQUIRE_ERRNO(EBADF,
287 getdirentries(pathfd, (char *)&de, sizeof(de), NULL) == -1);
289 /* It should be possible to create files under pathfd. */
290 fd = openat(pathfd, "test", O_RDWR | O_CREAT, 0600);
291 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
292 ATF_REQUIRE_MSG(fstatat(pathfd, "test", &sb, 0) == 0,
296 /* ... but doing so requires write access. */
297 if (geteuid() != 0) {
298 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
299 ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
300 ATF_REQUIRE_ERRNO(EACCES,
301 openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
304 /* fchdir(2) is permitted. */
305 ATF_REQUIRE_MSG(fchdir(pathfd) == 0, FMT_ERR("fchdir"));
307 CHECKED_CLOSE(pathfd);
310 /* Verify access permission checking for a directory path fd. */
311 ATF_TC_WITH_CLEANUP(path_directory_not_root);
312 ATF_TC_HEAD(path_directory_not_root, tc)
314 atf_tc_set_md_var(tc, "require.user", "unprivileged");
316 ATF_TC_BODY(path_directory_not_root, tc)
321 mktdir(path, "path_directory.XXXXXX");
323 pathfd = open(path, O_PATH | O_DIRECTORY);
324 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
326 ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1);
327 ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod"));
328 ATF_REQUIRE_ERRNO(EACCES,
329 openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0);
331 CHECKED_CLOSE(pathfd);
333 ATF_TC_CLEANUP(path_directory_not_root, tc)
337 /* Validate system calls that handle AT_EMPTY_PATH. */
338 ATF_TC_WITHOUT_HEAD(path_empty);
339 ATF_TC_BODY(path_empty, tc)
342 struct timespec ts[2];
346 mktfile(path, "path_empty.XXXXXX");
348 pathfd = open(path, O_PATH);
349 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
351 /* Various *at operations should work on path fds. */
352 ATF_REQUIRE_MSG(faccessat(pathfd, "", F_OK, AT_EMPTY_PATH) == 0,
353 FMT_ERR("faccessat"));
354 ATF_REQUIRE_MSG(chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == 0,
355 FMT_ERR("chflagsat"));
356 ATF_REQUIRE_MSG(fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == 0,
357 FMT_ERR("fchmodat"));
358 ATF_REQUIRE_MSG(fchownat(pathfd, "", getuid(), getgid(),
359 AT_EMPTY_PATH) == 0, FMT_ERR("fchownat"));
360 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
362 ATF_REQUIRE_MSG(sb.st_size == BUFSIZ,
363 "unexpected size %ju", (uintmax_t)sb.st_size);
364 memset(ts, 0, sizeof(ts));
365 ATF_REQUIRE_MSG(utimensat(pathfd, "", ts, AT_EMPTY_PATH) == 0,
366 FMT_ERR("utimensat"));
368 CHECKED_CLOSE(pathfd);
371 /* Verify that various operations on a path fd have access checks. */
372 ATF_TC_WITH_CLEANUP(path_empty_not_root);
373 ATF_TC_HEAD(path_empty_not_root, tc)
375 atf_tc_set_md_var(tc, "require.user", "unprivileged");
377 ATF_TC_BODY(path_empty_not_root, tc)
381 pathfd = open("/dev/null", O_PATH);
382 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
384 ATF_REQUIRE_ERRNO(EPERM,
385 chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == -1);
386 ATF_REQUIRE_ERRNO(EPERM,
387 fchownat(pathfd, "", getuid(), getgid(), AT_EMPTY_PATH) == -1);
388 ATF_REQUIRE_ERRNO(EPERM,
389 fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == -1);
390 ATF_REQUIRE_ERRNO(EPERM,
391 linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) == -1);
393 CHECKED_CLOSE(pathfd);
395 ATF_TC_CLEANUP(path_empty_not_root, tc)
399 /* Test linkat(2) with AT_EMPTY_PATH, which requires privileges. */
400 ATF_TC_WITH_CLEANUP(path_empty_root);
401 ATF_TC_HEAD(path_empty_root, tc)
403 atf_tc_set_md_var(tc, "require.user", "root");
405 ATF_TC_BODY(path_empty_root, tc)
411 mktfile(path, "path_empty_root.XXXXXX");
413 pathfd = open(path, O_PATH);
414 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
415 ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0,
418 ATF_REQUIRE_MSG(linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) ==
419 0, FMT_ERR("linkat"));
420 ATF_REQUIRE_MSG(fstatat(AT_FDCWD, "test", &sb2, 0) == 0,
422 ATF_REQUIRE_MSG(sb.st_dev == sb2.st_dev, "st_dev mismatch");
423 ATF_REQUIRE_MSG(sb.st_ino == sb2.st_ino, "st_ino mismatch");
425 CHECKED_CLOSE(pathfd);
428 ATF_TC_CLEANUP(path_empty_root, tc)
432 /* poll(2) never returns an event for path fds, but kevent(2) does. */
433 ATF_TC_WITHOUT_HEAD(path_event);
434 ATF_TC_BODY(path_event, tc)
436 char buf[BUFSIZ], path[PATH_MAX];
438 struct pollfd pollfd;
441 mktfile(path, "path_event.XXXXXX");
443 pathfd = open(path, O_PATH);
444 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
446 /* poll(2) should return POLLNVAL. */
448 pollfd.events = POLLIN;
450 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
451 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
453 pollfd.events = POLLOUT;
455 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll"));
456 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x",
459 /* Try to get a EVFILT_READ event through a path fd. */
461 ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
462 EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
463 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
465 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
467 ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set");
468 ATF_REQUIRE_MSG(ev.data == sizeof(buf),
469 "data is %jd", (intmax_t)ev.data);
470 EV_SET(&ev, pathfd, EVFILT_READ, EV_DELETE, 0, 0, 0);
471 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
474 /* Try to get a EVFILT_VNODE/NOTE_LINK event through a path fd. */
475 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_LINK, 0, 0);
476 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
478 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
479 FMT_ERR("funlinkat"));
480 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1,
482 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_DELETE, 0, 0, 0);
483 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0,
487 CHECKED_CLOSE(pathfd);
490 /* Check various fcntl(2) operations on a path desriptor. */
491 ATF_TC_WITHOUT_HEAD(path_fcntl);
492 ATF_TC_BODY(path_fcntl, tc)
495 int flags, pathfd, pathfd2;
497 mktfile(path, "path_fcntl.XXXXXX");
499 pathfd = open(path, O_PATH);
500 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
502 /* O_PATH should appear in the fd flags. */
503 flags = fcntl(pathfd, F_GETFL);
504 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
505 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
507 ATF_REQUIRE_ERRNO(EBADF,
508 fcntl(pathfd, F_SETFL, flags & ~O_PATH));
509 ATF_REQUIRE_ERRNO(EBADF,
510 fcntl(pathfd, F_SETFL, flags | O_APPEND));
512 /* A dup'ed O_PATH fd had better have O_PATH set too. */
513 pathfd2 = fcntl(pathfd, F_DUPFD, 0);
514 ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("fcntl"));
515 flags = fcntl(pathfd2, F_GETFL);
516 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
517 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
518 CHECKED_CLOSE(pathfd2);
520 /* Double check with dup(2). */
521 pathfd2 = dup(pathfd);
522 ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("dup"));
523 flags = fcntl(pathfd2, F_GETFL);
524 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
525 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set");
526 CHECKED_CLOSE(pathfd2);
528 /* It should be possible to set O_CLOEXEC. */
529 ATF_REQUIRE_MSG(fcntl(pathfd, F_SETFD, FD_CLOEXEC) == 0,
531 ATF_REQUIRE_MSG(fcntl(pathfd, F_GETFD) == FD_CLOEXEC,
534 CHECKED_CLOSE(pathfd);
537 /* Verify that we can execute a file opened with O_PATH. */
538 ATF_TC_WITHOUT_HEAD(path_fexecve);
539 ATF_TC_BODY(path_fexecve, tc)
546 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork"));
548 pathfd = open("/usr/bin/true", O_PATH | O_EXEC);
552 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL},
559 * Also verify that access permissions are checked when opening with
562 snprintf(path, sizeof(path), "path_fexecve.XXXXXX");
563 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
565 fd = open(path, O_CREAT | O_RDONLY, 0600);
566 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open"));
568 pathfd = open(path, O_PATH | O_EXEC);
569 ATF_REQUIRE_ERRNO(EACCES, pathfd < 0);
572 /* Make sure that O_PATH restrictions apply to named pipes as well. */
573 ATF_TC_WITHOUT_HEAD(path_fifo);
574 ATF_TC_BODY(path_fifo, tc)
576 char path[PATH_MAX], buf[BUFSIZ];
580 snprintf(path, sizeof(path), "path_fifo.XXXXXX");
581 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
583 ATF_REQUIRE_MSG(mkfifo(path, 0666) == 0, FMT_ERR("mkfifo"));
585 pathfd = open(path, O_PATH);
586 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
587 memset(buf, 0, sizeof(buf));
588 ATF_REQUIRE_ERRNO(EBADF, write(pathfd, buf, sizeof(buf)));
589 ATF_REQUIRE_ERRNO(EBADF, read(pathfd, buf, sizeof(buf)));
592 ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue"));
593 EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
594 ATF_REQUIRE_ERRNO(EBADF, kevent(kq, &ev, 1, NULL, 0, NULL) == -1);
596 CHECKED_CLOSE(pathfd);
599 /* Files may be unlinked using a path fd. */
600 ATF_TC_WITHOUT_HEAD(path_funlinkat);
601 ATF_TC_BODY(path_funlinkat, tc)
607 mktfile(path, "path_rights.XXXXXX");
609 pathfd = open(path, O_PATH);
610 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
612 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0,
613 FMT_ERR("funlinkat"));
614 ATF_REQUIRE_ERRNO(ENOENT, stat(path, &sb) == -1);
616 CHECKED_CLOSE(pathfd);
619 /* Verify that various I/O operations fail on an O_PATH descriptor. */
620 ATF_TC_WITHOUT_HEAD(path_io);
621 ATF_TC_BODY(path_io, tc)
623 char path[PATH_MAX], path2[PATH_MAX];
626 int error, fd, pathfd, sd[2];
628 /* It shouldn't be possible to create new files with O_PATH. */
629 snprintf(path, sizeof(path), "path_io.XXXXXX");
630 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
631 ATF_REQUIRE_ERRNO(ENOENT, open(path, O_PATH | O_CREAT, 0600) < 0);
633 /* Create a non-empty file for use in the rest of the tests. */
634 mktfile(path, "path_io.XXXXXX");
636 pathfd = open(path, O_PATH);
637 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
639 /* Make sure that basic I/O operations aren't possible. */
641 iov.iov_len = strlen(path);
642 ATF_REQUIRE_ERRNO(EBADF,
643 write(pathfd, iov.iov_base, iov.iov_len) == -1);
644 ATF_REQUIRE_ERRNO(EBADF,
645 pwrite(pathfd, iov.iov_base, iov.iov_len, 0) == -1);
646 ATF_REQUIRE_ERRNO(EBADF,
647 writev(pathfd, &iov, 1) == -1);
648 ATF_REQUIRE_ERRNO(EBADF,
649 pwritev(pathfd, &iov, 1, 0) == -1);
650 ATF_REQUIRE_ERRNO(EBADF,
651 read(pathfd, path, 1) == -1);
652 ATF_REQUIRE_ERRNO(EBADF,
653 pread(pathfd, path, 1, 0) == -1);
654 ATF_REQUIRE_ERRNO(EBADF,
655 readv(pathfd, &iov, 1) == -1);
656 ATF_REQUIRE_ERRNO(EBADF,
657 preadv(pathfd, &iov, 1, 0) == -1);
659 /* copy_file_range() should not be permitted. */
660 mktfile(path2, "path_io.XXXXXX");
661 fd = open(path2, O_RDWR);
662 ATF_REQUIRE_ERRNO(EBADF,
663 copy_file_range(fd, NULL, pathfd, NULL, sizeof(buf), 0) == -1);
664 ATF_REQUIRE_ERRNO(EBADF,
665 copy_file_range(pathfd, NULL, fd, NULL, sizeof(buf), 0) == -1);
668 /* sendfile() should not be permitted. */
669 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
670 FMT_ERR("socketpair"));
671 ATF_REQUIRE_ERRNO(EBADF,
672 sendfile(pathfd, sd[0], 0, 0, NULL, NULL, 0));
673 CHECKED_CLOSE(sd[0]);
674 CHECKED_CLOSE(sd[1]);
677 ATF_REQUIRE_ERRNO(ESPIPE,
678 lseek(pathfd, 0, SEEK_SET) == -1);
680 /* No operations on the file extent. */
681 ATF_REQUIRE_ERRNO(EINVAL,
682 ftruncate(pathfd, 0) == -1);
683 error = posix_fallocate(pathfd, 0, sizeof(buf) * 2);
684 ATF_REQUIRE_MSG(error == ESPIPE, "posix_fallocate() returned %d", error);
685 error = posix_fadvise(pathfd, 0, sizeof(buf), POSIX_FADV_NORMAL);
686 ATF_REQUIRE_MSG(error == ESPIPE, "posix_fadvise() returned %d", error);
688 /* mmap() is not allowed. */
689 ATF_REQUIRE_ERRNO(ENODEV,
690 mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, pathfd, 0) ==
692 ATF_REQUIRE_ERRNO(ENODEV,
693 mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_SHARED, pathfd, 0) ==
695 ATF_REQUIRE_ERRNO(ENODEV,
696 mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, pathfd, 0) ==
699 /* No fsync() or fdatasync(). */
700 ATF_REQUIRE_ERRNO(EBADF, fsync(pathfd) == -1);
701 ATF_REQUIRE_ERRNO(EBADF, fdatasync(pathfd) == -1);
703 CHECKED_CLOSE(pathfd);
706 /* ioctl(2) is not permitted on path fds. */
707 ATF_TC_WITHOUT_HEAD(path_ioctl);
708 ATF_TC_BODY(path_ioctl, tc)
711 struct mem_extract me;
714 mktfile(path, "path_ioctl.XXXXXX");
716 /* Standard file descriptor ioctls should fail. */
717 pathfd = open(path, O_PATH);
718 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
721 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONBIO, &val) == -1);
722 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONREAD, &val) == -1);
723 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONWRITE, &val) == -1);
724 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONSPACE, &val) == -1);
726 CHECKED_CLOSE(pathfd);
728 /* Device ioctls should fail. */
729 pathfd = open("/dev/mem", O_PATH);
730 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
732 me.me_vaddr = (uintptr_t)&me;
733 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, MEM_EXTRACT_PADDR, &me) == -1);
735 CHECKED_CLOSE(pathfd);
738 ATF_TC_WITHOUT_HEAD(path_lock);
739 ATF_TC_BODY(path_lock, tc)
741 char buf[BUFSIZ], path[PATH_MAX];
745 snprintf(path, sizeof(path), "path_rights.XXXXXX");
746 fd = mkostemp(path, O_SHLOCK);
747 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkostemp"));
748 memset(buf, 0, sizeof(buf));
749 ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf),
752 /* Verify that O_EXLOCK is ignored when combined with O_PATH. */
753 pathfd = open(path, O_PATH | O_EXLOCK);
754 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
758 /* flock(2) is prohibited. */
759 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH) == -1);
760 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX) == -1);
761 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH | LOCK_NB) == -1);
762 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX | LOCK_NB) == -1);
763 ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_UN) == -1);
765 /* fcntl(2) file locks are prohibited. */
766 memset(&flk, 0, sizeof(flk));
767 flk.l_whence = SEEK_CUR;
768 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_GETLK, &flk) == -1);
769 flk.l_type = F_RDLCK;
770 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
771 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
772 flk.l_type = F_WRLCK;
773 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1);
774 ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1);
776 CHECKED_CLOSE(pathfd);
779 /* Verify that we can send an O_PATH descriptor over a unix socket. */
780 ATF_TC_WITHOUT_HEAD(path_rights);
781 ATF_TC_BODY(path_rights, tc)
784 struct cmsghdr *cmsg;
787 int flags, pathfd, pathfd_copy, sd[2];
790 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0,
791 FMT_ERR("socketpair"));
793 mktfile(path, "path_rights.XXXXXX");
795 pathfd = open(path, O_PATH);
796 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open"));
798 /* Package up the O_PATH and send it over the socket pair. */
799 cmsg = malloc(CMSG_SPACE(sizeof(pathfd)));
800 ATF_REQUIRE_MSG(cmsg != NULL, FMT_ERR("malloc"));
802 cmsg->cmsg_len = CMSG_LEN(sizeof(pathfd));
803 cmsg->cmsg_level = SOL_SOCKET;
804 cmsg->cmsg_type = SCM_RIGHTS;
805 *(int *)(void *)CMSG_DATA(cmsg) = pathfd;
811 memset(&msg, 0, sizeof(msg));
814 msg.msg_control = cmsg;
815 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
817 ATF_REQUIRE_MSG(sendmsg(sd[0], &msg, 0) == sizeof(c),
820 /* Grab the pathfd copy from the other end of the pair. */
821 memset(&msg, 0, sizeof(msg));
824 msg.msg_control = cmsg;
825 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd));
827 ATF_REQUIRE_MSG(recvmsg(sd[1], &msg, 0) == 1,
829 pathfd_copy = *(int *)(void *)CMSG_DATA(cmsg);
830 ATF_REQUIRE_MSG(pathfd_copy != pathfd,
831 "pathfd and pathfd_copy are equal");
833 /* Verify that the copy has O_PATH properties. */
834 flags = fcntl(pathfd_copy, F_GETFL);
835 ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl"));
836 ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH is not set");
837 ATF_REQUIRE_ERRNO(EBADF,
838 read(pathfd_copy, &c, 1) == -1);
839 ATF_REQUIRE_ERRNO(EBADF,
840 write(pathfd_copy, &c, 1) == -1);
842 CHECKED_CLOSE(pathfd);
843 CHECKED_CLOSE(pathfd_copy);
844 CHECKED_CLOSE(sd[0]);
845 CHECKED_CLOSE(sd[1]);
848 /* Verify that a local socket can't be opened with O_PATH. */
849 ATF_TC_WITHOUT_HEAD(path_unix);
850 ATF_TC_BODY(path_unix, tc)
853 struct sockaddr_un sun;
856 snprintf(path, sizeof(path), "path_unix.XXXXXX");
857 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp"));
859 sd = socket(PF_LOCAL, SOCK_STREAM, 0);
860 ATF_REQUIRE_MSG(sd >= 0, FMT_ERR("socket"));
862 memset(&sun, 0, sizeof(sun));
863 sun.sun_family = PF_LOCAL;
864 (void)strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
865 ATF_REQUIRE_MSG(bind(sd, (struct sockaddr *)&sun, SUN_LEN(&sun)) == 0,
868 pathfd = open(path, O_RDONLY);
869 ATF_REQUIRE_ERRNO(EOPNOTSUPP, pathfd < 0);
876 ATF_TP_ADD_TC(tp, path_access);
877 ATF_TP_ADD_TC(tp, path_aio);
878 ATF_TP_ADD_TC(tp, path_capsicum);
879 ATF_TP_ADD_TC(tp, path_coredump);
880 ATF_TP_ADD_TC(tp, path_directory);
881 ATF_TP_ADD_TC(tp, path_directory_not_root);
882 ATF_TP_ADD_TC(tp, path_empty);
883 ATF_TP_ADD_TC(tp, path_empty_not_root);
884 ATF_TP_ADD_TC(tp, path_empty_root);
885 ATF_TP_ADD_TC(tp, path_event);
886 ATF_TP_ADD_TC(tp, path_fcntl);
887 ATF_TP_ADD_TC(tp, path_fexecve);
888 ATF_TP_ADD_TC(tp, path_fifo);
889 ATF_TP_ADD_TC(tp, path_funlinkat);
890 ATF_TP_ADD_TC(tp, path_io);
891 ATF_TP_ADD_TC(tp, path_ioctl);
892 ATF_TP_ADD_TC(tp, path_lock);
893 ATF_TP_ADD_TC(tp, path_rights);
894 ATF_TP_ADD_TC(tp, path_unix);
895 ATF_TP_ADD_TC(tp, path_pipe_fstatat);
897 return (atf_no_error());