1 /*- 2 * Copyright (c) 2006 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 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/mman.h> 32 #include <sys/resource.h> 33 #include <sys/stat.h> 34 #include <sys/syscall.h> 35 #include <sys/wait.h> 36 37 #include <ctype.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <signal.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <atf-c.h> 47 48 #define TEST_PATH_LEN 256 49 static char test_path[TEST_PATH_LEN]; 50 static char test_path2[TEST_PATH_LEN]; 51 static unsigned int test_path_idx = 0; 52 53 static void 54 gen_a_test_path(char *path) 55 { 56 snprintf(path, TEST_PATH_LEN, "/%s/tmp.XXXXXX%d", 57 getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR"), 58 test_path_idx); 59 60 test_path_idx++; 61 62 ATF_REQUIRE_MSG(mkstemp(path) != -1, 63 "mkstemp failed; errno=%d", errno); 64 ATF_REQUIRE_MSG(unlink(path) == 0, 65 "unlink failed; errno=%d", errno); 66 } 67 68 static void 69 gen_test_path(void) 70 { 71 gen_a_test_path(test_path); 72 } 73 74 static void 75 gen_test_path2(void) 76 { 77 gen_a_test_path(test_path2); 78 } 79 80 /* 81 * Attempt a shm_open() that should fail with an expected error of 'error'. 82 */ 83 static void 84 shm_open_should_fail(const char *path, int flags, mode_t mode, int error) 85 { 86 int fd; 87 88 fd = shm_open(path, flags, mode); 89 ATF_CHECK_MSG(fd == -1, "shm_open didn't fail"); 90 ATF_CHECK_MSG(error == errno, 91 "shm_open didn't fail with expected errno; errno=%d; expected " 92 "errno=%d", errno, error); 93 } 94 95 /* 96 * Attempt a shm_unlink() that should fail with an expected error of 'error'. 97 */ 98 static void 99 shm_unlink_should_fail(const char *path, int error) 100 { 101 102 ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail"); 103 ATF_CHECK_MSG(error == errno, 104 "shm_unlink didn't fail with expected errno; errno=%d; expected " 105 "errno=%d", errno, error); 106 } 107 108 /* 109 * Open the test object and write a value to the first byte. Returns valid fd 110 * on success and -1 on failure. 111 */ 112 static int 113 scribble_object(const char *path, char value) 114 { 115 char *page; 116 int fd, pagesize; 117 118 ATF_REQUIRE(0 < (pagesize = getpagesize())); 119 120 fd = shm_open(path, O_CREAT|O_EXCL|O_RDWR, 0777); 121 if (fd < 0 && errno == EEXIST) { 122 if (shm_unlink(test_path) < 0) 123 atf_tc_fail("shm_unlink"); 124 fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777); 125 } 126 if (fd < 0) 127 atf_tc_fail("shm_open failed; errno=%d", errno); 128 if (ftruncate(fd, pagesize) < 0) 129 atf_tc_fail("ftruncate failed; errno=%d", errno); 130 131 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 132 if (page == MAP_FAILED) 133 atf_tc_fail("mmap failed; errno=%d", errno); 134 135 page[0] = value; 136 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 137 errno); 138 139 return (fd); 140 } 141 142 /* 143 * Fail the test case if the 'path' does not refer to an shm whose first byte 144 * is equal to expected_value 145 */ 146 static void 147 verify_object(const char *path, char expected_value) 148 { 149 int fd; 150 int pagesize; 151 char *page; 152 153 ATF_REQUIRE(0 < (pagesize = getpagesize())); 154 155 fd = shm_open(path, O_RDONLY, 0777); 156 if (fd < 0) 157 atf_tc_fail("shm_open failed in verify_object; errno=%d, path=%s", 158 errno, path); 159 160 page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0); 161 if (page == MAP_FAILED) 162 atf_tc_fail("mmap(1)"); 163 if (page[0] != expected_value) 164 atf_tc_fail("Renamed object has incorrect value; has" 165 "%d (0x%x, '%c'), expected %d (0x%x, '%c')\n", 166 page[0], page[0], isprint(page[0]) ? page[0] : ' ', 167 expected_value, expected_value, 168 isprint(expected_value) ? expected_value : ' '); 169 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 170 errno); 171 close(fd); 172 } 173 174 ATF_TC_WITHOUT_HEAD(remap_object); 175 ATF_TC_BODY(remap_object, tc) 176 { 177 char *page; 178 int fd, pagesize; 179 180 ATF_REQUIRE(0 < (pagesize = getpagesize())); 181 182 gen_test_path(); 183 fd = scribble_object(test_path, '1'); 184 185 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 186 if (page == MAP_FAILED) 187 atf_tc_fail("mmap(2) failed; errno=%d", errno); 188 189 if (page[0] != '1') 190 atf_tc_fail("missing data ('%c' != '1')", page[0]); 191 192 close(fd); 193 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 194 errno); 195 196 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 197 "shm_unlink failed; errno=%d", errno); 198 } 199 200 ATF_TC_WITHOUT_HEAD(rename_from_anon); 201 ATF_TC_BODY(rename_from_anon, tc) 202 { 203 int rc; 204 205 gen_test_path(); 206 rc = shm_rename(SHM_ANON, test_path, 0); 207 if (rc != -1) 208 atf_tc_fail("shm_rename from SHM_ANON succeeded unexpectedly"); 209 } 210 211 ATF_TC_WITHOUT_HEAD(rename_bad_path_pointer); 212 ATF_TC_BODY(rename_bad_path_pointer, tc) 213 { 214 const char *bad_path; 215 int rc; 216 217 bad_path = (const char *)0x1; 218 219 gen_test_path(); 220 rc = shm_rename(test_path, bad_path, 0); 221 if (rc != -1) 222 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly"); 223 224 rc = shm_rename(bad_path, test_path, 0); 225 if (rc != -1) 226 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly"); 227 } 228 229 ATF_TC_WITHOUT_HEAD(rename_from_nonexisting); 230 ATF_TC_BODY(rename_from_nonexisting, tc) 231 { 232 int rc; 233 234 gen_test_path(); 235 gen_test_path2(); 236 rc = shm_rename(test_path, test_path2, 0); 237 if (rc != -1) 238 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly"); 239 240 if (errno != ENOENT) 241 atf_tc_fail("Expected ENOENT to rename of nonexistent shm; got %d", 242 errno); 243 } 244 245 ATF_TC_WITHOUT_HEAD(rename_to_anon); 246 ATF_TC_BODY(rename_to_anon, tc) 247 { 248 int rc; 249 250 gen_test_path(); 251 rc = shm_rename(test_path, SHM_ANON, 0); 252 if (rc != -1) 253 atf_tc_fail("shm_rename to SHM_ANON succeeded unexpectedly"); 254 } 255 256 ATF_TC_WITHOUT_HEAD(rename_to_replace); 257 ATF_TC_BODY(rename_to_replace, tc) 258 { 259 char expected_value; 260 int fd; 261 int fd2; 262 263 // Some contents we can verify later 264 expected_value = 'g'; 265 266 gen_test_path(); 267 fd = scribble_object(test_path, expected_value); 268 close(fd); 269 270 // Give the other some different value so we can detect success 271 gen_test_path2(); 272 fd2 = scribble_object(test_path2, 'h'); 273 close(fd2); 274 275 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 0) == 0, 276 "shm_rename failed; errno=%d", errno); 277 278 // Read back renamed; verify contents 279 verify_object(test_path2, expected_value); 280 } 281 282 ATF_TC_WITHOUT_HEAD(rename_to_noreplace); 283 ATF_TC_BODY(rename_to_noreplace, tc) 284 { 285 char expected_value_from; 286 char expected_value_to; 287 int fd_from; 288 int fd_to; 289 int rc; 290 291 // Some contents we can verify later 292 expected_value_from = 'g'; 293 gen_test_path(); 294 fd_from = scribble_object(test_path, expected_value_from); 295 close(fd_from); 296 297 // Give the other some different value so we can detect success 298 expected_value_to = 'h'; 299 gen_test_path2(); 300 fd_to = scribble_object(test_path2, expected_value_to); 301 close(fd_to); 302 303 rc = shm_rename(test_path, test_path2, SHM_RENAME_NOREPLACE); 304 ATF_REQUIRE_MSG((rc == -1) && (errno == EEXIST), 305 "shm_rename didn't fail as expected; errno: %d; return: %d", errno, 306 rc); 307 308 // Read back renamed; verify contents 309 verify_object(test_path2, expected_value_to); 310 } 311 312 ATF_TC_WITHOUT_HEAD(rename_to_exchange); 313 ATF_TC_BODY(rename_to_exchange, tc) 314 { 315 char expected_value_from; 316 char expected_value_to; 317 int fd_from; 318 int fd_to; 319 320 // Some contents we can verify later 321 expected_value_from = 'g'; 322 gen_test_path(); 323 fd_from = scribble_object(test_path, expected_value_from); 324 close(fd_from); 325 326 // Give the other some different value so we can detect success 327 expected_value_to = 'h'; 328 gen_test_path2(); 329 fd_to = scribble_object(test_path2, expected_value_to); 330 close(fd_to); 331 332 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 333 SHM_RENAME_EXCHANGE) == 0, 334 "shm_rename failed; errno=%d", errno); 335 336 // Read back renamed; verify contents 337 verify_object(test_path, expected_value_to); 338 verify_object(test_path2, expected_value_from); 339 } 340 341 ATF_TC_WITHOUT_HEAD(rename_to_exchange_nonexisting); 342 ATF_TC_BODY(rename_to_exchange_nonexisting, tc) 343 { 344 char expected_value_from; 345 int fd_from; 346 347 // Some contents we can verify later 348 expected_value_from = 'g'; 349 gen_test_path(); 350 fd_from = scribble_object(test_path, expected_value_from); 351 close(fd_from); 352 353 gen_test_path2(); 354 355 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 356 SHM_RENAME_EXCHANGE) == 0, 357 "shm_rename failed; errno=%d", errno); 358 359 // Read back renamed; verify contents 360 verify_object(test_path2, expected_value_from); 361 } 362 363 ATF_TC_WITHOUT_HEAD(rename_to_self); 364 ATF_TC_BODY(rename_to_self, tc) 365 { 366 int fd; 367 char expected_value; 368 369 expected_value = 't'; 370 371 gen_test_path(); 372 fd = scribble_object(test_path, expected_value); 373 close(fd); 374 375 ATF_REQUIRE_MSG(shm_rename(test_path, test_path, 0) == 0, 376 "shm_rename failed; errno=%d", errno); 377 378 verify_object(test_path, expected_value); 379 } 380 381 ATF_TC_WITHOUT_HEAD(rename_bad_flag); 382 ATF_TC_BODY(rename_bad_flag, tc) 383 { 384 int fd; 385 int rc; 386 387 /* Make sure we don't fail out due to ENOENT */ 388 gen_test_path(); 389 gen_test_path2(); 390 fd = scribble_object(test_path, 'd'); 391 close(fd); 392 fd = scribble_object(test_path2, 'd'); 393 close(fd); 394 395 /* 396 * Note: if we end up with enough flags that we use all the bits, 397 * then remove this test completely. 398 */ 399 rc = shm_rename(test_path, test_path2, INT_MIN); 400 ATF_REQUIRE_MSG((rc == -1) && (errno == EINVAL), 401 "shm_rename should have failed with EINVAL; got: return=%d, " 402 "errno=%d", rc, errno); 403 } 404 405 ATF_TC_WITHOUT_HEAD(reopen_object); 406 ATF_TC_BODY(reopen_object, tc) 407 { 408 char *page; 409 int fd, pagesize; 410 411 ATF_REQUIRE(0 < (pagesize = getpagesize())); 412 413 gen_test_path(); 414 fd = scribble_object(test_path, '1'); 415 close(fd); 416 417 fd = shm_open(test_path, O_RDONLY, 0777); 418 if (fd < 0) 419 atf_tc_fail("shm_open(2) failed; errno=%d", errno); 420 421 page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0); 422 if (page == MAP_FAILED) 423 atf_tc_fail("mmap(2) failed; errno=%d", errno); 424 425 if (page[0] != '1') 426 atf_tc_fail("missing data ('%c' != '1')", page[0]); 427 428 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 429 errno); 430 close(fd); 431 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 432 "shm_unlink failed; errno=%d", errno); 433 } 434 435 ATF_TC_WITHOUT_HEAD(readonly_mmap_write); 436 ATF_TC_BODY(readonly_mmap_write, tc) 437 { 438 char *page; 439 int fd, pagesize; 440 441 ATF_REQUIRE(0 < (pagesize = getpagesize())); 442 443 gen_test_path(); 444 445 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); 446 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 447 448 /* PROT_WRITE should fail with EACCES. */ 449 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 450 if (page != MAP_FAILED) 451 atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly"); 452 453 if (errno != EACCES) 454 atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; " 455 "errno=%d", errno); 456 457 close(fd); 458 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 459 "shm_unlink failed; errno=%d", errno); 460 } 461 462 ATF_TC_WITHOUT_HEAD(open_after_link); 463 ATF_TC_BODY(open_after_link, tc) 464 { 465 int fd; 466 467 gen_test_path(); 468 469 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); 470 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno); 471 close(fd); 472 473 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d", 474 errno); 475 476 shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT); 477 } 478 479 ATF_TC_WITHOUT_HEAD(open_invalid_path); 480 ATF_TC_BODY(open_invalid_path, tc) 481 { 482 483 shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL); 484 } 485 486 ATF_TC_WITHOUT_HEAD(open_write_only); 487 ATF_TC_BODY(open_write_only, tc) 488 { 489 490 gen_test_path(); 491 492 shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL); 493 } 494 495 ATF_TC_WITHOUT_HEAD(open_extra_flags); 496 ATF_TC_BODY(open_extra_flags, tc) 497 { 498 499 gen_test_path(); 500 501 shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL); 502 } 503 504 ATF_TC_WITHOUT_HEAD(open_anon); 505 ATF_TC_BODY(open_anon, tc) 506 { 507 int fd; 508 509 fd = shm_open(SHM_ANON, O_RDWR, 0777); 510 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 511 close(fd); 512 } 513 514 ATF_TC_WITHOUT_HEAD(open_anon_readonly); 515 ATF_TC_BODY(open_anon_readonly, tc) 516 { 517 518 shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL); 519 } 520 521 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer); 522 ATF_TC_BODY(open_bad_path_pointer, tc) 523 { 524 525 shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT); 526 } 527 528 ATF_TC_WITHOUT_HEAD(open_path_too_long); 529 ATF_TC_BODY(open_path_too_long, tc) 530 { 531 char *page; 532 533 page = malloc(MAXPATHLEN + 1); 534 memset(page, 'a', MAXPATHLEN); 535 page[MAXPATHLEN] = '\0'; 536 shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG); 537 free(page); 538 } 539 540 ATF_TC_WITHOUT_HEAD(open_nonexisting_object); 541 ATF_TC_BODY(open_nonexisting_object, tc) 542 { 543 544 shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT); 545 } 546 547 ATF_TC_WITHOUT_HEAD(open_create_existing_object); 548 ATF_TC_BODY(open_create_existing_object, tc) 549 { 550 int fd; 551 552 gen_test_path(); 553 554 fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777); 555 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 556 close(fd); 557 558 shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL, 559 0777, EEXIST); 560 561 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 562 "shm_unlink failed; errno=%d", errno); 563 } 564 565 ATF_TC_WITHOUT_HEAD(trunc_resets_object); 566 ATF_TC_BODY(trunc_resets_object, tc) 567 { 568 struct stat sb; 569 int fd; 570 571 gen_test_path(); 572 573 /* Create object and set size to 1024. */ 574 fd = shm_open(test_path, O_RDWR | O_CREAT, 0777); 575 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno); 576 ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1, 577 "ftruncate failed; errno=%d", errno); 578 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1, 579 "fstat(1) failed; errno=%d", errno); 580 ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size); 581 close(fd); 582 583 /* Open with O_TRUNC which should reset size to 0. */ 584 fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777); 585 ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno); 586 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1, 587 "fstat(2) failed; errno=%d", errno); 588 ATF_REQUIRE_MSG(sb.st_size == 0, 589 "size was not 0 after truncation: %d", (int)sb.st_size); 590 close(fd); 591 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 592 "shm_unlink failed; errno=%d", errno); 593 } 594 595 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer); 596 ATF_TC_BODY(unlink_bad_path_pointer, tc) 597 { 598 599 shm_unlink_should_fail((char *)1024, EFAULT); 600 } 601 602 ATF_TC_WITHOUT_HEAD(unlink_path_too_long); 603 ATF_TC_BODY(unlink_path_too_long, tc) 604 { 605 char *page; 606 607 page = malloc(MAXPATHLEN + 1); 608 memset(page, 'a', MAXPATHLEN); 609 page[MAXPATHLEN] = '\0'; 610 shm_unlink_should_fail(page, ENAMETOOLONG); 611 free(page); 612 } 613 614 ATF_TC_WITHOUT_HEAD(object_resize); 615 ATF_TC_BODY(object_resize, tc) 616 { 617 pid_t pid; 618 struct stat sb; 619 char *page; 620 int fd, pagesize, status; 621 622 ATF_REQUIRE(0 < (pagesize = getpagesize())); 623 624 /* Start off with a size of a single page. */ 625 fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777); 626 if (fd < 0) 627 atf_tc_fail("shm_open failed; errno=%d", errno); 628 629 if (ftruncate(fd, pagesize) < 0) 630 atf_tc_fail("ftruncate(1) failed; errno=%d", errno); 631 632 if (fstat(fd, &sb) < 0) 633 atf_tc_fail("fstat(1) failed; errno=%d", errno); 634 635 if (sb.st_size != pagesize) 636 atf_tc_fail("first resize failed (%d != %d)", 637 (int)sb.st_size, pagesize); 638 639 /* Write a '1' to the first byte. */ 640 page = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 641 if (page == MAP_FAILED) 642 atf_tc_fail("mmap(1)"); 643 644 page[0] = '1'; 645 646 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 647 errno); 648 649 /* Grow the object to 2 pages. */ 650 if (ftruncate(fd, pagesize * 2) < 0) 651 atf_tc_fail("ftruncate(2) failed; errno=%d", errno); 652 653 if (fstat(fd, &sb) < 0) 654 atf_tc_fail("fstat(2) failed; errno=%d", errno); 655 656 if (sb.st_size != pagesize * 2) 657 atf_tc_fail("second resize failed (%d != %d)", 658 (int)sb.st_size, pagesize * 2); 659 660 /* Check for '1' at the first byte. */ 661 page = mmap(0, pagesize * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 662 if (page == MAP_FAILED) 663 atf_tc_fail("mmap(2) failed; errno=%d", errno); 664 665 if (page[0] != '1') 666 atf_tc_fail("'%c' != '1'", page[0]); 667 668 /* Write a '2' at the start of the second page. */ 669 page[pagesize] = '2'; 670 671 /* Shrink the object back to 1 page. */ 672 if (ftruncate(fd, pagesize) < 0) 673 atf_tc_fail("ftruncate(3) failed; errno=%d", errno); 674 675 if (fstat(fd, &sb) < 0) 676 atf_tc_fail("fstat(3) failed; errno=%d", errno); 677 678 if (sb.st_size != pagesize) 679 atf_tc_fail("third resize failed (%d != %d)", 680 (int)sb.st_size, pagesize); 681 682 /* 683 * Fork a child process to make sure the second page is no 684 * longer valid. 685 */ 686 pid = fork(); 687 if (pid == -1) 688 atf_tc_fail("fork failed; errno=%d", errno); 689 690 if (pid == 0) { 691 struct rlimit lim; 692 char c; 693 694 /* Don't generate a core dump. */ 695 ATF_REQUIRE(getrlimit(RLIMIT_CORE, &lim) == 0); 696 lim.rlim_cur = 0; 697 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &lim) == 0); 698 699 /* 700 * The previous ftruncate(2) shrunk the backing object 701 * so that this address is no longer valid, so reading 702 * from it should trigger a SIGBUS. 703 */ 704 c = page[pagesize]; 705 fprintf(stderr, "child: page 1: '%c'\n", c); 706 exit(0); 707 } 708 709 if (wait(&status) < 0) 710 atf_tc_fail("wait failed; errno=%d", errno); 711 712 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS) 713 atf_tc_fail("child terminated with status %x", status); 714 715 /* Grow the object back to 2 pages. */ 716 if (ftruncate(fd, pagesize * 2) < 0) 717 atf_tc_fail("ftruncate(2) failed; errno=%d", errno); 718 719 if (fstat(fd, &sb) < 0) 720 atf_tc_fail("fstat(2) failed; errno=%d", errno); 721 722 if (sb.st_size != pagesize * 2) 723 atf_tc_fail("fourth resize failed (%d != %d)", 724 (int)sb.st_size, pagesize); 725 726 /* 727 * Note that the mapping at 'page' for the second page is 728 * still valid, and now that the shm object has been grown 729 * back up to 2 pages, there is now memory backing this page 730 * so the read will work. However, the data should be zero 731 * rather than '2' as the old data was thrown away when the 732 * object was shrunk and the new pages when an object are 733 * grown are zero-filled. 734 */ 735 if (page[pagesize] != 0) 736 atf_tc_fail("invalid data at %d: %x != 0", 737 pagesize, (int)page[pagesize]); 738 739 close(fd); 740 } 741 742 /* Signal handler which does nothing. */ 743 static void 744 ignoreit(int sig __unused) 745 { 746 ; 747 } 748 749 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork); 750 ATF_TC_BODY(shm_functionality_across_fork, tc) 751 { 752 char *cp, c; 753 int error, desc, rv; 754 long scval; 755 sigset_t ss; 756 struct sigaction sa; 757 void *region; 758 size_t i, psize; 759 760 #ifndef _POSIX_SHARED_MEMORY_OBJECTS 761 printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n"); 762 #else 763 printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n", 764 (long)_POSIX_SHARED_MEMORY_OBJECTS - 0); 765 if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1) 766 printf("***Indicates this feature may be unsupported!\n"); 767 #endif 768 errno = 0; 769 scval = sysconf(_SC_SHARED_MEMORY_OBJECTS); 770 if (scval == -1 && errno != 0) { 771 atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; " 772 "errno=%d", errno); 773 } else { 774 printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n", 775 scval); 776 if (scval == -1) 777 printf("***Indicates this feature is unsupported!\n"); 778 } 779 780 errno = 0; 781 scval = sysconf(_SC_PAGESIZE); 782 if (scval == -1 && errno != 0) { 783 atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno); 784 } else if (scval <= 0) { 785 fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld", 786 scval); 787 psize = 4096; 788 } else { 789 printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval); 790 psize = scval; 791 } 792 793 gen_test_path(); 794 desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600); 795 796 ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno); 797 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0, 798 "shm_unlink failed; errno=%d", errno); 799 ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1, 800 "ftruncate failed; errno=%d", errno); 801 802 region = mmap(NULL, psize, PROT_READ | PROT_WRITE, MAP_SHARED, desc, 0); 803 ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno); 804 memset(region, '\377', psize); 805 806 sa.sa_flags = 0; 807 sa.sa_handler = ignoreit; 808 sigemptyset(&sa.sa_mask); 809 ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0, 810 "sigaction failed; errno=%d", errno); 811 812 sigemptyset(&ss); 813 sigaddset(&ss, SIGUSR1); 814 ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0, 815 "sigprocmask failed; errno=%d", errno); 816 817 rv = fork(); 818 ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno); 819 if (rv == 0) { 820 sigemptyset(&ss); 821 sigsuspend(&ss); 822 823 for (cp = region; cp < (char *)region + psize; cp++) { 824 if (*cp != '\151') 825 _exit(1); 826 } 827 if (lseek(desc, 0, SEEK_SET) == -1) 828 _exit(1); 829 for (i = 0; i < psize; i++) { 830 error = read(desc, &c, 1); 831 if (c != '\151') 832 _exit(1); 833 } 834 _exit(0); 835 } else { 836 int status; 837 838 memset(region, '\151', psize - 2); 839 error = pwrite(desc, region, 2, psize - 2); 840 if (error != 2) { 841 if (error >= 0) 842 atf_tc_fail("short write; %d bytes written", 843 error); 844 else 845 atf_tc_fail("shmfd write"); 846 } 847 kill(rv, SIGUSR1); 848 waitpid(rv, &status, 0); 849 850 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 851 printf("Functionality test successful\n"); 852 } else if (WIFEXITED(status)) { 853 atf_tc_fail("Child process exited with status %d", 854 WEXITSTATUS(status)); 855 } else { 856 atf_tc_fail("Child process terminated with %s", 857 strsignal(WTERMSIG(status))); 858 } 859 } 860 861 ATF_REQUIRE_MSG(munmap(region, psize) == 0, "munmap failed; errno=%d", 862 errno); 863 shm_unlink(test_path); 864 } 865 866 ATF_TC_WITHOUT_HEAD(cloexec); 867 ATF_TC_BODY(cloexec, tc) 868 { 869 int fd; 870 871 gen_test_path(); 872 873 /* shm_open(2) is required to set FD_CLOEXEC */ 874 fd = shm_open(SHM_ANON, O_RDWR, 0777); 875 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 876 ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0); 877 close(fd); 878 879 /* Also make sure that named shm is correct */ 880 fd = shm_open(test_path, O_CREAT | O_RDWR, 0600); 881 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 882 ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0); 883 close(fd); 884 } 885 886 ATF_TC_WITHOUT_HEAD(mode); 887 ATF_TC_BODY(mode, tc) 888 { 889 struct stat st; 890 int fd; 891 mode_t restore_mask; 892 893 gen_test_path(); 894 895 /* Remove inhibitions from umask */ 896 restore_mask = umask(0); 897 fd = shm_open(test_path, O_CREAT | O_RDWR, 0600); 898 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 899 ATF_REQUIRE(fstat(fd, &st) == 0); 900 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0600); 901 close(fd); 902 ATF_REQUIRE(shm_unlink(test_path) == 0); 903 904 fd = shm_open(test_path, O_CREAT | O_RDWR, 0660); 905 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 906 ATF_REQUIRE(fstat(fd, &st) == 0); 907 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0660); 908 close(fd); 909 ATF_REQUIRE(shm_unlink(test_path) == 0); 910 911 fd = shm_open(test_path, O_CREAT | O_RDWR, 0666); 912 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 913 ATF_REQUIRE(fstat(fd, &st) == 0); 914 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0666); 915 close(fd); 916 ATF_REQUIRE(shm_unlink(test_path) == 0); 917 918 umask(restore_mask); 919 } 920 921 ATF_TC_WITHOUT_HEAD(fallocate); 922 ATF_TC_BODY(fallocate, tc) 923 { 924 struct stat st; 925 int error, fd, sz; 926 927 /* 928 * Primitive test case for posix_fallocate with shmd. Effectively 929 * expected to work like a smarter ftruncate that will grow the region 930 * as needed in a race-free way. 931 */ 932 fd = shm_open(SHM_ANON, O_RDWR, 0666); 933 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 934 /* Set the initial size. */ 935 sz = 32; 936 ATF_REQUIRE(ftruncate(fd, sz) == 0); 937 938 /* Now grow it. */ 939 error = 0; 940 sz *= 2; 941 ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz)) == 0, 942 "posix_fallocate failed; error=%d", error); 943 ATF_REQUIRE(fstat(fd, &st) == 0); 944 ATF_REQUIRE(st.st_size == sz); 945 /* Attempt to shrink it; should succeed, but not change the size. */ 946 ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz / 2)) == 0, 947 "posix_fallocate failed; error=%d", error); 948 ATF_REQUIRE(fstat(fd, &st) == 0); 949 ATF_REQUIRE(st.st_size == sz); 950 /* Grow it using an offset of sz and len of sz. */ 951 ATF_REQUIRE_MSG((error = posix_fallocate(fd, sz, sz)) == 0, 952 "posix_fallocate failed; error=%d", error); 953 ATF_REQUIRE(fstat(fd, &st) == 0); 954 ATF_REQUIRE(st.st_size == (sz * 2)); 955 956 close(fd); 957 } 958 959 ATF_TP_ADD_TCS(tp) 960 { 961 962 ATF_TP_ADD_TC(tp, remap_object); 963 ATF_TP_ADD_TC(tp, rename_from_anon); 964 ATF_TP_ADD_TC(tp, rename_bad_path_pointer); 965 ATF_TP_ADD_TC(tp, rename_from_nonexisting); 966 ATF_TP_ADD_TC(tp, rename_to_anon); 967 ATF_TP_ADD_TC(tp, rename_to_replace); 968 ATF_TP_ADD_TC(tp, rename_to_noreplace); 969 ATF_TP_ADD_TC(tp, rename_to_exchange); 970 ATF_TP_ADD_TC(tp, rename_to_exchange_nonexisting); 971 ATF_TP_ADD_TC(tp, rename_to_self); 972 ATF_TP_ADD_TC(tp, rename_bad_flag); 973 ATF_TP_ADD_TC(tp, reopen_object); 974 ATF_TP_ADD_TC(tp, readonly_mmap_write); 975 ATF_TP_ADD_TC(tp, open_after_link); 976 ATF_TP_ADD_TC(tp, open_invalid_path); 977 ATF_TP_ADD_TC(tp, open_write_only); 978 ATF_TP_ADD_TC(tp, open_extra_flags); 979 ATF_TP_ADD_TC(tp, open_anon); 980 ATF_TP_ADD_TC(tp, open_anon_readonly); 981 ATF_TP_ADD_TC(tp, open_bad_path_pointer); 982 ATF_TP_ADD_TC(tp, open_path_too_long); 983 ATF_TP_ADD_TC(tp, open_nonexisting_object); 984 ATF_TP_ADD_TC(tp, open_create_existing_object); 985 ATF_TP_ADD_TC(tp, shm_functionality_across_fork); 986 ATF_TP_ADD_TC(tp, trunc_resets_object); 987 ATF_TP_ADD_TC(tp, unlink_bad_path_pointer); 988 ATF_TP_ADD_TC(tp, unlink_path_too_long); 989 ATF_TP_ADD_TC(tp, object_resize); 990 ATF_TP_ADD_TC(tp, cloexec); 991 ATF_TP_ADD_TC(tp, mode); 992 ATF_TP_ADD_TC(tp, fallocate); 993 994 return (atf_no_error()); 995 } 996