1 /*- 2 * Copyright (c) 2008 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /*- 28 * This regression test attempts to confirm that the flags used at open-time 29 * for a file descriptor properly limit system calls that should be affected 30 * by those flags. Currently: 31 * 32 * System call Policy Tested 33 * __acl_aclcheck_fd(2) any no 34 * __acl_delete_fd(2) any no 35 * __acl_get_fd(2) any no 36 * __acl_set_fd(2) any no 37 * aio_fsync(2) any no 38 * aio_read(2) O_RDONLY or O_RDWR yes 39 * aio_write(2) O_WRONLY or O_RDWR yes 40 * dup(2) any yes 41 * dup2(2) any yes 42 * extattr_delete_fd(2) O_WRONLY or O_RDWR no 43 * extattr_get_fd(2) O_RDONLY or O_RDWR no 44 * extattr_list_fd(2) O_RDONLY or O_RDWR no 45 * extattr_set_fd(2) O_WRONLY or O_RDWR no 46 * fchdir(2) any directory yes 47 * fchflags(2) any yes 48 * fchmod(2) any yes 49 * fchown(2) any yes 50 * flock(2) any yes 51 * fpathconf(2) any yes 52 * fstat(2) any yes 53 * fstatfs(2) any yes 54 * fsync(2) any yes 55 * ftruncate(2) O_WRONLY or O_RDWR yes 56 * futimes(2) any yes 57 * getdents(2) O_RDONLY directory yes 58 * lseek(2) any yes 59 * mmap(2) PROT_READ O_RDONLY or O_RDWR yes 60 * mmap(2) PROT_WRITE O_WRONLY or O_RDWR yes 61 * mmap(2) PROT_WRITE + MAP_PRIV O_RDONLY or O_RDWR yes 62 * mmap(2) PROT_EXEC O_RDONLY or O_RDWR yes 63 * pread(2) O_RDONLY or O_RDWR yes 64 * preadv(2) O_RDONLY or O_RDWR yes 65 * pwrite(2) O_WRONLY or O_RDWR yes 66 * pwritev(2) O_WRONLY or O_RDWR yes 67 * read(2) O_RDONLY or O_RDWR yes 68 * readv(2) O_RDONLY or O_RDWR yes 69 * sendfile(2) O_RDONLY or O_RDWR on file yes 70 * write(2) O_WRONLY or O_RDWR yes 71 * writev(2) O_WRONLY or O_RDWR yes 72 * 73 * These checks do not verify that original permissions would allow the 74 * operation or that open is properly impacted by permissions, just that once 75 * a file descriptor is held, open-time limitations are implemented. 76 * 77 * We do, however, test that directories cannot be opened as writable. 78 * 79 * XXXRW: Arguably we should also test combinations of bits to mmap(2). 80 * 81 * XXXRW: Should verify mprotect() remapping limits. 82 * 83 * XXXRW: kqueue(2)/kevent(2), poll(2), select(2) 84 * 85 * XXXRW: oaio_read(2), oaio_write(2), freebsd6_*(2). 86 * 87 * XXXRW: __mac*(2) 88 * 89 * XXXRW: message queue and shared memory fds? 90 */ 91 92 #include <sys/param.h> 93 #include <sys/mman.h> 94 #include <sys/mount.h> 95 #include <sys/socket.h> 96 #include <sys/stat.h> 97 #include <sys/sysctl.h> 98 #include <sys/uio.h> 99 100 #include <aio.h> 101 #include <dirent.h> 102 #include <err.h> 103 #include <errno.h> 104 #include <fcntl.h> 105 #include <limits.h> 106 #include <stdio.h> 107 #include <stdlib.h> 108 #include <string.h> 109 #include <unistd.h> 110 111 #define PERM_FILE 0644 /* Allow read, write. Someday exec? */ 112 #define PERM_DIR 0755 /* Allow read, write, exec. */ 113 114 /* 115 * Modes to try all tests with. 116 */ 117 static const int file_modes[] = { O_RDONLY, O_WRONLY, O_RDWR, 118 O_RDONLY | O_TRUNC, O_WRONLY | O_TRUNC, O_RDWR | O_TRUNC }; 119 static const int file_modes_count = nitems(file_modes); 120 121 static const int dir_modes[] = { O_RDONLY }; 122 static const int dir_modes_count = nitems(dir_modes); 123 124 static int testnum; 125 static int aio_present; 126 127 static void 128 ok_mode(const char *testname, const char *comment, int mode) 129 { 130 131 testnum++; 132 if (comment == NULL) 133 printf("ok %d - %s # mode 0x%x\n", testnum, testname, mode); 134 else 135 printf("ok %d - %s # mode 0x%x - %s\n", testnum, testname, 136 mode, comment); 137 } 138 139 static void 140 notok_mode(const char *testname, const char *comment, int mode) 141 { 142 143 testnum++; 144 if (comment == NULL) 145 printf("not ok %d - %s # mode 0x%x\n", testnum, testname, 146 mode); 147 else 148 printf("not ok %d - %s # mode 0x%x - %s\n", testnum, testname, 149 mode, comment); 150 } 151 152 /* 153 * Before we get started, confirm that we can't open directories writable. 154 */ 155 static void 156 try_directory_open(const char *testname, const char *directory, 157 int mode, int expected_errno) 158 { 159 int dfd; 160 161 dfd = open(directory, mode); 162 if (dfd >= 0) { 163 if (expected_errno) 164 notok_mode(testname, "opened", mode); 165 else 166 ok_mode(testname, NULL, mode); 167 close(dfd); 168 } else { 169 if (expected_errno && expected_errno == errno) 170 ok_mode(testname, NULL, mode); 171 else if (expected_errno != 0) 172 notok_mode(testname, "wrong errno", mode); 173 else 174 notok_mode(testname, "failed", mode); 175 } 176 } 177 178 static void 179 check_directory_open_modes(const char *directory, const int *modes, 180 int modes_count) 181 { 182 int expected_errno, i, mode; 183 184 /* 185 * Directories should only open with O_RDONLY. Notice that we use 186 * file_modes and not dirmodes. 187 */ 188 for (i = 0; i < modes_count; i++) { 189 mode = modes[i]; 190 if (mode == O_RDONLY) 191 expected_errno = 0; 192 else 193 expected_errno = EISDIR; 194 try_directory_open(__func__, directory, mode, 195 expected_errno); 196 } 197 } 198 199 static void 200 check_dup(const char *testname, const char *path, const int *modes, 201 int modes_count) 202 { 203 int dfd, fd, i, mode; 204 205 /* 206 * dup() should work regardless of open mode. 207 */ 208 for (i = 0; i < modes_count; i++) { 209 mode = modes[i]; 210 fd = open(path, mode); 211 if (fd < 0) { 212 notok_mode(testname, "open", mode); 213 continue; 214 } 215 dfd = dup(fd); 216 if (dfd >= 0) { 217 ok_mode(testname, NULL, mode); 218 close(dfd); 219 } else 220 notok_mode(testname, NULL, mode); 221 close(fd); 222 } 223 } 224 225 static void 226 check_dup2(const char *testname, const char *path, const int *modes, 227 int modes_count) 228 { 229 int dfd, fd, i, mode; 230 231 /* 232 * dup2() should work regardless of open mode. 233 */ 234 for (i = 0; i < modes_count; i++) { 235 mode = modes[i]; 236 fd = open(path, mode); 237 if (fd < 0) { 238 notok_mode(testname, "open", mode); 239 continue; 240 } 241 dfd = dup2(fd, 500); /* Arbitrary but high number. */ 242 if (dfd >= 0) { 243 ok_mode(testname, NULL, mode); 244 close(dfd); 245 } else 246 notok_mode(testname, NULL, mode); 247 close(fd); 248 } 249 } 250 251 static void 252 check_fchdir(const char *testname, const char *path, const int *modes, 253 int modes_count) 254 { 255 int fd, i, mode; 256 257 /* 258 * fchdir() should work regardless of open mode. 259 */ 260 for (i = 0; i < modes_count; i++) { 261 mode = modes[i]; 262 fd = open(path, mode); 263 if (fd < 0) { 264 notok_mode(testname, "open", mode); 265 continue; 266 } 267 if (fchdir(fd) == 0) 268 ok_mode(testname, NULL, mode); 269 else 270 notok_mode(testname, "failed", mode); 271 close(fd); 272 } 273 } 274 275 static void 276 check_fchflags(const char *testname, const char *path, const int *modes, 277 int modes_count) 278 { 279 int fd, i, mode; 280 281 /* 282 * fchflags() should work regardless of open mode. 283 */ 284 for (i = 0; i < modes_count; i++) { 285 mode = modes[i]; 286 fd = open(path, mode); 287 if (fd < 0) { 288 notok_mode(testname, "open", mode); 289 continue; 290 } 291 if (fchflags(fd, UF_NODUMP) == 0) 292 ok_mode(testname, NULL, mode); 293 else 294 notok_mode(testname, "failed", mode); 295 close(fd); 296 } 297 } 298 299 static void 300 check_fchmod(const char *testname, const char *path, int setmode, 301 const int *modes, int modes_count) 302 { 303 int fd, i, mode; 304 305 /* 306 * fchmod() should work regardless of open mode. 307 */ 308 for (i = 0; i < modes_count; i++) { 309 mode = modes[i]; 310 fd = open(path, mode); 311 if (fd < 0) { 312 notok_mode(testname, "open", mode); 313 continue; 314 } 315 if (fchmod(fd, setmode) == 0) 316 ok_mode(testname, NULL, mode); 317 else 318 notok_mode(testname, "failed", mode); 319 close(fd); 320 } 321 } 322 323 static void 324 check_fchown(const char *testname, const char *path, const int *modes, 325 int modes_count) 326 { 327 int fd, i, mode; 328 329 /* 330 * fchown() should work regardless of open mode. 331 */ 332 for (i = 0; i < modes_count; i++) { 333 mode = modes[i]; 334 fd = open(path, mode); 335 if (fd < 0) { 336 notok_mode(testname, "open", mode); 337 continue; 338 } 339 if (fchown(fd, -1, -1) == 0) 340 ok_mode(testname, NULL, mode); 341 else 342 notok_mode(testname, "failed", mode); 343 close(fd); 344 } 345 } 346 347 static void 348 check_flock(const char *testname, const char *path, const int *modes, 349 int modes_count) 350 { 351 int fd, i, mode; 352 353 /* 354 * flock() should work regardless of open mode. 355 */ 356 for (i = 0; i < modes_count; i++) { 357 mode = modes[i]; 358 fd = open(path, mode); 359 if (fd < 0) { 360 notok_mode(testname, "open", mode); 361 continue; 362 } 363 if (flock(fd, LOCK_EX) == 0) 364 ok_mode(testname, NULL, mode); 365 else 366 notok_mode(testname, "failed", mode); 367 close(fd); 368 } 369 } 370 371 static void 372 check_fpathconf(const char *testname, const char *path, const int *modes, 373 int modes_count) 374 { 375 int fd, i, mode; 376 long l; 377 378 /* 379 * fpathconf() should work regardless of open mode. 380 */ 381 for (i = 0; i < modes_count; i++) { 382 mode = modes[i]; 383 fd = open(path, mode); 384 if (fd < 0) { 385 notok_mode(testname, "open", mode); 386 continue; 387 } 388 l = fpathconf(fd, _PC_FILESIZEBITS); 389 if (l >= 0) 390 ok_mode(testname, NULL, mode); 391 else 392 notok_mode(testname, "failed", mode); 393 close(fd); 394 } 395 } 396 397 static void 398 check_fstat(const char *testname, const char *path, const int *modes, 399 int modes_count) 400 { 401 struct stat sb; 402 int fd, i, mode; 403 404 /* 405 * fstat() should work regardless of open mode. 406 */ 407 for (i = 0; i < modes_count; i++) { 408 mode = modes[i]; 409 fd = open(path, mode); 410 if (fd < 0) { 411 notok_mode(testname, "open", mode); 412 continue; 413 } 414 if (fstat(fd, &sb) == 0) 415 ok_mode(testname, NULL, mode); 416 else 417 notok_mode(testname, "failed", mode); 418 close(fd); 419 } 420 } 421 422 static void 423 check_fstatfs(const char *testname, const char *path, const int *modes, 424 int modes_count) 425 { 426 struct statfs statfs; 427 int fd, i, mode; 428 429 /* 430 * fstatfs() should work regardless of open mode. 431 */ 432 for (i = 0; i < modes_count; i++) { 433 mode = modes[i]; 434 fd = open(path, mode); 435 if (fd < 0) { 436 notok_mode(testname, "open", mode); 437 continue; 438 } 439 if (fstatfs(fd, &statfs) == 0) 440 ok_mode(testname, NULL, mode); 441 else 442 notok_mode(testname, "failed", mode); 443 close(fd); 444 } 445 } 446 447 static void 448 check_fsync(const char *testname, const char *path, const int *modes, 449 int modes_count) 450 { 451 int fd, i, mode; 452 453 /* 454 * fstatfs() should work regardless of open mode. 455 */ 456 for (i = 0; i < modes_count; i++) { 457 mode = modes[i]; 458 fd = open(path, mode); 459 if (fd < 0) { 460 notok_mode(testname, "open", mode); 461 continue; 462 } 463 if (fsync(fd) == 0) 464 ok_mode(testname, NULL, mode); 465 else 466 notok_mode(testname, "failed", mode); 467 close(fd); 468 } 469 } 470 471 static void 472 check_ftruncate(const char *testname, const char *path, const int *modes, 473 int modes_count) 474 { 475 struct stat sb; 476 int fd, i, mode; 477 478 /* 479 * ftruncate() should work as long as long as (mode & O_ACCMODE) is 480 * O_RDWR or O_WRONLY. 481 * 482 * Directories should never be writable, so this test should always 483 * pass for directories... 484 */ 485 for (i = 0; i < modes_count; i++) { 486 mode = modes[i]; 487 fd = open(path, mode); 488 if (fd < 0) { 489 notok_mode(testname, "open", mode); 490 notok_mode(testname, "truncate1 skipped", mode); 491 notok_mode(testname, "truncate2 skipped", mode); 492 notok_mode(testname, "truncate3 skipped", mode); 493 continue; 494 } 495 if (fstat(fd, &sb) < 0) { 496 notok_mode(testname, "fstat", mode); 497 notok_mode(testname, "truncate1 skipped", mode); 498 notok_mode(testname, "truncate2 skipped", mode); 499 notok_mode(testname, "truncate3 skipped", mode); 500 close(fd); 501 continue; 502 } 503 ok_mode(testname, "setup", mode); 504 505 /* Truncate to grow file. */ 506 if (ftruncate(fd, sb.st_size + 1) == 0) { 507 if (((mode & O_ACCMODE) == O_WRONLY) || 508 ((mode & O_ACCMODE) == O_RDWR)) 509 ok_mode(testname, "truncate1 succeeded", 510 mode); 511 else { 512 notok_mode(testname, "truncate1 succeeded", 513 mode); 514 notok_mode(testname, "truncate2 skipped", 515 mode); 516 notok_mode(testname, "truncate3 skipped", 517 mode); 518 close(fd); 519 continue; 520 } 521 } else { 522 if (((mode & O_ACCMODE) == O_WRONLY) || 523 ((mode & O_ACCMODE) == O_RDWR)) { 524 notok_mode(testname, "truncate1 failed", 525 mode); 526 notok_mode(testname, "truncate2 skipped", 527 mode); 528 notok_mode(testname, "truncate3 skipped", 529 mode); 530 close(fd); 531 continue; 532 } else 533 ok_mode(testname, "truncate1 failed", mode); 534 } 535 536 /* Truncate to same size. */ 537 if (ftruncate(fd, sb.st_size + 1) == 0) { 538 if (((mode & O_ACCMODE) == O_WRONLY) || 539 ((mode & O_ACCMODE) == O_RDWR)) 540 ok_mode(testname, "truncate2 succeeded", 541 mode); 542 else { 543 notok_mode(testname, "truncate2 succeeded", 544 mode); 545 notok_mode(testname, "truncate3 skipped", 546 mode); 547 close(fd); 548 continue; 549 } 550 } else { 551 if (((mode & O_ACCMODE) == O_WRONLY) || 552 ((mode & O_ACCMODE) == O_RDWR)) { 553 notok_mode(testname, "truncate2 failed", 554 mode); 555 notok_mode(testname, "truncate3 skipped", 556 mode); 557 close(fd); 558 continue; 559 } else 560 ok_mode(testname, "truncate2 failed", mode); 561 } 562 563 /* Truncate to shrink. */ 564 if (ftruncate(fd, sb.st_size) == 0) { 565 if (((mode & O_ACCMODE) == O_WRONLY) || 566 ((mode & O_ACCMODE) == O_RDWR)) 567 ok_mode(testname, "truncate3 succeeded", 568 mode); 569 else 570 notok_mode(testname, "truncate3 succeeded", 571 mode); 572 } else { 573 if (((mode & O_ACCMODE) == O_WRONLY) || 574 ((mode & O_ACCMODE) == O_RDWR)) 575 notok_mode(testname, "truncate3 failed", 576 mode); 577 else 578 ok_mode(testname, "truncate3 failed", mode); 579 } 580 close(fd); 581 } 582 } 583 584 static void 585 check_futimes(const char *testname, const char *path, const int *modes, 586 int modes_count) 587 { 588 int fd, i, mode; 589 590 /* 591 * futimes() should work regardless of open mode. 592 */ 593 for (i = 0; i < modes_count; i++) { 594 mode = modes[i]; 595 fd = open(path, mode); 596 if (fd < 0) { 597 notok_mode(testname, "open", mode); 598 continue; 599 } 600 if (futimes(fd, NULL) == 0) 601 ok_mode(testname, NULL, mode); 602 else 603 notok_mode(testname, "failed", mode); 604 close(fd); 605 } 606 } 607 608 static void 609 check_lseek(const char *testname, const char *path, const int *modes, 610 int modes_count) 611 { 612 int fd, i, mode; 613 614 /* 615 * lseek() should work regardless of open mode. 616 */ 617 for (i = 0; i < modes_count; i++) { 618 mode = modes[i]; 619 fd = open(path, mode); 620 if (fd < 0) { 621 notok_mode(testname, "open", mode); 622 continue; 623 } 624 if (lseek(fd, 100, SEEK_SET) == 100) 625 ok_mode(testname, NULL, mode); 626 else 627 notok_mode(testname, "failed", mode); 628 close(fd); 629 } 630 } 631 632 static void 633 check_getdents(const char *testname, const char *path, int isdir, 634 const int *modes, int modes_count) 635 { 636 int fd, i, mode; 637 char buf[8192]; 638 639 /* 640 * getdents() should always work on directories and never on files, 641 * assuming directories are always opened for read (which they are). 642 */ 643 for (i = 0; i < modes_count; i++) { 644 mode = modes[i]; 645 fd = open(path, mode); 646 if (fd < 0) { 647 notok_mode(testname, "open", mode); 648 continue; 649 } 650 if (getdents(fd, buf, sizeof(buf)) >= 0) { 651 if (isdir && ((mode & O_ACCMODE) == O_RDONLY)) 652 ok_mode(testname, "directory succeeded", 653 mode); 654 else if (isdir) 655 notok_mode(testname, "directory succeeded", 656 mode); 657 else 658 notok_mode(testname, "file succeeded", mode); 659 } else { 660 if (isdir && ((mode & O_ACCMODE) == O_RDONLY)) 661 notok_mode(testname, "directory failed", 662 mode); 663 else if (isdir) 664 ok_mode(testname, "directory failed", mode); 665 else 666 ok_mode(testname, "file failed", mode); 667 } 668 close(fd); 669 } 670 } 671 672 static void 673 check_sendfile(const char *testname, const char *path, int isdir, 674 const int *modes, int modes_count) 675 { 676 int fd, i, mode, sv[2]; 677 off_t sent; 678 679 /* 680 * sendfile() should work only on files, and only when the access mode 681 * is O_RDONLY or O_RDWR. 682 */ 683 for (i = 0; i < modes_count; i++) { 684 mode = modes[i]; 685 fd = open(path, mode); 686 if (fd < 0) { 687 notok_mode(testname, "open", mode); 688 continue; 689 } 690 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) < 0) { 691 notok_mode(testname, "socketpair", mode); 692 continue; 693 } 694 if (sendfile(fd, sv[0], 0, 1, NULL, &sent, 0) == 0) { 695 if (isdir) 696 notok_mode(testname, "directory succeeded", 697 mode); 698 else if (((mode & O_ACCMODE) == O_RDONLY) || 699 ((mode & O_ACCMODE) == O_RDWR)) 700 ok_mode(testname, "succeeded", mode); 701 else 702 notok_mode(testname, "succeeded", mode); 703 } else { 704 if (isdir) 705 ok_mode(testname, "directory failed", mode); 706 else if (((mode & O_ACCMODE) == O_RDONLY) || 707 ((mode & O_ACCMODE) == O_RDWR)) 708 notok_mode(testname, "failed", mode); 709 else 710 ok_mode(testname, "failed", mode); 711 } 712 close(sv[0]); 713 close(sv[1]); 714 close(fd); 715 } 716 } 717 718 /* 719 * Various functions write, so just make write-like wrappers for them. 720 */ 721 typedef ssize_t (*write_fn)(int d, const void *buf, size_t nbytes); 722 723 static ssize_t 724 writev_wrapper(int d, const void *buf, size_t nbytes) 725 { 726 struct iovec iov; 727 728 iov.iov_base = (void *)buf; 729 iov.iov_len = nbytes; 730 return (writev(d, &iov, 1)); 731 } 732 733 static ssize_t 734 pwrite_wrapper(int d, const void *buf, size_t nbytes) 735 { 736 737 return (pwrite(d, buf, nbytes, 0)); 738 } 739 740 static ssize_t 741 pwritev_wrapper(int d, const void *buf, size_t nbytes) 742 { 743 struct iovec iov; 744 745 iov.iov_base = (void *)buf; 746 iov.iov_len = nbytes; 747 return (pwritev(d, &iov, 1, 0)); 748 } 749 750 static ssize_t 751 aio_write_wrapper(int d, const void *buf, size_t nbytes) 752 { 753 struct aiocb aiocb; 754 struct aiocb const *aiocb_array[] = { &aiocb }; 755 756 bzero(&aiocb, sizeof(aiocb)); 757 aiocb.aio_fildes = d; 758 aiocb.aio_buf = (void *)buf; 759 aiocb.aio_nbytes = nbytes; 760 if (aio_write(&aiocb) < 0) 761 return (-1); 762 aiocb_array[0] = &aiocb; 763 if (aio_suspend(aiocb_array, 1, NULL) < 0) 764 return (-1); 765 return (aio_return(&aiocb)); 766 } 767 768 static void 769 check_write(const char *testname, write_fn fn, const char *path, 770 const int *modes, int modes_count) 771 { 772 int fd, i, mode; 773 char ch; 774 775 /* 776 * write() should never succeed for directories, but especially 777 * because they can only be opened read-only. write() on files 778 * should succeed for O_WRONLY and O_RDWR descriptors. 779 */ 780 781 for (i = 0; i < modes_count; i++) { 782 mode = modes[i]; 783 fd = open(path, mode); 784 if (fd < 0) { 785 notok_mode(testname, "open", mode); 786 continue; 787 } 788 if (fn(fd, &ch, sizeof(ch)) < 0) { 789 if ((mode & O_ACCMODE) == O_WRONLY || 790 (mode & O_ACCMODE) == O_RDWR) 791 notok_mode(testname, "write failed", mode); 792 else 793 ok_mode(testname, "write failed", mode); 794 } else { 795 if (!((mode & O_ACCMODE) == O_WRONLY || 796 (mode & O_ACCMODE) == O_RDWR)) 797 notok_mode(testname, "write succeeded", mode); 798 else 799 ok_mode(testname, "write succeeded", mode); 800 } 801 close(fd); 802 } 803 } 804 805 /* 806 * Various functions read, so just make read-like wrappers for them. 807 */ 808 typedef ssize_t (*read_fn)(int d, void *buf, size_t nbytes); 809 810 static ssize_t 811 readv_wrapper(int d, void *buf, size_t nbytes) 812 { 813 struct iovec iov; 814 815 iov.iov_base = buf; 816 iov.iov_len = nbytes; 817 return (readv(d, &iov, 1)); 818 } 819 820 static ssize_t 821 pread_wrapper(int d, void *buf, size_t nbytes) 822 { 823 824 return (pread(d, buf, nbytes, 0)); 825 } 826 827 static ssize_t 828 preadv_wrapper(int d, void *buf, size_t nbytes) 829 { 830 struct iovec iov; 831 832 iov.iov_base = buf; 833 iov.iov_len = nbytes; 834 return (preadv(d, &iov, 1, 0)); 835 } 836 837 static ssize_t 838 aio_read_wrapper(int d, void *buf, size_t nbytes) 839 { 840 struct aiocb aiocb; 841 struct aiocb const *aiocb_array[] = { &aiocb }; 842 843 bzero(&aiocb, sizeof(aiocb)); 844 aiocb.aio_fildes = d; 845 aiocb.aio_buf = buf; 846 aiocb.aio_nbytes = nbytes; 847 if (aio_read(&aiocb) < 0) 848 return (-1); 849 if (aio_suspend(aiocb_array, 1, NULL) < 0) 850 return (-1); 851 return (aio_return(&aiocb)); 852 } 853 854 static void 855 check_read(const char *testname, read_fn fn, const char *path, 856 const int *modes, int modes_count) 857 { 858 int fd, i, mode; 859 char ch; 860 861 /* 862 * read() should (generally) succeeded on directories. read() on 863 * files should succeed for O_RDONLY and O_RDWR descriptors. 864 */ 865 for (i = 0; i < modes_count; i++) { 866 mode = modes[i]; 867 fd = open(path, mode); 868 if (fd < 0) { 869 notok_mode(testname, "open", mode); 870 continue; 871 } 872 if (fn(fd, &ch, sizeof(ch)) < 0) { 873 if ((mode & O_ACCMODE) == O_RDONLY || 874 (mode & O_ACCMODE) == O_RDWR) 875 notok_mode(testname, "read failed", mode); 876 else 877 ok_mode(testname, "read failed", mode); 878 } else { 879 if (!((mode & O_ACCMODE) == O_RDONLY || 880 (mode & O_ACCMODE) == O_RDWR)) 881 notok_mode(testname, "read succeeded", mode); 882 else 883 ok_mode(testname, "read succeeded", mode); 884 } 885 close(fd); 886 } 887 } 888 889 static void 890 check_mmap_read(const char *testname, const char *path, int isdir, 891 const int *modes, int modes_count) 892 { 893 int fd, i, mode; 894 char *addr; 895 896 /* 897 * mmap() read should fail for directories (ideally?) but succeed for 898 * O_RDONLY and O_RDWR file descriptors. 899 */ 900 for (i = 0; i < modes_count; i++) { 901 mode = modes[i]; 902 fd = open(path, mode); 903 if (fd < 0) { 904 notok_mode(testname, "open", mode); 905 continue; 906 } 907 addr = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 908 0); 909 if (addr == MAP_FAILED) { 910 if (isdir) 911 ok_mode(testname, "mmap dir failed", mode); 912 else if ((mode & O_ACCMODE) == O_RDONLY || 913 (mode & O_ACCMODE) == O_RDWR) 914 notok_mode(testname, "mmap file failed", 915 mode); 916 else 917 ok_mode(testname, "mmap file failed", mode); 918 } else { 919 if (isdir) 920 notok_mode(testname, "mmap dir succeeded", 921 mode); 922 else if ((mode & O_ACCMODE) == O_RDONLY || 923 (mode & O_ACCMODE) == O_RDWR) 924 ok_mode(testname, "mmap file succeeded", 925 mode); 926 else 927 notok_mode(testname, "mmap file succeeded", 928 mode); 929 (void)munmap(addr, getpagesize()); 930 } 931 close(fd); 932 } 933 } 934 935 static void 936 check_mmap_write(const char *testname, const char *path, const int *modes, 937 int modes_count) 938 { 939 int fd, i, mode; 940 char *addr; 941 942 /* 943 * mmap() will always fail for directories (ideally) as they are 944 * always open O_RDONLY. Check for O_WRONLY or O_RDWR to permit a 945 * write mapping. This variant does a MAP_SHARED mapping, but we 946 * are also interested in MAP_PRIVATE. 947 */ 948 for (i = 0; i < modes_count; i++) { 949 mode = modes[i]; 950 fd = open(path, mode); 951 if (fd < 0) { 952 notok_mode(testname, "open", mode); 953 continue; 954 } 955 addr = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd, 956 0); 957 if (addr == MAP_FAILED) { 958 if ((mode & O_ACCMODE) == O_WRONLY || 959 (mode & O_ACCMODE) == O_RDWR) 960 notok_mode(testname, "mmap failed", 961 mode); 962 else 963 ok_mode(testname, "mmap failed", mode); 964 } else { 965 if ((mode & O_ACCMODE) == O_WRONLY || 966 (mode & O_ACCMODE) == O_RDWR) 967 ok_mode(testname, "mmap succeeded", 968 mode); 969 else 970 notok_mode(testname, "mmap succeeded", mode); 971 (void)munmap(addr, getpagesize()); 972 } 973 close(fd); 974 } 975 } 976 977 static void 978 check_mmap_exec(const char *testname, const char *path, int isdir, 979 const int *modes, int modes_count) 980 { 981 int fd, i, mode; 982 char *addr; 983 984 /* 985 * mmap() exec should fail for directories (ideally?) but succeed for 986 * O_RDONLY and O_RDWR file descriptors. 987 */ 988 for (i = 0; i < modes_count; i++) { 989 mode = modes[i]; 990 fd = open(path, mode); 991 if (fd < 0) { 992 notok_mode(testname, "open", mode); 993 continue; 994 } 995 addr = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd, 996 0); 997 if (addr == MAP_FAILED) { 998 if (isdir) 999 ok_mode(testname, "mmap dir failed", mode); 1000 else if ((mode & O_ACCMODE) == O_RDONLY || 1001 (mode & O_ACCMODE) == O_RDWR) 1002 notok_mode(testname, "mmap file failed", 1003 mode); 1004 else 1005 ok_mode(testname, "mmap file failed", mode); 1006 } else { 1007 if (isdir) 1008 notok_mode(testname, "mmap dir succeeded", 1009 mode); 1010 else 1011 ok_mode(testname, "mmap file succeeded", 1012 mode); 1013 (void)munmap(addr, getpagesize()); 1014 } 1015 close(fd); 1016 } 1017 } 1018 1019 static void 1020 check_mmap_write_private(const char *testname, const char *path, int isdir, 1021 const int *modes, int modes_count) 1022 { 1023 int fd, i, mode; 1024 char *addr; 1025 1026 /* 1027 * mmap() write private should succeed for readable descriptors 1028 * except for directories. 1029 */ 1030 for (i = 0; i < modes_count; i++) { 1031 mode = modes[i]; 1032 fd = open(path, mode); 1033 if (fd < 0) { 1034 notok_mode(testname, "open", mode); 1035 continue; 1036 } 1037 addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, 1038 MAP_PRIVATE, fd, 0); 1039 if (addr == MAP_FAILED) { 1040 if (isdir) 1041 ok_mode(testname, "mmap dir failed", mode); 1042 else if ((mode & O_ACCMODE) == O_RDONLY || 1043 (mode & O_ACCMODE) == O_RDWR) 1044 notok_mode(testname, "mmap file failed", 1045 mode); 1046 else 1047 ok_mode(testname, "mmap file failed", mode); 1048 } else { 1049 if (isdir) 1050 notok_mode(testname, "mmap dir succeeded", 1051 mode); 1052 else if ((mode & O_ACCMODE) == O_RDONLY || 1053 (mode & O_ACCMODE) == O_RDWR) 1054 ok_mode(testname, "mmap file succeeded", 1055 mode); 1056 else 1057 notok_mode(testname, "mmap file succeeded", 1058 mode); 1059 (void)munmap(addr, getpagesize()); 1060 } 1061 close(fd); 1062 } 1063 } 1064 1065 int 1066 main(void) 1067 { 1068 char dir_path[PATH_MAX], file_path[PATH_MAX]; 1069 int dummy, fd; 1070 size_t size; 1071 1072 aio_present = 0; 1073 size = sizeof(dummy); 1074 if (sysctlbyname("vfs.aio", &dummy, &size, NULL, 0) < 0) { 1075 if (errno == EISDIR) 1076 aio_present = 1; 1077 } 1078 1079 strlcpy(dir_path, "/tmp/open-dir.XXXXXXXXXXX", sizeof(dir_path)); 1080 if (mkdtemp(dir_path) == NULL) 1081 err(1, "mkdtemp"); 1082 if (chmod(dir_path, PERM_DIR) < 0) { 1083 warn("chmod %s", dir_path); 1084 (void)rmdir(dir_path); 1085 exit(1); 1086 } 1087 strlcpy(file_path, "/tmp/open-file.XXXXXXXXXXX", sizeof(file_path)); 1088 fd = mkstemp(file_path); 1089 if (fd < 0) { 1090 warn("mkstemp"); 1091 (void)rmdir(dir_path); 1092 exit(1); 1093 } 1094 close(fd); 1095 if (chmod(file_path, PERM_FILE) < 0) { 1096 warn("chmod %s", file_path); 1097 (void)unlink(file_path); 1098 (void)rmdir(dir_path); 1099 exit(1); 1100 } 1101 check_directory_open_modes(dir_path, file_modes, file_modes_count); 1102 1103 check_dup("check_dup_dir", dir_path, dir_modes, dir_modes_count); 1104 check_dup("check_dup_file", file_path, file_modes, file_modes_count); 1105 1106 check_dup2("check_dup2_dir", dir_path, dir_modes, dir_modes_count); 1107 check_dup2("check_dup2_file", file_path, file_modes, 1108 file_modes_count); 1109 1110 check_fchdir("check_fchdir", dir_path, dir_modes, dir_modes_count); 1111 1112 check_fchflags("check_fchflags_dir", dir_path, dir_modes, 1113 dir_modes_count); 1114 check_fchflags("check_fchflags_file", file_path, file_modes, 1115 file_modes_count); 1116 1117 check_fchmod("check_fchmod_dir", dir_path, PERM_DIR, dir_modes, 1118 dir_modes_count); 1119 check_fchmod("check_fchmod_file", file_path, PERM_FILE, file_modes, 1120 file_modes_count); 1121 1122 check_fchown("check_fchown_dir", dir_path, dir_modes, 1123 dir_modes_count); 1124 check_fchown("check_fchown_file", file_path, file_modes, 1125 file_modes_count); 1126 1127 check_flock("check_flock_dir", dir_path, dir_modes, dir_modes_count); 1128 check_flock("check_flock_file", file_path, file_modes, 1129 file_modes_count); 1130 1131 check_fpathconf("check_fpathconf_dir", dir_path, dir_modes, 1132 dir_modes_count); 1133 check_fpathconf("check_fpathconf_file", file_path, file_modes, 1134 file_modes_count); 1135 1136 check_fstat("check_fstat_dir", dir_path, dir_modes, dir_modes_count); 1137 check_fstat("check_fstat_file", file_path, file_modes, 1138 file_modes_count); 1139 1140 check_fstatfs("check_fstatfs_dir", dir_path, dir_modes, 1141 dir_modes_count); 1142 check_fstatfs("check_fstatfs_file", file_path, file_modes, 1143 file_modes_count); 1144 1145 check_fsync("check_fsync_dir", dir_path, dir_modes, dir_modes_count); 1146 check_fsync("check_fsync_file", file_path, file_modes, 1147 file_modes_count); 1148 1149 check_ftruncate("check_ftruncate_dir", dir_path, dir_modes, 1150 dir_modes_count); 1151 check_ftruncate("check_ftruncate_file", file_path, file_modes, 1152 file_modes_count); 1153 1154 check_futimes("check_futimes_dir", dir_path, dir_modes, 1155 dir_modes_count); 1156 check_futimes("check_futimes_file", file_path, file_modes, 1157 file_modes_count); 1158 1159 check_lseek("check_lseek_dir", dir_path, dir_modes, dir_modes_count); 1160 check_lseek("check_lseek_file", file_path, file_modes, 1161 file_modes_count); 1162 1163 check_getdents("check_getdents_dir", dir_path, 1, dir_modes, 1164 dir_modes_count); 1165 check_getdents("check_getdents_file", file_path, 0, file_modes, 1166 file_modes_count); 1167 1168 check_sendfile("check_sendfile_dir", dir_path, 1, dir_modes, 1169 dir_modes_count); 1170 check_sendfile("check_sendfile_file", file_path, 0, file_modes, 1171 file_modes_count); 1172 1173 check_write("check_write_dir", write, dir_path, dir_modes, 1174 dir_modes_count); 1175 check_write("check_write_file", write, file_path, file_modes, 1176 file_modes_count); 1177 1178 check_write("check_writev_dir", writev_wrapper, dir_path, dir_modes, 1179 dir_modes_count); 1180 check_write("check_writev_file", writev_wrapper, file_path, 1181 file_modes, file_modes_count); 1182 1183 check_write("check_pwrite_dir", pwrite_wrapper, dir_path, dir_modes, 1184 dir_modes_count); 1185 check_write("check_pwrite_file", pwrite_wrapper, file_path, 1186 file_modes, file_modes_count); 1187 1188 check_write("check_pwritev_dir", pwritev_wrapper, dir_path, 1189 dir_modes, dir_modes_count); 1190 check_write("check_pwritev_file", pwritev_wrapper, file_path, 1191 file_modes, file_modes_count); 1192 1193 if (aio_present) { 1194 check_write("check_aio_write_dir", aio_write_wrapper, 1195 dir_path, dir_modes, dir_modes_count); 1196 check_write("check_aio_write_file", aio_write_wrapper, 1197 file_path, file_modes, file_modes_count); 1198 } 1199 1200 check_read("check_read_dir", read, dir_path, dir_modes, 1201 dir_modes_count); 1202 check_read("check_read_file", read, file_path, file_modes, 1203 file_modes_count); 1204 1205 check_read("check_readv_dir", readv_wrapper, dir_path, dir_modes, 1206 dir_modes_count); 1207 check_read("check_readv_file", readv_wrapper, file_path, 1208 file_modes, file_modes_count); 1209 1210 check_read("check_pread_dir", pread_wrapper, dir_path, dir_modes, 1211 dir_modes_count); 1212 check_read("check_pread_file", pread_wrapper, file_path, 1213 file_modes, file_modes_count); 1214 1215 check_read("check_preadv_dir", preadv_wrapper, dir_path, 1216 dir_modes, dir_modes_count); 1217 check_read("check_preadv_file", preadv_wrapper, file_path, 1218 file_modes, file_modes_count); 1219 1220 if (aio_present) { 1221 check_read("check_aio_read_dir", aio_read_wrapper, dir_path, 1222 dir_modes, dir_modes_count); 1223 check_read("check_aio_read_file", aio_read_wrapper, 1224 file_path, file_modes, file_modes_count); 1225 } 1226 1227 check_mmap_read("check_mmap_read_dir", dir_path, 1, dir_modes, 1228 dir_modes_count); 1229 check_mmap_read("check_mmap_read_file", file_path, 0, file_modes, 1230 file_modes_count); 1231 1232 check_mmap_write("check_mmap_write_dir", dir_path, dir_modes, 1233 dir_modes_count); 1234 check_mmap_write("check_mmap_write_file", file_path, file_modes, 1235 file_modes_count); 1236 1237 check_mmap_exec("check_mmap_exec_dir", dir_path, 1, dir_modes, 1238 dir_modes_count); 1239 check_mmap_exec("check_mmap_exec_file", file_path, 0, file_modes, 1240 file_modes_count); 1241 1242 check_mmap_write_private("check_mmap_write_private_dir", dir_path, 1, 1243 dir_modes, dir_modes_count); 1244 check_mmap_write_private("check_mmap_write_private_file", file_path, 1245 0, file_modes, file_modes_count); 1246 1247 (void)unlink(file_path); 1248 (void)rmdir(dir_path); 1249 exit(0); 1250 } 1251