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