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 = sizeof(file_modes) / sizeof(int); 123 124 static const int dir_modes[] = { O_RDONLY }; 125 static const int dir_modes_count = sizeof(dir_modes) / sizeof(int); 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 == expected_errno) 173 ok_mode(testname, NULL, mode); 174 else if (expected_errno) 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, *aiocb_array[1]; 757 758 bzero(&aiocb, sizeof(aiocb)); 759 aiocb.aio_fildes = d; 760 aiocb.aio_buf = (void *)buf; 761 aiocb.aio_nbytes = nbytes; 762 if (aio_write(&aiocb) < 0) 763 return (-1); 764 aiocb_array[0] = &aiocb; 765 if (aio_suspend(aiocb_array, 1, NULL) < 0) 766 return (-1); 767 return (aio_return(&aiocb)); 768 } 769 770 static void 771 check_write(const char *testname, write_fn fn, const char *path, 772 const int *modes, int modes_count) 773 { 774 int fd, i, mode; 775 char ch; 776 777 /* 778 * write() should never succeed for directories, but especially 779 * because they can only be opened read-only. write() on files 780 * should succeed for O_WRONLY and O_RDWR descriptors. 781 */ 782 783 for (i = 0; i < modes_count; i++) { 784 mode = modes[i]; 785 fd = open(path, mode); 786 if (fd < 0) { 787 notok_mode(testname, "open", mode); 788 continue; 789 } 790 if (fn(fd, &ch, sizeof(ch)) < 0) { 791 if ((mode & O_ACCMODE) == O_WRONLY || 792 (mode & O_ACCMODE) == O_RDWR) 793 notok_mode(testname, "write failed", mode); 794 else 795 ok_mode(testname, "write failed", mode); 796 } else { 797 if (!((mode & O_ACCMODE) == O_WRONLY || 798 (mode & O_ACCMODE) == O_RDWR)) 799 notok_mode(testname, "write succeeded", mode); 800 else 801 ok_mode(testname, "write succeeded", mode); 802 } 803 close(fd); 804 } 805 } 806 807 /* 808 * Various functions read, so just make read-like wrappers for them. 809 */ 810 typedef ssize_t (*read_fn)(int d, void *buf, size_t nbytes); 811 812 static ssize_t 813 readv_wrapper(int d, void *buf, size_t nbytes) 814 { 815 struct iovec iov; 816 817 iov.iov_base = buf; 818 iov.iov_len = nbytes; 819 return (readv(d, &iov, 1)); 820 } 821 822 static ssize_t 823 pread_wrapper(int d, void *buf, size_t nbytes) 824 { 825 826 return (pread(d, buf, nbytes, 0)); 827 } 828 829 static ssize_t 830 preadv_wrapper(int d, void *buf, size_t nbytes) 831 { 832 struct iovec iov; 833 834 iov.iov_base = buf; 835 iov.iov_len = nbytes; 836 return (preadv(d, &iov, 1, 0)); 837 } 838 839 static ssize_t 840 aio_read_wrapper(int d, void *buf, size_t nbytes) 841 { 842 struct aiocb aiocb, *aiocb_array[1]; 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 aiocb_array[0] = &aiocb; 851 if (aio_suspend(aiocb_array, 1, NULL) < 0) 852 return (-1); 853 return (aio_return(&aiocb)); 854 } 855 856 static void 857 check_read(const char *testname, read_fn fn, const char *path, 858 const int *modes, int modes_count) 859 { 860 int fd, i, mode; 861 char ch; 862 863 /* 864 * read() should (generally) succeeded on directories. read() on 865 * files should succeed for O_RDONLY and O_RDWR descriptors. 866 */ 867 for (i = 0; i < modes_count; i++) { 868 mode = modes[i]; 869 fd = open(path, mode); 870 if (fd < 0) { 871 notok_mode(testname, "open", mode); 872 continue; 873 } 874 if (fn(fd, &ch, sizeof(ch)) < 0) { 875 if ((mode & O_ACCMODE) == O_RDONLY || 876 (mode & O_ACCMODE) == O_RDWR) 877 notok_mode(testname, "read failed", mode); 878 else 879 ok_mode(testname, "read failed", mode); 880 } else { 881 if (!((mode & O_ACCMODE) == O_RDONLY || 882 (mode & O_ACCMODE) == O_RDWR)) 883 notok_mode(testname, "read succeeded", mode); 884 else 885 ok_mode(testname, "read succeeded", mode); 886 } 887 close(fd); 888 } 889 } 890 891 static void 892 check_mmap_read(const char *testname, const char *path, int isdir, 893 const int *modes, int modes_count) 894 { 895 int fd, i, mode; 896 char *addr; 897 898 /* 899 * mmap() read should fail for directories (ideally?) but succeed for 900 * O_RDONLY and O_RDWR file descriptors. 901 */ 902 for (i = 0; i < modes_count; i++) { 903 mode = modes[i]; 904 fd = open(path, mode); 905 if (fd < 0) { 906 notok_mode(testname, "open", mode); 907 continue; 908 } 909 addr = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 910 0); 911 if (addr == MAP_FAILED) { 912 if (isdir) 913 ok_mode(testname, "mmap dir failed", mode); 914 else if ((mode & O_ACCMODE) == O_RDONLY || 915 (mode & O_ACCMODE) == O_RDWR) 916 notok_mode(testname, "mmap file failed", 917 mode); 918 else 919 ok_mode(testname, "mmap file failed", mode); 920 } else { 921 if (isdir) 922 notok_mode(testname, "mmap dir succeeded", 923 mode); 924 else if ((mode & O_ACCMODE) == O_RDONLY || 925 (mode & O_ACCMODE) == O_RDWR) 926 ok_mode(testname, "mmap file succeeded", 927 mode); 928 else 929 notok_mode(testname, "mmap file succeeded", 930 mode); 931 (void)munmap(addr, getpagesize()); 932 } 933 close(fd); 934 } 935 } 936 937 static void 938 check_mmap_write(const char *testname, const char *path, const int *modes, 939 int modes_count) 940 { 941 int fd, i, mode; 942 char *addr; 943 944 /* 945 * mmap() will always fail for directories (ideally) as they are 946 * always open O_RDONLY. Check for O_WRONLY or O_RDWR to permit a 947 * write mapping. This variant does a MAP_SHARED mapping, but we 948 * are also interested in MAP_PRIVATE. 949 */ 950 for (i = 0; i < modes_count; i++) { 951 mode = modes[i]; 952 fd = open(path, mode); 953 if (fd < 0) { 954 notok_mode(testname, "open", mode); 955 continue; 956 } 957 addr = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd, 958 0); 959 if (addr == MAP_FAILED) { 960 if ((mode & O_ACCMODE) == O_WRONLY || 961 (mode & O_ACCMODE) == O_RDWR) 962 notok_mode(testname, "mmap failed", 963 mode); 964 else 965 ok_mode(testname, "mmap failed", mode); 966 } else { 967 if ((mode & O_ACCMODE) == O_WRONLY || 968 (mode & O_ACCMODE) == O_RDWR) 969 ok_mode(testname, "mmap succeeded", 970 mode); 971 else 972 notok_mode(testname, "mmap succeeded", mode); 973 (void)munmap(addr, getpagesize()); 974 } 975 close(fd); 976 } 977 } 978 979 static void 980 check_mmap_exec(const char *testname, const char *path, int isdir, 981 const int *modes, int modes_count) 982 { 983 int fd, i, mode; 984 char *addr; 985 986 /* 987 * mmap() exec should fail for directories (ideally?) but succeed for 988 * O_RDONLY and O_RDWR file descriptors. 989 */ 990 for (i = 0; i < modes_count; i++) { 991 mode = modes[i]; 992 fd = open(path, mode); 993 if (fd < 0) { 994 notok_mode(testname, "open", mode); 995 continue; 996 } 997 addr = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd, 998 0); 999 if (addr == MAP_FAILED) { 1000 if (isdir) 1001 ok_mode(testname, "mmap dir failed", mode); 1002 else if ((mode & O_ACCMODE) == O_RDONLY || 1003 (mode & O_ACCMODE) == O_RDWR) 1004 notok_mode(testname, "mmap file failed", 1005 mode); 1006 else 1007 ok_mode(testname, "mmap file failed", mode); 1008 } else { 1009 if (isdir) 1010 notok_mode(testname, "mmap dir succeeded", 1011 mode); 1012 else if ((mode & O_ACCMODE) == O_RDONLY || 1013 (mode & O_ACCMODE) == O_RDWR) 1014 ok_mode(testname, "mmap file succeeded", 1015 mode); 1016 else 1017 notok_mode(testname, "mmap file succeeded", 1018 mode); 1019 (void)munmap(addr, getpagesize()); 1020 } 1021 close(fd); 1022 } 1023 } 1024 1025 static void 1026 check_mmap_write_private(const char *testname, const char *path, int isdir, 1027 const int *modes, int modes_count) 1028 { 1029 int fd, i, mode; 1030 char *addr; 1031 1032 /* 1033 * mmap() write private should succeed for readable descriptors 1034 * except for directories. 1035 */ 1036 for (i = 0; i < modes_count; i++) { 1037 mode = modes[i]; 1038 fd = open(path, mode); 1039 if (fd < 0) { 1040 notok_mode(testname, "open", mode); 1041 continue; 1042 } 1043 addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, 1044 MAP_PRIVATE, fd, 0); 1045 if (addr == MAP_FAILED) { 1046 if (isdir) 1047 ok_mode(testname, "mmap dir failed", mode); 1048 else if ((mode & O_ACCMODE) == O_RDONLY || 1049 (mode & O_ACCMODE) == O_RDWR) 1050 notok_mode(testname, "mmap file failed", 1051 mode); 1052 else 1053 ok_mode(testname, "mmap file failed", mode); 1054 } else { 1055 if (isdir) 1056 notok_mode(testname, "mmap dir succeeded", 1057 mode); 1058 else if ((mode & O_ACCMODE) == O_RDONLY || 1059 (mode & O_ACCMODE) == O_RDWR) 1060 ok_mode(testname, "mmap file succeeded", 1061 mode); 1062 else 1063 notok_mode(testname, "mmap file succeeded", 1064 mode); 1065 (void)munmap(addr, getpagesize()); 1066 } 1067 close(fd); 1068 } 1069 } 1070 1071 int 1072 main(int argc, char *argv[]) 1073 { 1074 char dir_path[PATH_MAX], file_path[PATH_MAX]; 1075 int dummy, fd; 1076 size_t size; 1077 1078 aio_present = 0; 1079 size = sizeof(dummy); 1080 if (sysctlbyname("vfs.aio", &dummy, &size, NULL, 0) < 0) { 1081 if (errno == EISDIR) 1082 aio_present = 1; 1083 } 1084 1085 strlcpy(dir_path, "/tmp/open-dir.XXXXXXXXXXX", sizeof(dir_path)); 1086 if (mkdtemp(dir_path) == NULL) 1087 err(-1, "mkdtemp"); 1088 if (chmod(dir_path, PERM_DIR) < 0) { 1089 warn("chmod %s", dir_path); 1090 (void)rmdir(dir_path); 1091 exit(-1); 1092 } 1093 strlcpy(file_path, "/tmp/open-file.XXXXXXXXXXX", sizeof(file_path)); 1094 fd = mkstemp(file_path); 1095 if (fd < 0) { 1096 warn("mkstemp"); 1097 (void)rmdir(dir_path); 1098 exit(-1); 1099 } 1100 close(fd); 1101 if (chmod(file_path, PERM_FILE) < 0) { 1102 warn("chmod %s", file_path); 1103 (void)unlink(file_path); 1104 (void)rmdir(dir_path); 1105 exit(-1); 1106 } 1107 check_directory_open_modes(dir_path, file_modes, file_modes_count); 1108 1109 check_dup("check_dup_dir", dir_path, dir_modes, dir_modes_count); 1110 check_dup("check_dup_file", file_path, file_modes, file_modes_count); 1111 1112 check_dup2("check_dup2_dir", dir_path, dir_modes, dir_modes_count); 1113 check_dup2("check_dup2_file", file_path, file_modes, 1114 file_modes_count); 1115 1116 check_fchdir("check_fchdir", dir_path, dir_modes, dir_modes_count); 1117 1118 check_fchflags("check_fchflags_dir", dir_path, dir_modes, 1119 dir_modes_count); 1120 check_fchflags("check_fchflags_file", file_path, file_modes, 1121 file_modes_count); 1122 1123 check_fchmod("check_fchmod_dir", dir_path, PERM_DIR, dir_modes, 1124 dir_modes_count); 1125 check_fchmod("check_fchmod_file", file_path, PERM_FILE, file_modes, 1126 file_modes_count); 1127 1128 check_fchown("check_fchown_dir", dir_path, dir_modes, 1129 dir_modes_count); 1130 check_fchown("check_fchown_file", file_path, file_modes, 1131 file_modes_count); 1132 1133 check_flock("check_flock_dir", dir_path, dir_modes, dir_modes_count); 1134 check_flock("check_flock_file", file_path, file_modes, 1135 file_modes_count); 1136 1137 check_fpathconf("check_fpathconf_dir", dir_path, dir_modes, 1138 dir_modes_count); 1139 check_fpathconf("check_fpathconf_file", file_path, file_modes, 1140 file_modes_count); 1141 1142 check_fstat("check_fstat_dir", dir_path, dir_modes, dir_modes_count); 1143 check_fstat("check_fstat_file", file_path, file_modes, 1144 file_modes_count); 1145 1146 check_fstatfs("check_fstatfs_dir", dir_path, dir_modes, 1147 dir_modes_count); 1148 check_fstatfs("check_fstatfs_file", file_path, file_modes, 1149 file_modes_count); 1150 1151 check_fsync("check_fsync_dir", dir_path, dir_modes, dir_modes_count); 1152 check_fsync("check_fsync_file", file_path, file_modes, 1153 file_modes_count); 1154 1155 check_ftruncate("check_ftruncate_dir", dir_path, dir_modes, 1156 dir_modes_count); 1157 check_ftruncate("check_ftruncate_file", file_path, file_modes, 1158 file_modes_count); 1159 1160 check_futimes("check_futimes_dir", dir_path, dir_modes, 1161 dir_modes_count); 1162 check_futimes("check_futimes_file", file_path, file_modes, 1163 file_modes_count); 1164 1165 check_lseek("check_lseek_dir", dir_path, dir_modes, dir_modes_count); 1166 check_lseek("check_lseek_file", file_path, file_modes, 1167 file_modes_count); 1168 1169 check_getdents("check_getdents_dir", dir_path, 1, dir_modes, 1170 dir_modes_count); 1171 check_getdents("check_getdents_file", file_path, 0, file_modes, 1172 file_modes_count); 1173 1174 check_sendfile("check_sendfile_dir", dir_path, 1, dir_modes, 1175 dir_modes_count); 1176 check_sendfile("check_sendfile_file", file_path, 0, file_modes, 1177 file_modes_count); 1178 1179 check_write("check_write_dir", write, dir_path, dir_modes, 1180 dir_modes_count); 1181 check_write("check_write_file", write, file_path, file_modes, 1182 file_modes_count); 1183 1184 check_write("check_writev_dir", writev_wrapper, dir_path, dir_modes, 1185 dir_modes_count); 1186 check_write("check_writev_file", writev_wrapper, file_path, 1187 file_modes, file_modes_count); 1188 1189 check_write("check_pwrite_dir", pwrite_wrapper, dir_path, dir_modes, 1190 dir_modes_count); 1191 check_write("check_pwrite_file", pwrite_wrapper, file_path, 1192 file_modes, file_modes_count); 1193 1194 check_write("check_pwritev_dir", pwritev_wrapper, dir_path, 1195 dir_modes, dir_modes_count); 1196 check_write("check_pwritev_file", pwritev_wrapper, file_path, 1197 file_modes, file_modes_count); 1198 1199 if (aio_present) { 1200 check_write("check_aio_write_dir", aio_write_wrapper, 1201 dir_path, dir_modes, dir_modes_count); 1202 check_write("check_aio_write_file", aio_write_wrapper, 1203 file_path, file_modes, file_modes_count); 1204 } 1205 1206 check_read("check_read_dir", read, dir_path, dir_modes, 1207 dir_modes_count); 1208 check_read("check_read_file", read, file_path, file_modes, 1209 file_modes_count); 1210 1211 check_read("check_readv_dir", readv_wrapper, dir_path, dir_modes, 1212 dir_modes_count); 1213 check_read("check_readv_file", readv_wrapper, file_path, 1214 file_modes, file_modes_count); 1215 1216 check_read("check_pread_dir", pread_wrapper, dir_path, dir_modes, 1217 dir_modes_count); 1218 check_read("check_pread_file", pread_wrapper, file_path, 1219 file_modes, file_modes_count); 1220 1221 check_read("check_preadv_dir", preadv_wrapper, dir_path, 1222 dir_modes, dir_modes_count); 1223 check_read("check_preadv_file", preadv_wrapper, file_path, 1224 file_modes, file_modes_count); 1225 1226 if (aio_present) { 1227 check_read("check_aio_read_dir", aio_read_wrapper, dir_path, 1228 dir_modes, dir_modes_count); 1229 check_read("check_aio_read_file", aio_read_wrapper, 1230 file_path, file_modes, file_modes_count); 1231 } 1232 1233 check_mmap_read("check_mmap_read_dir", dir_path, 1, dir_modes, 1234 dir_modes_count); 1235 check_mmap_read("check_mmap_read_file", file_path, 0, file_modes, 1236 file_modes_count); 1237 1238 check_mmap_write("check_mmap_write_dir", dir_path, dir_modes, 1239 dir_modes_count); 1240 check_mmap_write("check_mmap_write_file", file_path, file_modes, 1241 file_modes_count); 1242 1243 check_mmap_exec("check_mmap_exec_dir", dir_path, 1, dir_modes, 1244 dir_modes_count); 1245 check_mmap_exec("check_mmap_exec_file", file_path, 0, file_modes, 1246 file_modes_count); 1247 1248 check_mmap_write_private("check_mmap_write_private_dir", dir_path, 1, 1249 dir_modes, dir_modes_count); 1250 check_mmap_write_private("check_mmap_write_private_file", file_path, 1251 0, file_modes, file_modes_count); 1252 1253 (void)unlink(file_path); 1254 (void)rmdir(dir_path); 1255 exit(0); 1256 } 1257