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 rc = shm_rename(test_path, test_path2, 0); 236 if (rc != -1) 237 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly"); 238 239 if (errno != ENOENT) 240 atf_tc_fail("Expected ENOENT to rename of nonexistent shm"); 241 } 242 243 ATF_TC_WITHOUT_HEAD(rename_to_anon); 244 ATF_TC_BODY(rename_to_anon, tc) 245 { 246 int rc; 247 248 gen_test_path(); 249 rc = shm_rename(test_path, SHM_ANON, 0); 250 if (rc != -1) 251 atf_tc_fail("shm_rename to SHM_ANON succeeded unexpectedly"); 252 } 253 254 ATF_TC_WITHOUT_HEAD(rename_to_replace); 255 ATF_TC_BODY(rename_to_replace, tc) 256 { 257 char expected_value; 258 int fd; 259 int fd2; 260 261 // Some contents we can verify later 262 expected_value = 'g'; 263 264 gen_test_path(); 265 fd = scribble_object(test_path, expected_value); 266 close(fd); 267 268 // Give the other some different value so we can detect success 269 gen_test_path2(); 270 fd2 = scribble_object(test_path2, 'h'); 271 close(fd2); 272 273 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 0) == 0, 274 "shm_rename failed; errno=%d", errno); 275 276 // Read back renamed; verify contents 277 verify_object(test_path2, expected_value); 278 } 279 280 ATF_TC_WITHOUT_HEAD(rename_to_noreplace); 281 ATF_TC_BODY(rename_to_noreplace, tc) 282 { 283 char expected_value_from; 284 char expected_value_to; 285 int fd_from; 286 int fd_to; 287 int rc; 288 289 // Some contents we can verify later 290 expected_value_from = 'g'; 291 gen_test_path(); 292 fd_from = scribble_object(test_path, expected_value_from); 293 close(fd_from); 294 295 // Give the other some different value so we can detect success 296 expected_value_to = 'h'; 297 gen_test_path2(); 298 fd_to = scribble_object(test_path2, expected_value_to); 299 close(fd_to); 300 301 rc = shm_rename(test_path, test_path2, SHM_RENAME_NOREPLACE); 302 ATF_REQUIRE_MSG((rc == -1) && (errno == EEXIST), 303 "shm_rename didn't fail as expected; errno: %d; return: %d", errno, 304 rc); 305 306 // Read back renamed; verify contents 307 verify_object(test_path2, expected_value_to); 308 } 309 310 ATF_TC_WITHOUT_HEAD(rename_to_exchange); 311 ATF_TC_BODY(rename_to_exchange, tc) 312 { 313 char expected_value_from; 314 char expected_value_to; 315 int fd_from; 316 int fd_to; 317 318 // Some contents we can verify later 319 expected_value_from = 'g'; 320 gen_test_path(); 321 fd_from = scribble_object(test_path, expected_value_from); 322 close(fd_from); 323 324 // Give the other some different value so we can detect success 325 expected_value_to = 'h'; 326 gen_test_path2(); 327 fd_to = scribble_object(test_path2, expected_value_to); 328 close(fd_to); 329 330 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 331 SHM_RENAME_EXCHANGE) == 0, 332 "shm_rename failed; errno=%d", errno); 333 334 // Read back renamed; verify contents 335 verify_object(test_path, expected_value_to); 336 verify_object(test_path2, expected_value_from); 337 } 338 339 ATF_TC_WITHOUT_HEAD(rename_to_exchange_nonexisting); 340 ATF_TC_BODY(rename_to_exchange_nonexisting, tc) 341 { 342 char expected_value_from; 343 int fd_from; 344 345 // Some contents we can verify later 346 expected_value_from = 'g'; 347 gen_test_path(); 348 fd_from = scribble_object(test_path, expected_value_from); 349 close(fd_from); 350 351 gen_test_path2(); 352 353 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 354 SHM_RENAME_EXCHANGE) == 0, 355 "shm_rename failed; errno=%d", errno); 356 357 // Read back renamed; verify contents 358 verify_object(test_path2, expected_value_from); 359 } 360 361 ATF_TC_WITHOUT_HEAD(rename_to_self); 362 ATF_TC_BODY(rename_to_self, tc) 363 { 364 int fd; 365 char expected_value; 366 367 expected_value = 't'; 368 369 gen_test_path(); 370 fd = scribble_object(test_path, expected_value); 371 close(fd); 372 373 ATF_REQUIRE_MSG(shm_rename(test_path, test_path, 0) == 0, 374 "shm_rename failed; errno=%d", errno); 375 376 verify_object(test_path, expected_value); 377 } 378 379 ATF_TC_WITHOUT_HEAD(rename_bad_flag); 380 ATF_TC_BODY(rename_bad_flag, tc) 381 { 382 int fd; 383 int rc; 384 385 /* Make sure we don't fail out due to ENOENT */ 386 gen_test_path(); 387 gen_test_path2(); 388 fd = scribble_object(test_path, 'd'); 389 close(fd); 390 fd = scribble_object(test_path2, 'd'); 391 close(fd); 392 393 /* 394 * Note: if we end up with enough flags that we use all the bits, 395 * then remove this test completely. 396 */ 397 rc = shm_rename(test_path, test_path2, INT_MIN); 398 ATF_REQUIRE_MSG((rc == -1) && (errno == EINVAL), 399 "shm_rename should have failed with EINVAL; got: return=%d, " 400 "errno=%d", rc, errno); 401 } 402 403 ATF_TC_WITHOUT_HEAD(reopen_object); 404 ATF_TC_BODY(reopen_object, tc) 405 { 406 char *page; 407 int fd, pagesize; 408 409 ATF_REQUIRE(0 < (pagesize = getpagesize())); 410 411 gen_test_path(); 412 fd = scribble_object(test_path, '1'); 413 close(fd); 414 415 fd = shm_open(test_path, O_RDONLY, 0777); 416 if (fd < 0) 417 atf_tc_fail("shm_open(2) failed; errno=%d", errno); 418 419 page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0); 420 if (page == MAP_FAILED) 421 atf_tc_fail("mmap(2) failed; errno=%d", errno); 422 423 if (page[0] != '1') 424 atf_tc_fail("missing data ('%c' != '1')", page[0]); 425 426 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 427 errno); 428 close(fd); 429 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 430 "shm_unlink failed; errno=%d", errno); 431 } 432 433 ATF_TC_WITHOUT_HEAD(readonly_mmap_write); 434 ATF_TC_BODY(readonly_mmap_write, tc) 435 { 436 char *page; 437 int fd, pagesize; 438 439 ATF_REQUIRE(0 < (pagesize = getpagesize())); 440 441 gen_test_path(); 442 443 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); 444 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 445 446 /* PROT_WRITE should fail with EACCES. */ 447 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 448 if (page != MAP_FAILED) 449 atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly"); 450 451 if (errno != EACCES) 452 atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; " 453 "errno=%d", errno); 454 455 close(fd); 456 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 457 "shm_unlink failed; errno=%d", errno); 458 } 459 460 ATF_TC_WITHOUT_HEAD(open_after_link); 461 ATF_TC_BODY(open_after_link, tc) 462 { 463 int fd; 464 465 gen_test_path(); 466 467 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); 468 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno); 469 close(fd); 470 471 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d", 472 errno); 473 474 shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT); 475 } 476 477 ATF_TC_WITHOUT_HEAD(open_invalid_path); 478 ATF_TC_BODY(open_invalid_path, tc) 479 { 480 481 shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL); 482 } 483 484 ATF_TC_WITHOUT_HEAD(open_write_only); 485 ATF_TC_BODY(open_write_only, tc) 486 { 487 488 gen_test_path(); 489 490 shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL); 491 } 492 493 ATF_TC_WITHOUT_HEAD(open_extra_flags); 494 ATF_TC_BODY(open_extra_flags, tc) 495 { 496 497 gen_test_path(); 498 499 shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL); 500 } 501 502 ATF_TC_WITHOUT_HEAD(open_anon); 503 ATF_TC_BODY(open_anon, tc) 504 { 505 int fd; 506 507 fd = shm_open(SHM_ANON, O_RDWR, 0777); 508 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 509 close(fd); 510 } 511 512 ATF_TC_WITHOUT_HEAD(open_anon_readonly); 513 ATF_TC_BODY(open_anon_readonly, tc) 514 { 515 516 shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL); 517 } 518 519 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer); 520 ATF_TC_BODY(open_bad_path_pointer, tc) 521 { 522 523 shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT); 524 } 525 526 ATF_TC_WITHOUT_HEAD(open_path_too_long); 527 ATF_TC_BODY(open_path_too_long, tc) 528 { 529 char *page; 530 531 page = malloc(MAXPATHLEN + 1); 532 memset(page, 'a', MAXPATHLEN); 533 page[MAXPATHLEN] = '\0'; 534 shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG); 535 free(page); 536 } 537 538 ATF_TC_WITHOUT_HEAD(open_nonexisting_object); 539 ATF_TC_BODY(open_nonexisting_object, tc) 540 { 541 542 shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT); 543 } 544 545 ATF_TC_WITHOUT_HEAD(open_create_existing_object); 546 ATF_TC_BODY(open_create_existing_object, tc) 547 { 548 int fd; 549 550 gen_test_path(); 551 552 fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777); 553 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 554 close(fd); 555 556 shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL, 557 0777, EEXIST); 558 559 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 560 "shm_unlink failed; errno=%d", errno); 561 } 562 563 ATF_TC_WITHOUT_HEAD(trunc_resets_object); 564 ATF_TC_BODY(trunc_resets_object, tc) 565 { 566 struct stat sb; 567 int fd; 568 569 gen_test_path(); 570 571 /* Create object and set size to 1024. */ 572 fd = shm_open(test_path, O_RDWR | O_CREAT, 0777); 573 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno); 574 ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1, 575 "ftruncate failed; errno=%d", errno); 576 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1, 577 "fstat(1) failed; errno=%d", errno); 578 ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size); 579 close(fd); 580 581 /* Open with O_TRUNC which should reset size to 0. */ 582 fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777); 583 ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno); 584 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1, 585 "fstat(2) failed; errno=%d", errno); 586 ATF_REQUIRE_MSG(sb.st_size == 0, 587 "size was not 0 after truncation: %d", (int)sb.st_size); 588 close(fd); 589 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 590 "shm_unlink failed; errno=%d", errno); 591 } 592 593 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer); 594 ATF_TC_BODY(unlink_bad_path_pointer, tc) 595 { 596 597 shm_unlink_should_fail((char *)1024, EFAULT); 598 } 599 600 ATF_TC_WITHOUT_HEAD(unlink_path_too_long); 601 ATF_TC_BODY(unlink_path_too_long, tc) 602 { 603 char *page; 604 605 page = malloc(MAXPATHLEN + 1); 606 memset(page, 'a', MAXPATHLEN); 607 page[MAXPATHLEN] = '\0'; 608 shm_unlink_should_fail(page, ENAMETOOLONG); 609 free(page); 610 } 611 612 ATF_TC_WITHOUT_HEAD(object_resize); 613 ATF_TC_BODY(object_resize, tc) 614 { 615 pid_t pid; 616 struct stat sb; 617 char *page; 618 int fd, pagesize, status; 619 620 ATF_REQUIRE(0 < (pagesize = getpagesize())); 621 622 /* Start off with a size of a single page. */ 623 fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777); 624 if (fd < 0) 625 atf_tc_fail("shm_open failed; errno=%d", errno); 626 627 if (ftruncate(fd, pagesize) < 0) 628 atf_tc_fail("ftruncate(1) failed; errno=%d", errno); 629 630 if (fstat(fd, &sb) < 0) 631 atf_tc_fail("fstat(1) failed; errno=%d", errno); 632 633 if (sb.st_size != pagesize) 634 atf_tc_fail("first resize failed (%d != %d)", 635 (int)sb.st_size, pagesize); 636 637 /* Write a '1' to the first byte. */ 638 page = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 639 if (page == MAP_FAILED) 640 atf_tc_fail("mmap(1)"); 641 642 page[0] = '1'; 643 644 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d", 645 errno); 646 647 /* Grow the object to 2 pages. */ 648 if (ftruncate(fd, pagesize * 2) < 0) 649 atf_tc_fail("ftruncate(2) failed; errno=%d", errno); 650 651 if (fstat(fd, &sb) < 0) 652 atf_tc_fail("fstat(2) failed; errno=%d", errno); 653 654 if (sb.st_size != pagesize * 2) 655 atf_tc_fail("second resize failed (%d != %d)", 656 (int)sb.st_size, pagesize * 2); 657 658 /* Check for '1' at the first byte. */ 659 page = mmap(0, pagesize * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 660 if (page == MAP_FAILED) 661 atf_tc_fail("mmap(2) failed; errno=%d", errno); 662 663 if (page[0] != '1') 664 atf_tc_fail("'%c' != '1'", page[0]); 665 666 /* Write a '2' at the start of the second page. */ 667 page[pagesize] = '2'; 668 669 /* Shrink the object back to 1 page. */ 670 if (ftruncate(fd, pagesize) < 0) 671 atf_tc_fail("ftruncate(3) failed; errno=%d", errno); 672 673 if (fstat(fd, &sb) < 0) 674 atf_tc_fail("fstat(3) failed; errno=%d", errno); 675 676 if (sb.st_size != pagesize) 677 atf_tc_fail("third resize failed (%d != %d)", 678 (int)sb.st_size, pagesize); 679 680 /* 681 * Fork a child process to make sure the second page is no 682 * longer valid. 683 */ 684 pid = fork(); 685 if (pid == -1) 686 atf_tc_fail("fork failed; errno=%d", errno); 687 688 if (pid == 0) { 689 struct rlimit lim; 690 char c; 691 692 /* Don't generate a core dump. */ 693 ATF_REQUIRE(getrlimit(RLIMIT_CORE, &lim) == 0); 694 lim.rlim_cur = 0; 695 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &lim) == 0); 696 697 /* 698 * The previous ftruncate(2) shrunk the backing object 699 * so that this address is no longer valid, so reading 700 * from it should trigger a SIGBUS. 701 */ 702 c = page[pagesize]; 703 fprintf(stderr, "child: page 1: '%c'\n", c); 704 exit(0); 705 } 706 707 if (wait(&status) < 0) 708 atf_tc_fail("wait failed; errno=%d", errno); 709 710 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS) 711 atf_tc_fail("child terminated with status %x", status); 712 713 /* Grow the object back to 2 pages. */ 714 if (ftruncate(fd, pagesize * 2) < 0) 715 atf_tc_fail("ftruncate(2) failed; errno=%d", errno); 716 717 if (fstat(fd, &sb) < 0) 718 atf_tc_fail("fstat(2) failed; errno=%d", errno); 719 720 if (sb.st_size != pagesize * 2) 721 atf_tc_fail("fourth resize failed (%d != %d)", 722 (int)sb.st_size, pagesize); 723 724 /* 725 * Note that the mapping at 'page' for the second page is 726 * still valid, and now that the shm object has been grown 727 * back up to 2 pages, there is now memory backing this page 728 * so the read will work. However, the data should be zero 729 * rather than '2' as the old data was thrown away when the 730 * object was shrunk and the new pages when an object are 731 * grown are zero-filled. 732 */ 733 if (page[pagesize] != 0) 734 atf_tc_fail("invalid data at %d: %x != 0", 735 pagesize, (int)page[pagesize]); 736 737 close(fd); 738 } 739 740 /* Signal handler which does nothing. */ 741 static void 742 ignoreit(int sig __unused) 743 { 744 ; 745 } 746 747 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork); 748 ATF_TC_BODY(shm_functionality_across_fork, tc) 749 { 750 char *cp, c; 751 int error, desc, rv; 752 long scval; 753 sigset_t ss; 754 struct sigaction sa; 755 void *region; 756 size_t i, psize; 757 758 #ifndef _POSIX_SHARED_MEMORY_OBJECTS 759 printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n"); 760 #else 761 printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n", 762 (long)_POSIX_SHARED_MEMORY_OBJECTS - 0); 763 if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1) 764 printf("***Indicates this feature may be unsupported!\n"); 765 #endif 766 errno = 0; 767 scval = sysconf(_SC_SHARED_MEMORY_OBJECTS); 768 if (scval == -1 && errno != 0) { 769 atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; " 770 "errno=%d", errno); 771 } else { 772 printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n", 773 scval); 774 if (scval == -1) 775 printf("***Indicates this feature is unsupported!\n"); 776 } 777 778 errno = 0; 779 scval = sysconf(_SC_PAGESIZE); 780 if (scval == -1 && errno != 0) { 781 atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno); 782 } else if (scval <= 0) { 783 fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld", 784 scval); 785 psize = 4096; 786 } else { 787 printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval); 788 psize = scval; 789 } 790 791 gen_test_path(); 792 desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600); 793 794 ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno); 795 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0, 796 "shm_unlink failed; errno=%d", errno); 797 ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1, 798 "ftruncate failed; errno=%d", errno); 799 800 region = mmap(NULL, psize, PROT_READ | PROT_WRITE, MAP_SHARED, desc, 0); 801 ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno); 802 memset(region, '\377', psize); 803 804 sa.sa_flags = 0; 805 sa.sa_handler = ignoreit; 806 sigemptyset(&sa.sa_mask); 807 ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0, 808 "sigaction failed; errno=%d", errno); 809 810 sigemptyset(&ss); 811 sigaddset(&ss, SIGUSR1); 812 ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0, 813 "sigprocmask failed; errno=%d", errno); 814 815 rv = fork(); 816 ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno); 817 if (rv == 0) { 818 sigemptyset(&ss); 819 sigsuspend(&ss); 820 821 for (cp = region; cp < (char *)region + psize; cp++) { 822 if (*cp != '\151') 823 _exit(1); 824 } 825 if (lseek(desc, 0, SEEK_SET) == -1) 826 _exit(1); 827 for (i = 0; i < psize; i++) { 828 error = read(desc, &c, 1); 829 if (c != '\151') 830 _exit(1); 831 } 832 _exit(0); 833 } else { 834 int status; 835 836 memset(region, '\151', psize - 2); 837 error = pwrite(desc, region, 2, psize - 2); 838 if (error != 2) { 839 if (error >= 0) 840 atf_tc_fail("short write; %d bytes written", 841 error); 842 else 843 atf_tc_fail("shmfd write"); 844 } 845 kill(rv, SIGUSR1); 846 waitpid(rv, &status, 0); 847 848 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 849 printf("Functionality test successful\n"); 850 } else if (WIFEXITED(status)) { 851 atf_tc_fail("Child process exited with status %d", 852 WEXITSTATUS(status)); 853 } else { 854 atf_tc_fail("Child process terminated with %s", 855 strsignal(WTERMSIG(status))); 856 } 857 } 858 859 ATF_REQUIRE_MSG(munmap(region, psize) == 0, "munmap failed; errno=%d", 860 errno); 861 shm_unlink(test_path); 862 } 863 864 ATF_TC_WITHOUT_HEAD(cloexec); 865 ATF_TC_BODY(cloexec, tc) 866 { 867 int fd; 868 869 gen_test_path(); 870 871 /* shm_open(2) is required to set FD_CLOEXEC */ 872 fd = shm_open(SHM_ANON, O_RDWR, 0777); 873 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 874 ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0); 875 close(fd); 876 877 /* Also make sure that named shm is correct */ 878 fd = shm_open(test_path, O_CREAT | O_RDWR, 0600); 879 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 880 ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0); 881 close(fd); 882 } 883 884 ATF_TC_WITHOUT_HEAD(mode); 885 ATF_TC_BODY(mode, tc) 886 { 887 struct stat st; 888 int fd; 889 mode_t restore_mask; 890 891 gen_test_path(); 892 893 /* Remove inhibitions from umask */ 894 restore_mask = umask(0); 895 fd = shm_open(test_path, O_CREAT | O_RDWR, 0600); 896 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 897 ATF_REQUIRE(fstat(fd, &st) == 0); 898 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0600); 899 close(fd); 900 ATF_REQUIRE(shm_unlink(test_path) == 0); 901 902 fd = shm_open(test_path, O_CREAT | O_RDWR, 0660); 903 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 904 ATF_REQUIRE(fstat(fd, &st) == 0); 905 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0660); 906 close(fd); 907 ATF_REQUIRE(shm_unlink(test_path) == 0); 908 909 fd = shm_open(test_path, O_CREAT | O_RDWR, 0666); 910 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 911 ATF_REQUIRE(fstat(fd, &st) == 0); 912 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0666); 913 close(fd); 914 ATF_REQUIRE(shm_unlink(test_path) == 0); 915 916 umask(restore_mask); 917 } 918 919 ATF_TP_ADD_TCS(tp) 920 { 921 922 ATF_TP_ADD_TC(tp, remap_object); 923 ATF_TP_ADD_TC(tp, rename_from_anon); 924 ATF_TP_ADD_TC(tp, rename_bad_path_pointer); 925 ATF_TP_ADD_TC(tp, rename_from_nonexisting); 926 ATF_TP_ADD_TC(tp, rename_to_anon); 927 ATF_TP_ADD_TC(tp, rename_to_replace); 928 ATF_TP_ADD_TC(tp, rename_to_noreplace); 929 ATF_TP_ADD_TC(tp, rename_to_exchange); 930 ATF_TP_ADD_TC(tp, rename_to_exchange_nonexisting); 931 ATF_TP_ADD_TC(tp, rename_to_self); 932 ATF_TP_ADD_TC(tp, rename_bad_flag); 933 ATF_TP_ADD_TC(tp, reopen_object); 934 ATF_TP_ADD_TC(tp, readonly_mmap_write); 935 ATF_TP_ADD_TC(tp, open_after_link); 936 ATF_TP_ADD_TC(tp, open_invalid_path); 937 ATF_TP_ADD_TC(tp, open_write_only); 938 ATF_TP_ADD_TC(tp, open_extra_flags); 939 ATF_TP_ADD_TC(tp, open_anon); 940 ATF_TP_ADD_TC(tp, open_anon_readonly); 941 ATF_TP_ADD_TC(tp, open_bad_path_pointer); 942 ATF_TP_ADD_TC(tp, open_path_too_long); 943 ATF_TP_ADD_TC(tp, open_nonexisting_object); 944 ATF_TP_ADD_TC(tp, open_create_existing_object); 945 ATF_TP_ADD_TC(tp, shm_functionality_across_fork); 946 ATF_TP_ADD_TC(tp, trunc_resets_object); 947 ATF_TP_ADD_TC(tp, unlink_bad_path_pointer); 948 ATF_TP_ADD_TC(tp, unlink_path_too_long); 949 ATF_TP_ADD_TC(tp, object_resize); 950 ATF_TP_ADD_TC(tp, cloexec); 951 ATF_TP_ADD_TC(tp, mode); 952 953 return (atf_no_error()); 954 } 955