13a248c84SMark Johnston /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 33a248c84SMark Johnston * 43a248c84SMark Johnston * Copyright (c) 2021 The FreeBSD Foundation 53a248c84SMark Johnston * 63a248c84SMark Johnston * This software was developed by Mark Johnston under sponsorship from 73a248c84SMark Johnston * the FreeBSD Foundation. 83a248c84SMark Johnston * 93a248c84SMark Johnston * Redistribution and use in source and binary forms, with or without 103a248c84SMark Johnston * modification, are permitted provided that the following conditions are 113a248c84SMark Johnston * met: 123a248c84SMark Johnston * 1. Redistributions of source code must retain the above copyright 133a248c84SMark Johnston * notice, this list of conditions and the following disclaimer. 143a248c84SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 153a248c84SMark Johnston * notice, this list of conditions and the following disclaimer in 163a248c84SMark Johnston * the documentation and/or other materials provided with the distribution. 173a248c84SMark Johnston * 183a248c84SMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 193a248c84SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 203a248c84SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 213a248c84SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 223a248c84SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 233a248c84SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 243a248c84SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 253a248c84SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 263a248c84SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 273a248c84SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 283a248c84SMark Johnston * SUCH DAMAGE. 293a248c84SMark Johnston */ 303a248c84SMark Johnston 313a248c84SMark Johnston /* 323a248c84SMark Johnston * Basic regression tests for handling of O_PATH descriptors. 333a248c84SMark Johnston */ 343a248c84SMark Johnston 353a248c84SMark Johnston #include <sys/param.h> 363a248c84SMark Johnston #include <sys/capsicum.h> 373a248c84SMark Johnston #include <sys/event.h> 383a248c84SMark Johnston #include <sys/ioctl.h> 393a248c84SMark Johnston #include <sys/memrange.h> 403a248c84SMark Johnston #include <sys/mman.h> 41b59851e9SMark Johnston #include <sys/ptrace.h> 423a248c84SMark Johnston #include <sys/socket.h> 433a248c84SMark Johnston #include <sys/stat.h> 443a248c84SMark Johnston #include <sys/time.h> 453a248c84SMark Johnston #include <sys/uio.h> 46b59851e9SMark Johnston #include <sys/un.h> 473a248c84SMark Johnston #include <sys/wait.h> 483a248c84SMark Johnston 493a248c84SMark Johnston #include <aio.h> 503a248c84SMark Johnston #include <dirent.h> 513a248c84SMark Johnston #include <errno.h> 523a248c84SMark Johnston #include <fcntl.h> 533a248c84SMark Johnston #include <poll.h> 54b59851e9SMark Johnston #include <signal.h> 553a248c84SMark Johnston #include <stdio.h> 563a248c84SMark Johnston #include <stdlib.h> 573a248c84SMark Johnston #include <unistd.h> 583a248c84SMark Johnston 593a248c84SMark Johnston #include <atf-c.h> 603a248c84SMark Johnston 613a248c84SMark Johnston #define FMT_ERR(s) s ": %s", strerror(errno) 623a248c84SMark Johnston 633a248c84SMark Johnston #define CHECKED_CLOSE(fd) \ 643a248c84SMark Johnston ATF_REQUIRE_MSG(close(fd) == 0, FMT_ERR("close")) 653a248c84SMark Johnston 663a248c84SMark Johnston /* Create a temporary regular file containing some data. */ 673a248c84SMark Johnston static void 683a248c84SMark Johnston mktfile(char path[PATH_MAX], const char *template) 693a248c84SMark Johnston { 703a248c84SMark Johnston char buf[BUFSIZ]; 713a248c84SMark Johnston int fd; 723a248c84SMark Johnston 733a248c84SMark Johnston snprintf(path, PATH_MAX, "%s", template); 743a248c84SMark Johnston fd = mkstemp(path); 753a248c84SMark Johnston ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkstemp")); 763a248c84SMark Johnston memset(buf, 0, sizeof(buf)); 773a248c84SMark Johnston ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf), 783a248c84SMark Johnston FMT_ERR("write")); 793a248c84SMark Johnston CHECKED_CLOSE(fd); 803a248c84SMark Johnston } 813a248c84SMark Johnston 823a248c84SMark Johnston /* Make a temporary directory. */ 833a248c84SMark Johnston static void 843a248c84SMark Johnston mktdir(char path[PATH_MAX], const char *template) 853a248c84SMark Johnston { 863a248c84SMark Johnston snprintf(path, PATH_MAX, "%s", template); 873a248c84SMark Johnston ATF_REQUIRE_MSG(mkdtemp(path) == path, FMT_ERR("mkdtemp")); 883a248c84SMark Johnston } 893a248c84SMark Johnston 903a248c84SMark Johnston /* Wait for a child process to exit with status 0. */ 913a248c84SMark Johnston static void 923a248c84SMark Johnston waitchild(pid_t child, int exstatus) 933a248c84SMark Johnston { 943a248c84SMark Johnston int error, status; 953a248c84SMark Johnston 963a248c84SMark Johnston error = waitpid(child, &status, 0); 973a248c84SMark Johnston ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid")); 983a248c84SMark Johnston ATF_REQUIRE_MSG(WIFEXITED(status), "child exited abnormally, status %d", 993a248c84SMark Johnston status); 1003a248c84SMark Johnston ATF_REQUIRE_MSG(WEXITSTATUS(status) == exstatus, 1013a248c84SMark Johnston "child exit status is %d, expected %d", 1023a248c84SMark Johnston WEXITSTATUS(status), exstatus); 1033a248c84SMark Johnston } 1043a248c84SMark Johnston 1053a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_access); 1063a248c84SMark Johnston ATF_TC_BODY(path_access, tc) 1073a248c84SMark Johnston { 1083a248c84SMark Johnston char path[PATH_MAX]; 1093a248c84SMark Johnston struct stat sb; 1103a248c84SMark Johnston struct timespec ts[2]; 1113a248c84SMark Johnston struct timeval tv[2]; 1123a248c84SMark Johnston int pathfd; 1133a248c84SMark Johnston 1143a248c84SMark Johnston mktfile(path, "path_access.XXXXXX"); 1153a248c84SMark Johnston 1163a248c84SMark Johnston pathfd = open(path, O_PATH); 1173a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 1183a248c84SMark Johnston 1193a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0666) == -1); 1203a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fchown(pathfd, getuid(), getgid()) == -1); 1213a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fchflags(pathfd, UF_NODUMP) == -1); 1223a248c84SMark Johnston memset(tv, 0, sizeof(tv)); 1233a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, futimes(pathfd, tv) == -1); 1243a248c84SMark Johnston memset(ts, 0, sizeof(ts)); 1253a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, futimens(pathfd, ts) == -1); 1263a248c84SMark Johnston 1273a248c84SMark Johnston /* fpathconf(2) and fstat(2) are permitted. */ 1283a248c84SMark Johnston ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat")); 1293a248c84SMark Johnston ATF_REQUIRE_MSG(fpathconf(pathfd, _PC_LINK_MAX) != -1, 1303a248c84SMark Johnston FMT_ERR("fpathconf")); 1313a248c84SMark Johnston 1323a248c84SMark Johnston CHECKED_CLOSE(pathfd); 1333a248c84SMark Johnston } 1343a248c84SMark Johnston 1353a248c84SMark Johnston /* Basic tests to verify that AIO operations fail. */ 1363a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_aio); 1373a248c84SMark Johnston ATF_TC_BODY(path_aio, tc) 1383a248c84SMark Johnston { 1393a248c84SMark Johnston struct aiocb aio; 1403a248c84SMark Johnston char buf[BUFSIZ], path[PATH_MAX]; 1413a248c84SMark Johnston int pathfd; 1423a248c84SMark Johnston 1433a248c84SMark Johnston mktfile(path, "path_aio.XXXXXX"); 1443a248c84SMark Johnston 1453a248c84SMark Johnston pathfd = open(path, O_PATH); 1463a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 1473a248c84SMark Johnston 1483a248c84SMark Johnston memset(&aio, 0, sizeof(aio)); 1493a248c84SMark Johnston aio.aio_buf = buf; 1503a248c84SMark Johnston aio.aio_nbytes = sizeof(buf); 1513a248c84SMark Johnston aio.aio_fildes = pathfd; 1523a248c84SMark Johnston aio.aio_offset = 0; 1533a248c84SMark Johnston 1543a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, aio_read(&aio) == -1); 1553a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, aio_write(&aio) == -1); 1563a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_SYNC, &aio) == -1); 1573a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, aio_fsync(O_DSYNC, &aio) == -1); 1583a248c84SMark Johnston 1593a248c84SMark Johnston CHECKED_CLOSE(pathfd); 1603a248c84SMark Johnston } 1613a248c84SMark Johnston 1623a248c84SMark Johnston /* Basic tests to verify that Capsicum restrictions apply to path fds. */ 1633a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_capsicum); 1643a248c84SMark Johnston ATF_TC_BODY(path_capsicum, tc) 1653a248c84SMark Johnston { 1663a248c84SMark Johnston char path[PATH_MAX]; 1673a248c84SMark Johnston cap_rights_t rights; 1683a248c84SMark Johnston int truefd; 1693a248c84SMark Johnston pid_t child; 1703a248c84SMark Johnston 1713a248c84SMark Johnston mktfile(path, "path_capsicum.XXXXXX"); 1723a248c84SMark Johnston 1733a248c84SMark Johnston /* Make sure that filesystem namespace restrictions apply to O_PATH. */ 1743a248c84SMark Johnston child = fork(); 1753a248c84SMark Johnston ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 1763a248c84SMark Johnston if (child == 0) { 1773a248c84SMark Johnston if (cap_enter() != 0) 1783a248c84SMark Johnston _exit(1); 1793a248c84SMark Johnston if (open(path, O_PATH) >= 0) 1803a248c84SMark Johnston _exit(2); 1813a248c84SMark Johnston if (errno != ECAPMODE) 1823a248c84SMark Johnston _exit(3); 1833a248c84SMark Johnston if (open("/usr/bin/true", O_PATH | O_EXEC) >= 0) 1843a248c84SMark Johnston _exit(4); 1853a248c84SMark Johnston if (errno != ECAPMODE) 1863a248c84SMark Johnston _exit(5); 1873a248c84SMark Johnston _exit(0); 1883a248c84SMark Johnston } 1893a248c84SMark Johnston waitchild(child, 0); 1903a248c84SMark Johnston 1913a248c84SMark Johnston /* Make sure that CAP_FEXECVE is required. */ 1923a248c84SMark Johnston child = fork(); 1933a248c84SMark Johnston ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 1943a248c84SMark Johnston if (child == 0) { 1953a248c84SMark Johnston truefd = open("/usr/bin/true", O_PATH | O_EXEC); 1963a248c84SMark Johnston if (truefd < 0) 1973a248c84SMark Johnston _exit(1); 1983a248c84SMark Johnston cap_rights_init(&rights); 1993a248c84SMark Johnston if (cap_rights_limit(truefd, &rights) != 0) 2003a248c84SMark Johnston _exit(2); 2013a248c84SMark Johnston (void)fexecve(truefd, 2023a248c84SMark Johnston (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL}, 2033a248c84SMark Johnston NULL); 2043a248c84SMark Johnston if (errno != ENOTCAPABLE) 2053a248c84SMark Johnston _exit(3); 2063a248c84SMark Johnston _exit(4); 2073a248c84SMark Johnston } 2083a248c84SMark Johnston waitchild(child, 4); 2093a248c84SMark Johnston } 2103a248c84SMark Johnston 211e5e1d9c7SMark Johnston /* 212e5e1d9c7SMark Johnston * Check that a pathfd can be converted to a regular fd using openat() in 213e5e1d9c7SMark Johnston * capability mode, but that rights on the pathfd are respected. 214e5e1d9c7SMark Johnston */ 215e5e1d9c7SMark Johnston ATF_TC_WITHOUT_HEAD(path_capsicum_empty); 216e5e1d9c7SMark Johnston ATF_TC_BODY(path_capsicum_empty, tc) 217e5e1d9c7SMark Johnston { 218e5e1d9c7SMark Johnston char path[PATH_MAX]; 219e5e1d9c7SMark Johnston cap_rights_t rights; 220e5e1d9c7SMark Johnston int dfd, fd, pathfd, pathdfd; 221e5e1d9c7SMark Johnston 222e5e1d9c7SMark Johnston mktfile(path, "path_capsicum.XXXXXX"); 223e5e1d9c7SMark Johnston 224e5e1d9c7SMark Johnston pathdfd = open(".", O_PATH); 225e5e1d9c7SMark Johnston ATF_REQUIRE_MSG(pathdfd >= 0, FMT_ERR("open")); 226e5e1d9c7SMark Johnston pathfd = open(path, O_PATH); 227e5e1d9c7SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 228e5e1d9c7SMark Johnston 229e5e1d9c7SMark Johnston ATF_REQUIRE(cap_enter() == 0); 230e5e1d9c7SMark Johnston 231e5e1d9c7SMark Johnston dfd = openat(pathdfd, "", O_DIRECTORY | O_EMPTY_PATH); 232e5e1d9c7SMark Johnston ATF_REQUIRE(dfd >= 0); 233e5e1d9c7SMark Johnston CHECKED_CLOSE(dfd); 234e5e1d9c7SMark Johnston 235e5e1d9c7SMark Johnston /* 236e5e1d9c7SMark Johnston * CAP_READ and CAP_LOOKUP should be sufficient to open a directory. 237e5e1d9c7SMark Johnston */ 2388d1348f5SEd Maste cap_rights_init(&rights, CAP_READ, CAP_LOOKUP); 239e5e1d9c7SMark Johnston ATF_REQUIRE(cap_rights_limit(pathdfd, &rights) == 0); 240e5e1d9c7SMark Johnston dfd = openat(pathdfd, "", O_DIRECTORY | O_EMPTY_PATH); 241e5e1d9c7SMark Johnston ATF_REQUIRE(dfd >= 0); 242e5e1d9c7SMark Johnston CHECKED_CLOSE(dfd); 243e5e1d9c7SMark Johnston 244e5e1d9c7SMark Johnston /* 245e5e1d9c7SMark Johnston * ... CAP_READ on its own is not. 246e5e1d9c7SMark Johnston */ 247e5e1d9c7SMark Johnston cap_rights_init(&rights, CAP_READ); 248e5e1d9c7SMark Johnston ATF_REQUIRE(cap_rights_limit(pathdfd, &rights) == 0); 249e5e1d9c7SMark Johnston dfd = openat(pathdfd, "", O_DIRECTORY | O_EMPTY_PATH); 250e5e1d9c7SMark Johnston ATF_REQUIRE_ERRNO(ENOTCAPABLE, dfd == -1); 251e5e1d9c7SMark Johnston 252e5e1d9c7SMark Johnston /* 253e5e1d9c7SMark Johnston * Now try with a regular file. 254e5e1d9c7SMark Johnston */ 255e5e1d9c7SMark Johnston fd = openat(pathfd, "", O_RDWR | O_EMPTY_PATH); 256e5e1d9c7SMark Johnston ATF_REQUIRE(fd >= 0); 257e5e1d9c7SMark Johnston CHECKED_CLOSE(fd); 258e5e1d9c7SMark Johnston 2598d1348f5SEd Maste cap_rights_init(&rights, CAP_READ, CAP_LOOKUP, CAP_WRITE); 260e5e1d9c7SMark Johnston ATF_REQUIRE(cap_rights_limit(pathfd, &rights) == 0); 261e5e1d9c7SMark Johnston fd = openat(pathfd, "", O_RDWR | O_EMPTY_PATH | O_APPEND); 262e5e1d9c7SMark Johnston ATF_REQUIRE(fd >= 0); 263e5e1d9c7SMark Johnston CHECKED_CLOSE(fd); 264e5e1d9c7SMark Johnston 265e5e1d9c7SMark Johnston /* 266e5e1d9c7SMark Johnston * CAP_SEEK is needed to open a file for writing without O_APPEND. 267e5e1d9c7SMark Johnston */ 2688d1348f5SEd Maste cap_rights_init(&rights, CAP_READ, CAP_LOOKUP, CAP_WRITE); 269e5e1d9c7SMark Johnston ATF_REQUIRE(cap_rights_limit(pathfd, &rights) == 0); 270e5e1d9c7SMark Johnston fd = openat(pathfd, "", O_RDWR | O_EMPTY_PATH); 271e5e1d9c7SMark Johnston ATF_REQUIRE_ERRNO(ENOTCAPABLE, fd == -1); 272e5e1d9c7SMark Johnston 273e5e1d9c7SMark Johnston /* 274e5e1d9c7SMark Johnston * CAP_LOOKUP isn't sufficient to open a file for reading. 275e5e1d9c7SMark Johnston */ 276e5e1d9c7SMark Johnston cap_rights_init(&rights, CAP_LOOKUP); 277e5e1d9c7SMark Johnston ATF_REQUIRE(cap_rights_limit(pathfd, &rights) == 0); 278e5e1d9c7SMark Johnston fd = openat(pathfd, "", O_RDONLY | O_EMPTY_PATH); 279e5e1d9c7SMark Johnston ATF_REQUIRE_ERRNO(ENOTCAPABLE, fd == -1); 280e5e1d9c7SMark Johnston 281e5e1d9c7SMark Johnston CHECKED_CLOSE(pathfd); 282e5e1d9c7SMark Johnston CHECKED_CLOSE(pathdfd); 283e5e1d9c7SMark Johnston } 284e5e1d9c7SMark Johnston 285b59851e9SMark Johnston /* Make sure that ptrace(PT_COREDUMP) cannot be used to write to a path fd. */ 286b59851e9SMark Johnston ATF_TC_WITHOUT_HEAD(path_coredump); 287b59851e9SMark Johnston ATF_TC_BODY(path_coredump, tc) 288b59851e9SMark Johnston { 289b59851e9SMark Johnston char path[PATH_MAX]; 290b59851e9SMark Johnston struct ptrace_coredump pc; 291b59851e9SMark Johnston int error, pathfd, status; 292b59851e9SMark Johnston pid_t child; 293b59851e9SMark Johnston 294b59851e9SMark Johnston mktdir(path, "path_coredump.XXXXXX"); 295b59851e9SMark Johnston 296b59851e9SMark Johnston child = fork(); 297b59851e9SMark Johnston ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 298b59851e9SMark Johnston if (child == 0) { 299b59851e9SMark Johnston while (true) 300b59851e9SMark Johnston (void)sleep(1); 301b59851e9SMark Johnston } 302b59851e9SMark Johnston 303b59851e9SMark Johnston pathfd = open(path, O_PATH); 304b59851e9SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 305b59851e9SMark Johnston 306b59851e9SMark Johnston error = ptrace(PT_ATTACH, child, 0, 0); 307b59851e9SMark Johnston ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace")); 308b59851e9SMark Johnston error = waitpid(child, &status, 0); 309b59851e9SMark Johnston ATF_REQUIRE_MSG(error != -1, FMT_ERR("waitpid")); 310b59851e9SMark Johnston ATF_REQUIRE_MSG(WIFSTOPPED(status), "unexpected status %d", status); 311b59851e9SMark Johnston 312b59851e9SMark Johnston pc.pc_fd = pathfd; 313b59851e9SMark Johnston pc.pc_flags = 0; 314b59851e9SMark Johnston pc.pc_limit = 0; 315b59851e9SMark Johnston error = ptrace(PT_COREDUMP, child, (void *)&pc, sizeof(pc)); 316b59851e9SMark Johnston ATF_REQUIRE_ERRNO(EBADF, error == -1); 317b59851e9SMark Johnston 318b59851e9SMark Johnston error = ptrace(PT_DETACH, child, 0, 0); 319b59851e9SMark Johnston ATF_REQUIRE_MSG(error == 0, FMT_ERR("ptrace")); 320b59851e9SMark Johnston 321b59851e9SMark Johnston ATF_REQUIRE_MSG(kill(child, SIGKILL) == 0, FMT_ERR("kill")); 322b59851e9SMark Johnston 323b59851e9SMark Johnston CHECKED_CLOSE(pathfd); 324b59851e9SMark Johnston } 325b59851e9SMark Johnston 3263a248c84SMark Johnston /* Verify operations on directory path descriptors. */ 3273a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_directory); 3283a248c84SMark Johnston ATF_TC_BODY(path_directory, tc) 3293a248c84SMark Johnston { 3303a248c84SMark Johnston struct dirent de; 3313a248c84SMark Johnston struct stat sb; 3323a248c84SMark Johnston char path[PATH_MAX]; 3333a248c84SMark Johnston int fd, pathfd; 3343a248c84SMark Johnston 3353a248c84SMark Johnston mktdir(path, "path_directory.XXXXXX"); 3363a248c84SMark Johnston 3373a248c84SMark Johnston pathfd = open(path, O_PATH | O_DIRECTORY); 3383a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 3393a248c84SMark Johnston 3403a248c84SMark Johnston /* Should not be possible to list directory entries. */ 3413a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 3423a248c84SMark Johnston getdirentries(pathfd, (char *)&de, sizeof(de), NULL) == -1); 3433a248c84SMark Johnston 3443a248c84SMark Johnston /* It should be possible to create files under pathfd. */ 3453a248c84SMark Johnston fd = openat(pathfd, "test", O_RDWR | O_CREAT, 0600); 3463a248c84SMark Johnston ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open")); 3473a248c84SMark Johnston ATF_REQUIRE_MSG(fstatat(pathfd, "test", &sb, 0) == 0, 3483a248c84SMark Johnston FMT_ERR("fstatat")); 3493a248c84SMark Johnston CHECKED_CLOSE(fd); 3503a248c84SMark Johnston 3513a248c84SMark Johnston /* ... but doing so requires write access. */ 3523a248c84SMark Johnston if (geteuid() != 0) { 3533a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1); 3543a248c84SMark Johnston ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod")); 3553a248c84SMark Johnston ATF_REQUIRE_ERRNO(EACCES, 3563a248c84SMark Johnston openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0); 3573a248c84SMark Johnston } 3583a248c84SMark Johnston 3593a248c84SMark Johnston /* fchdir(2) is permitted. */ 3603a248c84SMark Johnston ATF_REQUIRE_MSG(fchdir(pathfd) == 0, FMT_ERR("fchdir")); 3613a248c84SMark Johnston 3623a248c84SMark Johnston CHECKED_CLOSE(pathfd); 3633a248c84SMark Johnston } 3643a248c84SMark Johnston 3653a248c84SMark Johnston /* Verify access permission checking for a directory path fd. */ 3663a248c84SMark Johnston ATF_TC_WITH_CLEANUP(path_directory_not_root); 3673a248c84SMark Johnston ATF_TC_HEAD(path_directory_not_root, tc) 3683a248c84SMark Johnston { 3693a248c84SMark Johnston atf_tc_set_md_var(tc, "require.user", "unprivileged"); 3703a248c84SMark Johnston } 3713a248c84SMark Johnston ATF_TC_BODY(path_directory_not_root, tc) 3723a248c84SMark Johnston { 3733a248c84SMark Johnston char path[PATH_MAX]; 3743a248c84SMark Johnston int pathfd; 3753a248c84SMark Johnston 3763a248c84SMark Johnston mktdir(path, "path_directory.XXXXXX"); 3773a248c84SMark Johnston 3783a248c84SMark Johnston pathfd = open(path, O_PATH | O_DIRECTORY); 3793a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 3803a248c84SMark Johnston 3813a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fchmod(pathfd, 0500) == -1); 3823a248c84SMark Johnston ATF_REQUIRE_MSG(chmod(path, 0500) == 0, FMT_ERR("chmod")); 3833a248c84SMark Johnston ATF_REQUIRE_ERRNO(EACCES, 3843a248c84SMark Johnston openat(pathfd, "test2", O_RDWR | O_CREAT, 0600) < 0); 3853a248c84SMark Johnston 3863a248c84SMark Johnston CHECKED_CLOSE(pathfd); 3873a248c84SMark Johnston } 3883a248c84SMark Johnston ATF_TC_CLEANUP(path_directory_not_root, tc) 3893a248c84SMark Johnston { 3903a248c84SMark Johnston } 3913a248c84SMark Johnston 3923a248c84SMark Johnston /* Validate system calls that handle AT_EMPTY_PATH. */ 3933a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_empty); 3943a248c84SMark Johnston ATF_TC_BODY(path_empty, tc) 3953a248c84SMark Johnston { 3963a248c84SMark Johnston char path[PATH_MAX]; 3973a248c84SMark Johnston struct timespec ts[2]; 3983a248c84SMark Johnston struct stat sb; 3993a248c84SMark Johnston int pathfd; 4003a248c84SMark Johnston 4013a248c84SMark Johnston mktfile(path, "path_empty.XXXXXX"); 4023a248c84SMark Johnston 4033a248c84SMark Johnston pathfd = open(path, O_PATH); 4043a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 4053a248c84SMark Johnston 4063a248c84SMark Johnston /* Various *at operations should work on path fds. */ 4073a248c84SMark Johnston ATF_REQUIRE_MSG(faccessat(pathfd, "", F_OK, AT_EMPTY_PATH) == 0, 4083a248c84SMark Johnston FMT_ERR("faccessat")); 4093a248c84SMark Johnston ATF_REQUIRE_MSG(chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == 0, 4103a248c84SMark Johnston FMT_ERR("chflagsat")); 4113a248c84SMark Johnston ATF_REQUIRE_MSG(fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == 0, 4123a248c84SMark Johnston FMT_ERR("fchmodat")); 4133a248c84SMark Johnston ATF_REQUIRE_MSG(fchownat(pathfd, "", getuid(), getgid(), 4143a248c84SMark Johnston AT_EMPTY_PATH) == 0, FMT_ERR("fchownat")); 4153a248c84SMark Johnston ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0, 4163a248c84SMark Johnston FMT_ERR("fstatat")); 4173a248c84SMark Johnston ATF_REQUIRE_MSG(sb.st_size == BUFSIZ, 4183a248c84SMark Johnston "unexpected size %ju", (uintmax_t)sb.st_size); 4193a248c84SMark Johnston memset(ts, 0, sizeof(ts)); 4203a248c84SMark Johnston ATF_REQUIRE_MSG(utimensat(pathfd, "", ts, AT_EMPTY_PATH) == 0, 4213a248c84SMark Johnston FMT_ERR("utimensat")); 4223a248c84SMark Johnston 4233a248c84SMark Johnston CHECKED_CLOSE(pathfd); 4243a248c84SMark Johnston } 4253a248c84SMark Johnston 4263a248c84SMark Johnston /* Verify that various operations on a path fd have access checks. */ 4273a248c84SMark Johnston ATF_TC_WITH_CLEANUP(path_empty_not_root); 4283a248c84SMark Johnston ATF_TC_HEAD(path_empty_not_root, tc) 4293a248c84SMark Johnston { 4303a248c84SMark Johnston atf_tc_set_md_var(tc, "require.user", "unprivileged"); 4313a248c84SMark Johnston } 4323a248c84SMark Johnston ATF_TC_BODY(path_empty_not_root, tc) 4333a248c84SMark Johnston { 4343a248c84SMark Johnston int pathfd; 4353a248c84SMark Johnston 4363a248c84SMark Johnston pathfd = open("/dev/null", O_PATH); 4373a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 4383a248c84SMark Johnston 4393a248c84SMark Johnston ATF_REQUIRE_ERRNO(EPERM, 4403a248c84SMark Johnston chflagsat(pathfd, "", UF_NODUMP, AT_EMPTY_PATH) == -1); 4413a248c84SMark Johnston ATF_REQUIRE_ERRNO(EPERM, 4423a248c84SMark Johnston fchownat(pathfd, "", getuid(), getgid(), AT_EMPTY_PATH) == -1); 4433a248c84SMark Johnston ATF_REQUIRE_ERRNO(EPERM, 4443a248c84SMark Johnston fchmodat(pathfd, "", 0600, AT_EMPTY_PATH) == -1); 4453a248c84SMark Johnston ATF_REQUIRE_ERRNO(EPERM, 4463a248c84SMark Johnston linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) == -1); 4473a248c84SMark Johnston 4483a248c84SMark Johnston CHECKED_CLOSE(pathfd); 4493a248c84SMark Johnston } 4503a248c84SMark Johnston ATF_TC_CLEANUP(path_empty_not_root, tc) 4513a248c84SMark Johnston { 4523a248c84SMark Johnston } 4533a248c84SMark Johnston 4543a248c84SMark Johnston /* Test linkat(2) with AT_EMPTY_PATH, which requires privileges. */ 4553a248c84SMark Johnston ATF_TC_WITH_CLEANUP(path_empty_root); 4563a248c84SMark Johnston ATF_TC_HEAD(path_empty_root, tc) 4573a248c84SMark Johnston { 4583a248c84SMark Johnston atf_tc_set_md_var(tc, "require.user", "root"); 4593a248c84SMark Johnston } 4603a248c84SMark Johnston ATF_TC_BODY(path_empty_root, tc) 4613a248c84SMark Johnston { 4623a248c84SMark Johnston char path[PATH_MAX]; 4633a248c84SMark Johnston struct stat sb, sb2; 4643a248c84SMark Johnston int pathfd; 4653a248c84SMark Johnston 4663a248c84SMark Johnston mktfile(path, "path_empty_root.XXXXXX"); 4673a248c84SMark Johnston 4683a248c84SMark Johnston pathfd = open(path, O_PATH); 4693a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 4703a248c84SMark Johnston ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0, 4713a248c84SMark Johnston FMT_ERR("fstatat")); 4723a248c84SMark Johnston 4733a248c84SMark Johnston ATF_REQUIRE_MSG(linkat(pathfd, "", AT_FDCWD, "test", AT_EMPTY_PATH) == 4743a248c84SMark Johnston 0, FMT_ERR("linkat")); 4753a248c84SMark Johnston ATF_REQUIRE_MSG(fstatat(AT_FDCWD, "test", &sb2, 0) == 0, 4763a248c84SMark Johnston FMT_ERR("fstatat")); 4773a248c84SMark Johnston ATF_REQUIRE_MSG(sb.st_dev == sb2.st_dev, "st_dev mismatch"); 4783a248c84SMark Johnston ATF_REQUIRE_MSG(sb.st_ino == sb2.st_ino, "st_ino mismatch"); 4793a248c84SMark Johnston 4803a248c84SMark Johnston CHECKED_CLOSE(pathfd); 4813a248c84SMark Johnston 4823a248c84SMark Johnston } 4833a248c84SMark Johnston ATF_TC_CLEANUP(path_empty_root, tc) 4843a248c84SMark Johnston { 4853a248c84SMark Johnston } 4863a248c84SMark Johnston 4873a248c84SMark Johnston /* poll(2) never returns an event for path fds, but kevent(2) does. */ 4883a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_event); 4893a248c84SMark Johnston ATF_TC_BODY(path_event, tc) 4903a248c84SMark Johnston { 4913a248c84SMark Johnston char buf[BUFSIZ], path[PATH_MAX]; 4923a248c84SMark Johnston struct kevent ev; 4933a248c84SMark Johnston struct pollfd pollfd; 4943a248c84SMark Johnston int kq, pathfd; 4953a248c84SMark Johnston 4963a248c84SMark Johnston mktfile(path, "path_event.XXXXXX"); 4973a248c84SMark Johnston 4983a248c84SMark Johnston pathfd = open(path, O_PATH); 4993a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 5003a248c84SMark Johnston 5013a248c84SMark Johnston /* poll(2) should return POLLNVAL. */ 5023a248c84SMark Johnston pollfd.fd = pathfd; 5033a248c84SMark Johnston pollfd.events = POLLIN; 5043a248c84SMark Johnston pollfd.revents = 0; 5053a248c84SMark Johnston ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll")); 5063a248c84SMark Johnston ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x", 5073a248c84SMark Johnston pollfd.revents); 5083a248c84SMark Johnston pollfd.events = POLLOUT; 5093a248c84SMark Johnston pollfd.revents = 0; 5103a248c84SMark Johnston ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll")); 5113a248c84SMark Johnston ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x", 5123a248c84SMark Johnston pollfd.revents); 5133a248c84SMark Johnston 5143a248c84SMark Johnston /* Try to get a EVFILT_READ event through a path fd. */ 5153a248c84SMark Johnston kq = kqueue(); 5163a248c84SMark Johnston ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue")); 5173a248c84SMark Johnston EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 5183a248c84SMark Johnston ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 5193a248c84SMark Johnston FMT_ERR("kevent")); 5203a248c84SMark Johnston ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1, 5213a248c84SMark Johnston FMT_ERR("kevent")); 5223a248c84SMark Johnston ATF_REQUIRE_MSG((ev.flags & EV_ERROR) == 0, "EV_ERROR is set"); 5233a248c84SMark Johnston ATF_REQUIRE_MSG(ev.data == sizeof(buf), 5243a248c84SMark Johnston "data is %jd", (intmax_t)ev.data); 5253a248c84SMark Johnston EV_SET(&ev, pathfd, EVFILT_READ, EV_DELETE, 0, 0, 0); 5263a248c84SMark Johnston ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 5273a248c84SMark Johnston FMT_ERR("kevent")); 5283a248c84SMark Johnston 529333f6684SMark Johnston /* Try to get a EVFILT_VNODE/NOTE_DELETE event through a path fd. */ 530333f6684SMark Johnston EV_SET(&ev, pathfd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_DELETE, 0, 531333f6684SMark Johnston 0); 5323a248c84SMark Johnston ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 5333a248c84SMark Johnston FMT_ERR("kevent")); 5343a248c84SMark Johnston ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0, 5353a248c84SMark Johnston FMT_ERR("funlinkat")); 5363a248c84SMark Johnston ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1, 5373a248c84SMark Johnston FMT_ERR("kevent")); 538333f6684SMark Johnston ATF_REQUIRE_MSG(ev.fflags == NOTE_DELETE, 539333f6684SMark Johnston "unexpected fflags %#x", ev.fflags); 5403a248c84SMark Johnston EV_SET(&ev, pathfd, EVFILT_VNODE, EV_DELETE, 0, 0, 0); 5413a248c84SMark Johnston ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 5423a248c84SMark Johnston FMT_ERR("kevent")); 5433a248c84SMark Johnston 5443a248c84SMark Johnston CHECKED_CLOSE(kq); 5453a248c84SMark Johnston CHECKED_CLOSE(pathfd); 5463a248c84SMark Johnston } 5473a248c84SMark Johnston 5483a248c84SMark Johnston /* Check various fcntl(2) operations on a path desriptor. */ 5493a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_fcntl); 5503a248c84SMark Johnston ATF_TC_BODY(path_fcntl, tc) 5513a248c84SMark Johnston { 5523a248c84SMark Johnston char path[PATH_MAX]; 5533a248c84SMark Johnston int flags, pathfd, pathfd2; 5543a248c84SMark Johnston 5553a248c84SMark Johnston mktfile(path, "path_fcntl.XXXXXX"); 5563a248c84SMark Johnston 5573a248c84SMark Johnston pathfd = open(path, O_PATH); 5583a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 5593a248c84SMark Johnston 5603a248c84SMark Johnston /* O_PATH should appear in the fd flags. */ 5613a248c84SMark Johnston flags = fcntl(pathfd, F_GETFL); 5623a248c84SMark Johnston ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl")); 5633a248c84SMark Johnston ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set"); 5643a248c84SMark Johnston 5653a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 5663a248c84SMark Johnston fcntl(pathfd, F_SETFL, flags & ~O_PATH)); 5673a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 5683a248c84SMark Johnston fcntl(pathfd, F_SETFL, flags | O_APPEND)); 5693a248c84SMark Johnston 5703a248c84SMark Johnston /* A dup'ed O_PATH fd had better have O_PATH set too. */ 5713a248c84SMark Johnston pathfd2 = fcntl(pathfd, F_DUPFD, 0); 5723a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("fcntl")); 5733a248c84SMark Johnston flags = fcntl(pathfd2, F_GETFL); 5743a248c84SMark Johnston ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl")); 5753a248c84SMark Johnston ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set"); 5763a248c84SMark Johnston CHECKED_CLOSE(pathfd2); 5773a248c84SMark Johnston 5783a248c84SMark Johnston /* Double check with dup(2). */ 5793a248c84SMark Johnston pathfd2 = dup(pathfd); 5803a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd2 >= 0, FMT_ERR("dup")); 5813a248c84SMark Johnston flags = fcntl(pathfd2, F_GETFL); 5823a248c84SMark Johnston ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl")); 5833a248c84SMark Johnston ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH not set"); 5843a248c84SMark Johnston CHECKED_CLOSE(pathfd2); 5853a248c84SMark Johnston 5863a248c84SMark Johnston /* It should be possible to set O_CLOEXEC. */ 5873a248c84SMark Johnston ATF_REQUIRE_MSG(fcntl(pathfd, F_SETFD, FD_CLOEXEC) == 0, 5883a248c84SMark Johnston FMT_ERR("fcntl")); 5893a248c84SMark Johnston ATF_REQUIRE_MSG(fcntl(pathfd, F_GETFD) == FD_CLOEXEC, 5903a248c84SMark Johnston FMT_ERR("fcntl")); 5913a248c84SMark Johnston 5923a248c84SMark Johnston CHECKED_CLOSE(pathfd); 5933a248c84SMark Johnston } 5943a248c84SMark Johnston 5953a248c84SMark Johnston /* Verify that we can execute a file opened with O_PATH. */ 5963a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_fexecve); 5973a248c84SMark Johnston ATF_TC_BODY(path_fexecve, tc) 5983a248c84SMark Johnston { 5993a248c84SMark Johnston char path[PATH_MAX]; 6003a248c84SMark Johnston pid_t child; 6013a248c84SMark Johnston int fd, pathfd; 6023a248c84SMark Johnston 6033a248c84SMark Johnston child = fork(); 6043a248c84SMark Johnston ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 6053a248c84SMark Johnston if (child == 0) { 6063a248c84SMark Johnston pathfd = open("/usr/bin/true", O_PATH | O_EXEC); 6073a248c84SMark Johnston if (pathfd < 0) 6083a248c84SMark Johnston _exit(1); 6093a248c84SMark Johnston fexecve(pathfd, 6103a248c84SMark Johnston (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL}, 6113a248c84SMark Johnston NULL); 6123a248c84SMark Johnston _exit(2); 6133a248c84SMark Johnston } 6143a248c84SMark Johnston waitchild(child, 0); 6153a248c84SMark Johnston 6163a248c84SMark Johnston /* 6173a248c84SMark Johnston * Also verify that access permissions are checked when opening with 6183a248c84SMark Johnston * O_PATH. 6193a248c84SMark Johnston */ 6203a248c84SMark Johnston snprintf(path, sizeof(path), "path_fexecve.XXXXXX"); 6213a248c84SMark Johnston ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp")); 6223a248c84SMark Johnston 6233a248c84SMark Johnston fd = open(path, O_CREAT | O_RDONLY, 0600); 6243a248c84SMark Johnston ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open")); 6253a248c84SMark Johnston 6263a248c84SMark Johnston pathfd = open(path, O_PATH | O_EXEC); 6273a248c84SMark Johnston ATF_REQUIRE_ERRNO(EACCES, pathfd < 0); 6283a248c84SMark Johnston } 6293a248c84SMark Johnston 630b59851e9SMark Johnston /* Make sure that O_PATH restrictions apply to named pipes as well. */ 631b59851e9SMark Johnston ATF_TC_WITHOUT_HEAD(path_fifo); 632b59851e9SMark Johnston ATF_TC_BODY(path_fifo, tc) 633b59851e9SMark Johnston { 634b59851e9SMark Johnston char path[PATH_MAX], buf[BUFSIZ]; 635b59851e9SMark Johnston struct kevent ev; 636b59851e9SMark Johnston int kq, pathfd; 637b59851e9SMark Johnston 638b59851e9SMark Johnston snprintf(path, sizeof(path), "path_fifo.XXXXXX"); 639b59851e9SMark Johnston ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp")); 640b59851e9SMark Johnston 641b59851e9SMark Johnston ATF_REQUIRE_MSG(mkfifo(path, 0666) == 0, FMT_ERR("mkfifo")); 642b59851e9SMark Johnston 643b59851e9SMark Johnston pathfd = open(path, O_PATH); 644b59851e9SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 645b59851e9SMark Johnston memset(buf, 0, sizeof(buf)); 646b59851e9SMark Johnston ATF_REQUIRE_ERRNO(EBADF, write(pathfd, buf, sizeof(buf))); 647b59851e9SMark Johnston ATF_REQUIRE_ERRNO(EBADF, read(pathfd, buf, sizeof(buf))); 648b59851e9SMark Johnston 649b59851e9SMark Johnston kq = kqueue(); 650b59851e9SMark Johnston ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue")); 651b59851e9SMark Johnston EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 652b59851e9SMark Johnston ATF_REQUIRE_ERRNO(EBADF, kevent(kq, &ev, 1, NULL, 0, NULL) == -1); 653b59851e9SMark Johnston 654b59851e9SMark Johnston CHECKED_CLOSE(pathfd); 655b59851e9SMark Johnston } 656b59851e9SMark Johnston 6573a248c84SMark Johnston /* Files may be unlinked using a path fd. */ 6583a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_funlinkat); 6593a248c84SMark Johnston ATF_TC_BODY(path_funlinkat, tc) 6603a248c84SMark Johnston { 6613a248c84SMark Johnston char path[PATH_MAX]; 6623a248c84SMark Johnston struct stat sb; 6633a248c84SMark Johnston int pathfd; 6643a248c84SMark Johnston 6653a248c84SMark Johnston mktfile(path, "path_rights.XXXXXX"); 6663a248c84SMark Johnston 6673a248c84SMark Johnston pathfd = open(path, O_PATH); 6683a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 6693a248c84SMark Johnston 6703a248c84SMark Johnston ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0, 6713a248c84SMark Johnston FMT_ERR("funlinkat")); 6723a248c84SMark Johnston ATF_REQUIRE_ERRNO(ENOENT, stat(path, &sb) == -1); 6733a248c84SMark Johnston 6743a248c84SMark Johnston CHECKED_CLOSE(pathfd); 6753a248c84SMark Johnston } 6763a248c84SMark Johnston 6773a248c84SMark Johnston /* Verify that various I/O operations fail on an O_PATH descriptor. */ 6783a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_io); 6793a248c84SMark Johnston ATF_TC_BODY(path_io, tc) 6803a248c84SMark Johnston { 6813a248c84SMark Johnston char path[PATH_MAX], path2[PATH_MAX]; 6823a248c84SMark Johnston char buf[BUFSIZ]; 6833a248c84SMark Johnston struct iovec iov; 6848d40ee59SAndrew Turner size_t page_size; 6853a248c84SMark Johnston int error, fd, pathfd, sd[2]; 6863a248c84SMark Johnston 687*749b3b2cSKonstantin Belousov /* It is allowed to create new files with O_PATH. */ 6883a248c84SMark Johnston snprintf(path, sizeof(path), "path_io.XXXXXX"); 6893a248c84SMark Johnston ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp")); 690*749b3b2cSKonstantin Belousov pathfd = open(path, O_PATH | O_CREAT, 0600); 691*749b3b2cSKonstantin Belousov ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open(O_PATH|O_CREAT)")); 692*749b3b2cSKonstantin Belousov /* Ensure that this is indeed O_PATH fd */ 693*749b3b2cSKonstantin Belousov ATF_REQUIRE_ERRNO(EBADF, write(pathfd, path, strlen(path)) == -1); 694*749b3b2cSKonstantin Belousov CHECKED_CLOSE(pathfd); 6953a248c84SMark Johnston 6963a248c84SMark Johnston /* Create a non-empty file for use in the rest of the tests. */ 6973a248c84SMark Johnston mktfile(path, "path_io.XXXXXX"); 6983a248c84SMark Johnston 6993a248c84SMark Johnston pathfd = open(path, O_PATH); 7003a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 7013a248c84SMark Johnston 7023a248c84SMark Johnston /* Make sure that basic I/O operations aren't possible. */ 7033a248c84SMark Johnston iov.iov_base = path; 7043a248c84SMark Johnston iov.iov_len = strlen(path); 7053a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7063a248c84SMark Johnston write(pathfd, iov.iov_base, iov.iov_len) == -1); 7073a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7083a248c84SMark Johnston pwrite(pathfd, iov.iov_base, iov.iov_len, 0) == -1); 7093a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7103a248c84SMark Johnston writev(pathfd, &iov, 1) == -1); 7113a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7123a248c84SMark Johnston pwritev(pathfd, &iov, 1, 0) == -1); 7133a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7143a248c84SMark Johnston read(pathfd, path, 1) == -1); 7153a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7163a248c84SMark Johnston pread(pathfd, path, 1, 0) == -1); 7173a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7183a248c84SMark Johnston readv(pathfd, &iov, 1) == -1); 7193a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7203a248c84SMark Johnston preadv(pathfd, &iov, 1, 0) == -1); 7213a248c84SMark Johnston 7223a248c84SMark Johnston /* copy_file_range() should not be permitted. */ 7233a248c84SMark Johnston mktfile(path2, "path_io.XXXXXX"); 7243a248c84SMark Johnston fd = open(path2, O_RDWR); 7253a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7263a248c84SMark Johnston copy_file_range(fd, NULL, pathfd, NULL, sizeof(buf), 0) == -1); 7273a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7283a248c84SMark Johnston copy_file_range(pathfd, NULL, fd, NULL, sizeof(buf), 0) == -1); 7293a248c84SMark Johnston CHECKED_CLOSE(fd); 7303a248c84SMark Johnston 7313a248c84SMark Johnston /* sendfile() should not be permitted. */ 7323a248c84SMark Johnston ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0, 7333a248c84SMark Johnston FMT_ERR("socketpair")); 7343a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 7353a248c84SMark Johnston sendfile(pathfd, sd[0], 0, 0, NULL, NULL, 0)); 7363a248c84SMark Johnston CHECKED_CLOSE(sd[0]); 7373a248c84SMark Johnston CHECKED_CLOSE(sd[1]); 7383a248c84SMark Johnston 7393a248c84SMark Johnston /* No seeking. */ 7403a248c84SMark Johnston ATF_REQUIRE_ERRNO(ESPIPE, 7413a248c84SMark Johnston lseek(pathfd, 0, SEEK_SET) == -1); 7423a248c84SMark Johnston 7433a248c84SMark Johnston /* No operations on the file extent. */ 7443a248c84SMark Johnston ATF_REQUIRE_ERRNO(EINVAL, 7453a248c84SMark Johnston ftruncate(pathfd, 0) == -1); 7463a248c84SMark Johnston error = posix_fallocate(pathfd, 0, sizeof(buf) * 2); 7473a248c84SMark Johnston ATF_REQUIRE_MSG(error == ESPIPE, "posix_fallocate() returned %d", error); 7483a248c84SMark Johnston error = posix_fadvise(pathfd, 0, sizeof(buf), POSIX_FADV_NORMAL); 7493a248c84SMark Johnston ATF_REQUIRE_MSG(error == ESPIPE, "posix_fadvise() returned %d", error); 7503a248c84SMark Johnston 7513a248c84SMark Johnston /* mmap() is not allowed. */ 7528d40ee59SAndrew Turner page_size = getpagesize(); 7533a248c84SMark Johnston ATF_REQUIRE_ERRNO(ENODEV, 7548d40ee59SAndrew Turner mmap(NULL, page_size, PROT_READ, MAP_SHARED, pathfd, 0) == 7553a248c84SMark Johnston MAP_FAILED); 7563a248c84SMark Johnston ATF_REQUIRE_ERRNO(ENODEV, 7578d40ee59SAndrew Turner mmap(NULL, page_size, PROT_NONE, MAP_SHARED, pathfd, 0) == 7583a248c84SMark Johnston MAP_FAILED); 7593a248c84SMark Johnston ATF_REQUIRE_ERRNO(ENODEV, 7608d40ee59SAndrew Turner mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, pathfd, 0) == 7613a248c84SMark Johnston MAP_FAILED); 7623a248c84SMark Johnston 7633a248c84SMark Johnston /* No fsync() or fdatasync(). */ 7643a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fsync(pathfd) == -1); 7653a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fdatasync(pathfd) == -1); 7663a248c84SMark Johnston 7673a248c84SMark Johnston CHECKED_CLOSE(pathfd); 7683a248c84SMark Johnston } 7693a248c84SMark Johnston 7703a248c84SMark Johnston /* ioctl(2) is not permitted on path fds. */ 7713a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_ioctl); 7723a248c84SMark Johnston ATF_TC_BODY(path_ioctl, tc) 7733a248c84SMark Johnston { 7743a248c84SMark Johnston char path[PATH_MAX]; 7753a248c84SMark Johnston struct mem_extract me; 7763a248c84SMark Johnston int pathfd, val; 7773a248c84SMark Johnston 7783a248c84SMark Johnston mktfile(path, "path_ioctl.XXXXXX"); 7793a248c84SMark Johnston 7803a248c84SMark Johnston /* Standard file descriptor ioctls should fail. */ 7813a248c84SMark Johnston pathfd = open(path, O_PATH); 7823a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 7833a248c84SMark Johnston 7843a248c84SMark Johnston val = 0; 7853a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONBIO, &val) == -1); 7863a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONREAD, &val) == -1); 7873a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONWRITE, &val) == -1); 7883a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, FIONSPACE, &val) == -1); 7893a248c84SMark Johnston 7903a248c84SMark Johnston CHECKED_CLOSE(pathfd); 7913a248c84SMark Johnston 7923a248c84SMark Johnston /* Device ioctls should fail. */ 7933a248c84SMark Johnston pathfd = open("/dev/mem", O_PATH); 7943a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 7953a248c84SMark Johnston 7963a248c84SMark Johnston me.me_vaddr = (uintptr_t)&me; 7973a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, MEM_EXTRACT_PADDR, &me) == -1); 7983a248c84SMark Johnston 7993a248c84SMark Johnston CHECKED_CLOSE(pathfd); 8003a248c84SMark Johnston } 8013a248c84SMark Johnston 8023a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_lock); 8033a248c84SMark Johnston ATF_TC_BODY(path_lock, tc) 8043a248c84SMark Johnston { 8053a248c84SMark Johnston char buf[BUFSIZ], path[PATH_MAX]; 8063a248c84SMark Johnston struct flock flk; 8073a248c84SMark Johnston int fd, pathfd; 8083a248c84SMark Johnston 8093a248c84SMark Johnston snprintf(path, sizeof(path), "path_rights.XXXXXX"); 8103a248c84SMark Johnston fd = mkostemp(path, O_SHLOCK); 8113a248c84SMark Johnston ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("mkostemp")); 8123a248c84SMark Johnston memset(buf, 0, sizeof(buf)); 8133a248c84SMark Johnston ATF_REQUIRE_MSG(write(fd, buf, sizeof(buf)) == sizeof(buf), 8143a248c84SMark Johnston FMT_ERR("write()")); 8153a248c84SMark Johnston 8163a248c84SMark Johnston /* Verify that O_EXLOCK is ignored when combined with O_PATH. */ 8173a248c84SMark Johnston pathfd = open(path, O_PATH | O_EXLOCK); 8183a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 8193a248c84SMark Johnston 8203a248c84SMark Johnston CHECKED_CLOSE(fd); 8213a248c84SMark Johnston 8223a248c84SMark Johnston /* flock(2) is prohibited. */ 8233a248c84SMark Johnston ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH) == -1); 8243a248c84SMark Johnston ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX) == -1); 8253a248c84SMark Johnston ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_SH | LOCK_NB) == -1); 8263a248c84SMark Johnston ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_EX | LOCK_NB) == -1); 8273a248c84SMark Johnston ATF_REQUIRE_ERRNO(EOPNOTSUPP, flock(pathfd, LOCK_UN) == -1); 8283a248c84SMark Johnston 8293a248c84SMark Johnston /* fcntl(2) file locks are prohibited. */ 8303a248c84SMark Johnston memset(&flk, 0, sizeof(flk)); 8313a248c84SMark Johnston flk.l_whence = SEEK_CUR; 8323a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_GETLK, &flk) == -1); 8333a248c84SMark Johnston flk.l_type = F_RDLCK; 8343a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1); 8353a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1); 8363a248c84SMark Johnston flk.l_type = F_WRLCK; 8373a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLK, &flk) == -1); 8383a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, fcntl(pathfd, F_SETLKW, &flk) == -1); 8393a248c84SMark Johnston 8403a248c84SMark Johnston CHECKED_CLOSE(pathfd); 8413a248c84SMark Johnston } 8423a248c84SMark Johnston 843c4c66153SMark Johnston /* 844c4c66153SMark Johnston * Verify fstatat(AT_EMPTY_PATH) on non-regular dirfd. 845c4c66153SMark Johnston * Verify that fstatat(AT_EMPTY_PATH) on NULL path returns EFAULT. 846c4c66153SMark Johnston */ 847c4c66153SMark Johnston ATF_TC_WITHOUT_HEAD(path_pipe_fstatat); 848c4c66153SMark Johnston ATF_TC_BODY(path_pipe_fstatat, tc) 849c4c66153SMark Johnston { 850c4c66153SMark Johnston struct stat sb; 851c4c66153SMark Johnston int fd[2]; 852c4c66153SMark Johnston 853c4c66153SMark Johnston ATF_REQUIRE_MSG(pipe(fd) == 0, FMT_ERR("pipe")); 854c4c66153SMark Johnston ATF_REQUIRE_MSG(fstatat(fd[0], "", &sb, AT_EMPTY_PATH) == 0, 855c4c66153SMark Johnston FMT_ERR("fstatat pipe")); 856c4c66153SMark Johnston ATF_REQUIRE_ERRNO(EFAULT, fstatat(fd[0], NULL, &sb, 857c4c66153SMark Johnston AT_EMPTY_PATH) == -1); 858c4c66153SMark Johnston CHECKED_CLOSE(fd[0]); 859c4c66153SMark Johnston CHECKED_CLOSE(fd[1]); 860c4c66153SMark Johnston } 861c4c66153SMark Johnston 8623a248c84SMark Johnston /* Verify that we can send an O_PATH descriptor over a unix socket. */ 8633a248c84SMark Johnston ATF_TC_WITHOUT_HEAD(path_rights); 8643a248c84SMark Johnston ATF_TC_BODY(path_rights, tc) 8653a248c84SMark Johnston { 8663a248c84SMark Johnston char path[PATH_MAX]; 8673a248c84SMark Johnston struct cmsghdr *cmsg; 8683a248c84SMark Johnston struct msghdr msg; 8693a248c84SMark Johnston struct iovec iov; 8703a248c84SMark Johnston int flags, pathfd, pathfd_copy, sd[2]; 8713a248c84SMark Johnston char c; 8723a248c84SMark Johnston 8733a248c84SMark Johnston ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0, 8743a248c84SMark Johnston FMT_ERR("socketpair")); 8753a248c84SMark Johnston 8763a248c84SMark Johnston mktfile(path, "path_rights.XXXXXX"); 8773a248c84SMark Johnston 8783a248c84SMark Johnston pathfd = open(path, O_PATH); 8793a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 8803a248c84SMark Johnston 8813a248c84SMark Johnston /* Package up the O_PATH and send it over the socket pair. */ 8823a248c84SMark Johnston cmsg = malloc(CMSG_SPACE(sizeof(pathfd))); 8833a248c84SMark Johnston ATF_REQUIRE_MSG(cmsg != NULL, FMT_ERR("malloc")); 8843a248c84SMark Johnston 8853a248c84SMark Johnston cmsg->cmsg_len = CMSG_LEN(sizeof(pathfd)); 8863a248c84SMark Johnston cmsg->cmsg_level = SOL_SOCKET; 8873a248c84SMark Johnston cmsg->cmsg_type = SCM_RIGHTS; 8883a248c84SMark Johnston *(int *)(void *)CMSG_DATA(cmsg) = pathfd; 8893a248c84SMark Johnston 8903a248c84SMark Johnston c = 0; 8913a248c84SMark Johnston iov.iov_base = &c; 8923a248c84SMark Johnston iov.iov_len = 1; 8933a248c84SMark Johnston 8943a248c84SMark Johnston memset(&msg, 0, sizeof(msg)); 8953a248c84SMark Johnston msg.msg_iov = &iov; 8963a248c84SMark Johnston msg.msg_iovlen = 1; 8973a248c84SMark Johnston msg.msg_control = cmsg; 8983a248c84SMark Johnston msg.msg_controllen = CMSG_SPACE(sizeof(pathfd)); 8993a248c84SMark Johnston 9003a248c84SMark Johnston ATF_REQUIRE_MSG(sendmsg(sd[0], &msg, 0) == sizeof(c), 9013a248c84SMark Johnston FMT_ERR("sendmsg")); 9023a248c84SMark Johnston 9033a248c84SMark Johnston /* Grab the pathfd copy from the other end of the pair. */ 9043a248c84SMark Johnston memset(&msg, 0, sizeof(msg)); 9053a248c84SMark Johnston msg.msg_iov = &iov; 9063a248c84SMark Johnston msg.msg_iovlen = 1; 9073a248c84SMark Johnston msg.msg_control = cmsg; 9083a248c84SMark Johnston msg.msg_controllen = CMSG_SPACE(sizeof(pathfd)); 9093a248c84SMark Johnston 9103a248c84SMark Johnston ATF_REQUIRE_MSG(recvmsg(sd[1], &msg, 0) == 1, 9113a248c84SMark Johnston FMT_ERR("recvmsg")); 9123a248c84SMark Johnston pathfd_copy = *(int *)(void *)CMSG_DATA(cmsg); 9133a248c84SMark Johnston ATF_REQUIRE_MSG(pathfd_copy != pathfd, 9143a248c84SMark Johnston "pathfd and pathfd_copy are equal"); 9153a248c84SMark Johnston 9163a248c84SMark Johnston /* Verify that the copy has O_PATH properties. */ 9173a248c84SMark Johnston flags = fcntl(pathfd_copy, F_GETFL); 9183a248c84SMark Johnston ATF_REQUIRE_MSG(flags != -1, FMT_ERR("fcntl")); 9193a248c84SMark Johnston ATF_REQUIRE_MSG((flags & O_PATH) != 0, "O_PATH is not set"); 9203a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 9213a248c84SMark Johnston read(pathfd_copy, &c, 1) == -1); 9223a248c84SMark Johnston ATF_REQUIRE_ERRNO(EBADF, 9233a248c84SMark Johnston write(pathfd_copy, &c, 1) == -1); 9243a248c84SMark Johnston 9253a248c84SMark Johnston CHECKED_CLOSE(pathfd); 9263a248c84SMark Johnston CHECKED_CLOSE(pathfd_copy); 9273a248c84SMark Johnston CHECKED_CLOSE(sd[0]); 9283a248c84SMark Johnston CHECKED_CLOSE(sd[1]); 9293a248c84SMark Johnston } 9303a248c84SMark Johnston 9312bd98269SMark Johnston /* Verify that a local socket can be opened with O_PATH. */ 932b59851e9SMark Johnston ATF_TC_WITHOUT_HEAD(path_unix); 933b59851e9SMark Johnston ATF_TC_BODY(path_unix, tc) 934b59851e9SMark Johnston { 9352bd98269SMark Johnston char buf[BUFSIZ], path[PATH_MAX]; 9362bd98269SMark Johnston struct kevent ev; 937b59851e9SMark Johnston struct sockaddr_un sun; 9382bd98269SMark Johnston struct stat sb; 9392bd98269SMark Johnston int kq, pathfd, sd; 940b59851e9SMark Johnston 941b59851e9SMark Johnston snprintf(path, sizeof(path), "path_unix.XXXXXX"); 942b59851e9SMark Johnston ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp")); 943b59851e9SMark Johnston 944b59851e9SMark Johnston sd = socket(PF_LOCAL, SOCK_STREAM, 0); 945b59851e9SMark Johnston ATF_REQUIRE_MSG(sd >= 0, FMT_ERR("socket")); 946b59851e9SMark Johnston 947b59851e9SMark Johnston memset(&sun, 0, sizeof(sun)); 948b59851e9SMark Johnston sun.sun_family = PF_LOCAL; 949b59851e9SMark Johnston (void)strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 950b59851e9SMark Johnston ATF_REQUIRE_MSG(bind(sd, (struct sockaddr *)&sun, SUN_LEN(&sun)) == 0, 951b59851e9SMark Johnston FMT_ERR("bind")); 952b59851e9SMark Johnston 9538b83b656SMark Johnston pathfd = open(path, O_PATH); 9542bd98269SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 9552bd98269SMark Johnston 9562bd98269SMark Johnston ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0, 9572bd98269SMark Johnston FMT_ERR("fstatat")); 9582bd98269SMark Johnston ATF_REQUIRE_MSG(sb.st_mode & S_IFSOCK, "socket mode %#x", sb.st_mode); 9592bd98269SMark Johnston ATF_REQUIRE_MSG(sb.st_ino != 0, "socket has inode number 0"); 9602bd98269SMark Johnston 9612bd98269SMark Johnston memset(buf, 0, sizeof(buf)); 9622bd98269SMark Johnston ATF_REQUIRE_ERRNO(EBADF, write(pathfd, buf, sizeof(buf))); 9632bd98269SMark Johnston ATF_REQUIRE_ERRNO(EBADF, read(pathfd, buf, sizeof(buf))); 9642bd98269SMark Johnston 9652bd98269SMark Johnston /* kevent() is disallowed with sockets. */ 9662bd98269SMark Johnston kq = kqueue(); 9672bd98269SMark Johnston ATF_REQUIRE_MSG(kq >= 0, FMT_ERR("kqueue")); 9682bd98269SMark Johnston EV_SET(&ev, pathfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 9692bd98269SMark Johnston ATF_REQUIRE_ERRNO(EBADF, kevent(kq, &ev, 1, NULL, 0, NULL) == -1); 9702bd98269SMark Johnston 9712bd98269SMark Johnston /* Should not be able to open a socket without O_PATH. */ 9722bd98269SMark Johnston ATF_REQUIRE_ERRNO(EOPNOTSUPP, openat(pathfd, "", O_EMPTY_PATH) == -1); 9732bd98269SMark Johnston 9742bd98269SMark Johnston ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0, 9752bd98269SMark Johnston FMT_ERR("funlinkat")); 976b59851e9SMark Johnston 977b59851e9SMark Johnston CHECKED_CLOSE(sd); 9782bd98269SMark Johnston CHECKED_CLOSE(pathfd); 979b59851e9SMark Johnston } 980b59851e9SMark Johnston 981b13ac678SMark Johnston /* 982b13ac678SMark Johnston * Check that we can perform operations using an O_PATH fd for an unlinked file. 983b13ac678SMark Johnston */ 984b13ac678SMark Johnston ATF_TC_WITHOUT_HEAD(path_unlinked); 985b13ac678SMark Johnston ATF_TC_BODY(path_unlinked, tc) 986b13ac678SMark Johnston { 987b13ac678SMark Johnston char path[PATH_MAX]; 988b13ac678SMark Johnston struct stat sb; 989b13ac678SMark Johnston int pathfd; 990b13ac678SMark Johnston 991b13ac678SMark Johnston mktfile(path, "path_rights.XXXXXX"); 992b13ac678SMark Johnston 993b13ac678SMark Johnston pathfd = open(path, O_PATH); 994b13ac678SMark Johnston ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 995b13ac678SMark Johnston 996b13ac678SMark Johnston ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0, 997b13ac678SMark Johnston FMT_ERR("fstatat")); 998b13ac678SMark Johnston ATF_REQUIRE(sb.st_nlink == 1); 999b13ac678SMark Johnston ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat")); 1000b13ac678SMark Johnston ATF_REQUIRE(sb.st_nlink == 1); 1001b13ac678SMark Johnston 1002b13ac678SMark Johnston ATF_REQUIRE_MSG(unlink(path) == 0, FMT_ERR("unlink")); 1003b13ac678SMark Johnston 1004b13ac678SMark Johnston ATF_REQUIRE_MSG(fstatat(pathfd, "", &sb, AT_EMPTY_PATH) == 0, 1005b13ac678SMark Johnston FMT_ERR("fstatat")); 1006b13ac678SMark Johnston ATF_REQUIRE(sb.st_nlink == 0); 1007b13ac678SMark Johnston ATF_REQUIRE_MSG(fstat(pathfd, &sb) == 0, FMT_ERR("fstat")); 1008b13ac678SMark Johnston ATF_REQUIRE(sb.st_nlink == 0); 1009b13ac678SMark Johnston 1010b13ac678SMark Johnston CHECKED_CLOSE(pathfd); 1011b13ac678SMark Johnston } 1012b13ac678SMark Johnston 10133a248c84SMark Johnston ATF_TP_ADD_TCS(tp) 10143a248c84SMark Johnston { 10153a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_access); 10163a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_aio); 10173a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_capsicum); 1018e5e1d9c7SMark Johnston ATF_TP_ADD_TC(tp, path_capsicum_empty); 1019b59851e9SMark Johnston ATF_TP_ADD_TC(tp, path_coredump); 10203a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_directory); 10213a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_directory_not_root); 10223a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_empty); 10233a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_empty_not_root); 10243a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_empty_root); 10253a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_event); 10263a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_fcntl); 10273a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_fexecve); 1028b59851e9SMark Johnston ATF_TP_ADD_TC(tp, path_fifo); 10293a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_funlinkat); 10303a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_io); 10313a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_ioctl); 10323a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_lock); 1033c4c66153SMark Johnston ATF_TP_ADD_TC(tp, path_pipe_fstatat); 10343a248c84SMark Johnston ATF_TP_ADD_TC(tp, path_rights); 1035b59851e9SMark Johnston ATF_TP_ADD_TC(tp, path_unix); 1036b13ac678SMark Johnston ATF_TP_ADD_TC(tp, path_unlinked); 10373a248c84SMark Johnston 10383a248c84SMark Johnston return (atf_no_error()); 10393a248c84SMark Johnston } 1040