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