1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 The FreeBSD Foundation 5 * 6 * This software was developed by Mark Johnston under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are 11 * met: 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. 17 * 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 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * Basic regression tests for handling of O_PATH descriptors. 33 */ 34 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> 40 #include <sys/mman.h> 41 #include <sys/socket.h> 42 #include <sys/stat.h> 43 #include <sys/time.h> 44 #include <sys/uio.h> 45 #include <sys/wait.h> 46 47 #include <aio.h> 48 #include <dirent.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <poll.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <unistd.h> 55 56 #include <atf-c.h> 57 58 #define FMT_ERR(s) s ": %s", strerror(errno) 59 60 #define CHECKED_CLOSE(fd) \ 61 ATF_REQUIRE_MSG(close(fd) == 0, FMT_ERR("close")) 62 63 /* Create a temporary regular file containing some data. */ 64 static void 65 mktfile(char path[PATH_MAX], const char *template) 66 { 67 char buf[BUFSIZ]; 68 int fd; 69 70 snprintf(path, PATH_MAX, "%s", template); 71 fd = mkstemp(path); 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), 75 FMT_ERR("write")); 76 CHECKED_CLOSE(fd); 77 } 78 79 /* Make a temporary directory. */ 80 static void 81 mktdir(char path[PATH_MAX], const char *template) 82 { 83 snprintf(path, PATH_MAX, "%s", template); 84 ATF_REQUIRE_MSG(mkdtemp(path) == path, FMT_ERR("mkdtemp")); 85 } 86 87 /* Wait for a child process to exit with status 0. */ 88 static void 89 waitchild(pid_t child, int exstatus) 90 { 91 int error, status; 92 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", 96 status); 97 ATF_REQUIRE_MSG(WEXITSTATUS(status) == exstatus, 98 "child exit status is %d, expected %d", 99 WEXITSTATUS(status), exstatus); 100 } 101 102 ATF_TC_WITHOUT_HEAD(path_access); 103 ATF_TC_BODY(path_access, tc) 104 { 105 char path[PATH_MAX]; 106 struct stat sb; 107 struct timespec ts[2]; 108 struct timeval tv[2]; 109 int pathfd; 110 111 mktfile(path, "path_access.XXXXXX"); 112 113 pathfd = open(path, O_PATH); 114 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 115 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); 123 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")); 128 129 CHECKED_CLOSE(pathfd); 130 } 131 132 /* Basic tests to verify that AIO operations fail. */ 133 ATF_TC_WITHOUT_HEAD(path_aio); 134 ATF_TC_BODY(path_aio, tc) 135 { 136 struct aiocb aio; 137 char buf[BUFSIZ], path[PATH_MAX]; 138 int pathfd; 139 140 mktfile(path, "path_aio.XXXXXX"); 141 142 pathfd = open(path, O_PATH); 143 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 144 145 memset(&aio, 0, sizeof(aio)); 146 aio.aio_buf = buf; 147 aio.aio_nbytes = sizeof(buf); 148 aio.aio_fildes = pathfd; 149 aio.aio_offset = 0; 150 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); 155 156 CHECKED_CLOSE(pathfd); 157 } 158 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) 162 { 163 char path[PATH_MAX]; 164 cap_rights_t rights; 165 int truefd; 166 pid_t child; 167 168 mktfile(path, "path_capsicum.XXXXXX"); 169 170 /* Make sure that filesystem namespace restrictions apply to O_PATH. */ 171 child = fork(); 172 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 173 if (child == 0) { 174 if (cap_enter() != 0) 175 _exit(1); 176 if (open(path, O_PATH) >= 0) 177 _exit(2); 178 if (errno != ECAPMODE) 179 _exit(3); 180 if (open("/usr/bin/true", O_PATH | O_EXEC) >= 0) 181 _exit(4); 182 if (errno != ECAPMODE) 183 _exit(5); 184 _exit(0); 185 } 186 waitchild(child, 0); 187 188 /* Make sure that CAP_FEXECVE is required. */ 189 child = fork(); 190 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 191 if (child == 0) { 192 truefd = open("/usr/bin/true", O_PATH | O_EXEC); 193 if (truefd < 0) 194 _exit(1); 195 cap_rights_init(&rights); 196 if (cap_rights_limit(truefd, &rights) != 0) 197 _exit(2); 198 (void)fexecve(truefd, 199 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL}, 200 NULL); 201 if (errno != ENOTCAPABLE) 202 _exit(3); 203 _exit(4); 204 } 205 waitchild(child, 4); 206 } 207 208 /* Verify operations on directory path descriptors. */ 209 ATF_TC_WITHOUT_HEAD(path_directory); 210 ATF_TC_BODY(path_directory, tc) 211 { 212 struct dirent de; 213 struct stat sb; 214 char path[PATH_MAX]; 215 int fd, pathfd; 216 217 mktdir(path, "path_directory.XXXXXX"); 218 219 pathfd = open(path, O_PATH | O_DIRECTORY); 220 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 221 222 /* Should not be possible to list directory entries. */ 223 ATF_REQUIRE_ERRNO(EBADF, 224 getdirentries(pathfd, (char *)&de, sizeof(de), NULL) == -1); 225 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, 230 FMT_ERR("fstatat")); 231 CHECKED_CLOSE(fd); 232 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); 239 } 240 241 /* fchdir(2) is permitted. */ 242 ATF_REQUIRE_MSG(fchdir(pathfd) == 0, FMT_ERR("fchdir")); 243 244 CHECKED_CLOSE(pathfd); 245 } 246 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) 250 { 251 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 252 } 253 ATF_TC_BODY(path_directory_not_root, tc) 254 { 255 char path[PATH_MAX]; 256 int pathfd; 257 258 mktdir(path, "path_directory.XXXXXX"); 259 260 pathfd = open(path, O_PATH | O_DIRECTORY); 261 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 262 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); 267 268 CHECKED_CLOSE(pathfd); 269 } 270 ATF_TC_CLEANUP(path_directory_not_root, tc) 271 { 272 } 273 274 /* Validate system calls that handle AT_EMPTY_PATH. */ 275 ATF_TC_WITHOUT_HEAD(path_empty); 276 ATF_TC_BODY(path_empty, tc) 277 { 278 char path[PATH_MAX]; 279 struct timespec ts[2]; 280 struct stat sb; 281 int pathfd; 282 283 mktfile(path, "path_empty.XXXXXX"); 284 285 pathfd = open(path, O_PATH); 286 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 287 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, 298 FMT_ERR("fstatat")); 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")); 304 305 CHECKED_CLOSE(pathfd); 306 } 307 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) 311 { 312 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 313 } 314 ATF_TC_BODY(path_empty_not_root, tc) 315 { 316 int pathfd; 317 318 pathfd = open("/dev/null", O_PATH); 319 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 320 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); 329 330 CHECKED_CLOSE(pathfd); 331 } 332 ATF_TC_CLEANUP(path_empty_not_root, tc) 333 { 334 } 335 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) 339 { 340 atf_tc_set_md_var(tc, "require.user", "root"); 341 } 342 ATF_TC_BODY(path_empty_root, tc) 343 { 344 char path[PATH_MAX]; 345 struct stat sb, sb2; 346 int pathfd; 347 348 mktfile(path, "path_empty_root.XXXXXX"); 349 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, 353 FMT_ERR("fstatat")); 354 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, 358 FMT_ERR("fstatat")); 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"); 361 362 CHECKED_CLOSE(pathfd); 363 364 } 365 ATF_TC_CLEANUP(path_empty_root, tc) 366 { 367 } 368 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) 372 { 373 char buf[BUFSIZ], path[PATH_MAX]; 374 struct kevent ev; 375 struct pollfd pollfd; 376 int kq, pathfd; 377 378 mktfile(path, "path_event.XXXXXX"); 379 380 pathfd = open(path, O_PATH); 381 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 382 383 /* poll(2) should return POLLNVAL. */ 384 pollfd.fd = pathfd; 385 pollfd.events = POLLIN; 386 pollfd.revents = 0; 387 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll")); 388 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x", 389 pollfd.revents); 390 pollfd.events = POLLOUT; 391 pollfd.revents = 0; 392 ATF_REQUIRE_MSG(poll(&pollfd, 1, 0) == 1, FMT_ERR("poll")); 393 ATF_REQUIRE_MSG(pollfd.revents == POLLNVAL, "unexpected revents %x", 394 pollfd.revents); 395 396 /* Try to get a EVFILT_READ event through a path fd. */ 397 kq = kqueue(); 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, 401 FMT_ERR("kevent")); 402 ATF_REQUIRE_MSG(kevent(kq, NULL, 0, &ev, 1, NULL) == 1, 403 FMT_ERR("kevent")); 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, 409 FMT_ERR("kevent")); 410 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, 414 FMT_ERR("kevent")); 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, 418 FMT_ERR("kevent")); 419 EV_SET(&ev, pathfd, EVFILT_VNODE, EV_DELETE, 0, 0, 0); 420 ATF_REQUIRE_MSG(kevent(kq, &ev, 1, NULL, 0, NULL) == 0, 421 FMT_ERR("kevent")); 422 423 CHECKED_CLOSE(kq); 424 CHECKED_CLOSE(pathfd); 425 } 426 427 /* Check various fcntl(2) operations on a path desriptor. */ 428 ATF_TC_WITHOUT_HEAD(path_fcntl); 429 ATF_TC_BODY(path_fcntl, tc) 430 { 431 char path[PATH_MAX]; 432 int flags, pathfd, pathfd2; 433 434 mktfile(path, "path_fcntl.XXXXXX"); 435 436 pathfd = open(path, O_PATH); 437 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 438 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"); 443 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)); 448 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); 456 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); 464 465 /* It should be possible to set O_CLOEXEC. */ 466 ATF_REQUIRE_MSG(fcntl(pathfd, F_SETFD, FD_CLOEXEC) == 0, 467 FMT_ERR("fcntl")); 468 ATF_REQUIRE_MSG(fcntl(pathfd, F_GETFD) == FD_CLOEXEC, 469 FMT_ERR("fcntl")); 470 471 CHECKED_CLOSE(pathfd); 472 } 473 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) 477 { 478 char path[PATH_MAX]; 479 pid_t child; 480 int fd, pathfd; 481 482 child = fork(); 483 ATF_REQUIRE_MSG(child != -1, FMT_ERR("fork")); 484 if (child == 0) { 485 pathfd = open("/usr/bin/true", O_PATH | O_EXEC); 486 if (pathfd < 0) 487 _exit(1); 488 fexecve(pathfd, 489 (char * const[]){__DECONST(char *, "/usr/bin/true"), NULL}, 490 NULL); 491 _exit(2); 492 } 493 waitchild(child, 0); 494 495 /* 496 * Also verify that access permissions are checked when opening with 497 * O_PATH. 498 */ 499 snprintf(path, sizeof(path), "path_fexecve.XXXXXX"); 500 ATF_REQUIRE_MSG(mktemp(path) == path, FMT_ERR("mktemp")); 501 502 fd = open(path, O_CREAT | O_RDONLY, 0600); 503 ATF_REQUIRE_MSG(fd >= 0, FMT_ERR("open")); 504 505 pathfd = open(path, O_PATH | O_EXEC); 506 ATF_REQUIRE_ERRNO(EACCES, pathfd < 0); 507 } 508 509 /* Files may be unlinked using a path fd. */ 510 ATF_TC_WITHOUT_HEAD(path_funlinkat); 511 ATF_TC_BODY(path_funlinkat, tc) 512 { 513 char path[PATH_MAX]; 514 struct stat sb; 515 int pathfd; 516 517 mktfile(path, "path_rights.XXXXXX"); 518 519 pathfd = open(path, O_PATH); 520 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 521 522 ATF_REQUIRE_MSG(funlinkat(AT_FDCWD, path, pathfd, 0) == 0, 523 FMT_ERR("funlinkat")); 524 ATF_REQUIRE_ERRNO(ENOENT, stat(path, &sb) == -1); 525 526 CHECKED_CLOSE(pathfd); 527 } 528 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) 532 { 533 char path[PATH_MAX], path2[PATH_MAX]; 534 char buf[BUFSIZ]; 535 struct iovec iov; 536 int error, fd, pathfd, sd[2]; 537 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); 542 543 /* Create a non-empty file for use in the rest of the tests. */ 544 mktfile(path, "path_io.XXXXXX"); 545 546 pathfd = open(path, O_PATH); 547 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 548 549 /* Make sure that basic I/O operations aren't possible. */ 550 iov.iov_base = path; 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); 568 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); 576 CHECKED_CLOSE(fd); 577 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]); 585 586 /* No seeking. */ 587 ATF_REQUIRE_ERRNO(ESPIPE, 588 lseek(pathfd, 0, SEEK_SET) == -1); 589 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); 597 598 /* mmap() is not allowed. */ 599 ATF_REQUIRE_ERRNO(ENODEV, 600 mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, pathfd, 0) == 601 MAP_FAILED); 602 ATF_REQUIRE_ERRNO(ENODEV, 603 mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_SHARED, pathfd, 0) == 604 MAP_FAILED); 605 ATF_REQUIRE_ERRNO(ENODEV, 606 mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, pathfd, 0) == 607 MAP_FAILED); 608 609 /* No fsync() or fdatasync(). */ 610 ATF_REQUIRE_ERRNO(EBADF, fsync(pathfd) == -1); 611 ATF_REQUIRE_ERRNO(EBADF, fdatasync(pathfd) == -1); 612 613 CHECKED_CLOSE(pathfd); 614 } 615 616 /* ioctl(2) is not permitted on path fds. */ 617 ATF_TC_WITHOUT_HEAD(path_ioctl); 618 ATF_TC_BODY(path_ioctl, tc) 619 { 620 char path[PATH_MAX]; 621 struct mem_extract me; 622 int pathfd, val; 623 624 mktfile(path, "path_ioctl.XXXXXX"); 625 626 /* Standard file descriptor ioctls should fail. */ 627 pathfd = open(path, O_PATH); 628 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 629 630 val = 0; 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); 635 636 CHECKED_CLOSE(pathfd); 637 638 /* Device ioctls should fail. */ 639 pathfd = open("/dev/mem", O_PATH); 640 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 641 642 me.me_vaddr = (uintptr_t)&me; 643 ATF_REQUIRE_ERRNO(EBADF, ioctl(pathfd, MEM_EXTRACT_PADDR, &me) == -1); 644 645 CHECKED_CLOSE(pathfd); 646 } 647 648 ATF_TC_WITHOUT_HEAD(path_lock); 649 ATF_TC_BODY(path_lock, tc) 650 { 651 char buf[BUFSIZ], path[PATH_MAX]; 652 struct flock flk; 653 int fd, pathfd; 654 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), 660 FMT_ERR("write()")); 661 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")); 665 666 CHECKED_CLOSE(fd); 667 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); 674 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); 685 686 CHECKED_CLOSE(pathfd); 687 } 688 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) 692 { 693 char path[PATH_MAX]; 694 struct cmsghdr *cmsg; 695 struct msghdr msg; 696 struct iovec iov; 697 int flags, pathfd, pathfd_copy, sd[2]; 698 char c; 699 700 ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, sd) == 0, 701 FMT_ERR("socketpair")); 702 703 mktfile(path, "path_rights.XXXXXX"); 704 705 pathfd = open(path, O_PATH); 706 ATF_REQUIRE_MSG(pathfd >= 0, FMT_ERR("open")); 707 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")); 711 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; 716 717 c = 0; 718 iov.iov_base = &c; 719 iov.iov_len = 1; 720 721 memset(&msg, 0, sizeof(msg)); 722 msg.msg_iov = &iov; 723 msg.msg_iovlen = 1; 724 msg.msg_control = cmsg; 725 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd)); 726 727 ATF_REQUIRE_MSG(sendmsg(sd[0], &msg, 0) == sizeof(c), 728 FMT_ERR("sendmsg")); 729 730 /* Grab the pathfd copy from the other end of the pair. */ 731 memset(&msg, 0, sizeof(msg)); 732 msg.msg_iov = &iov; 733 msg.msg_iovlen = 1; 734 msg.msg_control = cmsg; 735 msg.msg_controllen = CMSG_SPACE(sizeof(pathfd)); 736 737 ATF_REQUIRE_MSG(recvmsg(sd[1], &msg, 0) == 1, 738 FMT_ERR("recvmsg")); 739 pathfd_copy = *(int *)(void *)CMSG_DATA(cmsg); 740 ATF_REQUIRE_MSG(pathfd_copy != pathfd, 741 "pathfd and pathfd_copy are equal"); 742 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); 751 752 CHECKED_CLOSE(pathfd); 753 CHECKED_CLOSE(pathfd_copy); 754 CHECKED_CLOSE(sd[0]); 755 CHECKED_CLOSE(sd[1]); 756 } 757 758 ATF_TP_ADD_TCS(tp) 759 { 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); 776 777 return (atf_no_error()); 778 } 779