1 #define _GNU_SOURCE 2 #define __EXPORTED_HEADERS__ 3 4 #include <errno.h> 5 #include <inttypes.h> 6 #include <limits.h> 7 #include <linux/falloc.h> 8 #include <linux/fcntl.h> 9 #include <linux/memfd.h> 10 #include <sched.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <signal.h> 14 #include <string.h> 15 #include <sys/mman.h> 16 #include <sys/stat.h> 17 #include <sys/syscall.h> 18 #include <sys/wait.h> 19 #include <unistd.h> 20 21 #define MEMFD_STR "memfd:" 22 #define SHARED_FT_STR "(shared file-table)" 23 24 #define MFD_DEF_SIZE 8192 25 #define STACK_SIZE 65536 26 27 /* 28 * Default is not to test hugetlbfs 29 */ 30 static int hugetlbfs_test; 31 static size_t mfd_def_size = MFD_DEF_SIZE; 32 33 /* 34 * Copied from mlock2-tests.c 35 */ 36 static unsigned long default_huge_page_size(void) 37 { 38 unsigned long hps = 0; 39 char *line = NULL; 40 size_t linelen = 0; 41 FILE *f = fopen("/proc/meminfo", "r"); 42 43 if (!f) 44 return 0; 45 while (getline(&line, &linelen, f) > 0) { 46 if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) { 47 hps <<= 10; 48 break; 49 } 50 } 51 52 free(line); 53 fclose(f); 54 return hps; 55 } 56 57 static int sys_memfd_create(const char *name, 58 unsigned int flags) 59 { 60 if (hugetlbfs_test) 61 flags |= MFD_HUGETLB; 62 63 return syscall(__NR_memfd_create, name, flags); 64 } 65 66 static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags) 67 { 68 int r, fd; 69 70 fd = sys_memfd_create(name, flags); 71 if (fd < 0) { 72 printf("memfd_create(\"%s\", %u) failed: %m\n", 73 name, flags); 74 abort(); 75 } 76 77 r = ftruncate(fd, sz); 78 if (r < 0) { 79 printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz); 80 abort(); 81 } 82 83 return fd; 84 } 85 86 static void mfd_fail_new(const char *name, unsigned int flags) 87 { 88 int r; 89 90 r = sys_memfd_create(name, flags); 91 if (r >= 0) { 92 printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n", 93 name, flags); 94 close(r); 95 abort(); 96 } 97 } 98 99 static unsigned int mfd_assert_get_seals(int fd) 100 { 101 int r; 102 103 r = fcntl(fd, F_GET_SEALS); 104 if (r < 0) { 105 printf("GET_SEALS(%d) failed: %m\n", fd); 106 abort(); 107 } 108 109 return (unsigned int)r; 110 } 111 112 static void mfd_assert_has_seals(int fd, unsigned int seals) 113 { 114 unsigned int s; 115 116 s = mfd_assert_get_seals(fd); 117 if (s != seals) { 118 printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd); 119 abort(); 120 } 121 } 122 123 static void mfd_assert_add_seals(int fd, unsigned int seals) 124 { 125 int r; 126 unsigned int s; 127 128 s = mfd_assert_get_seals(fd); 129 r = fcntl(fd, F_ADD_SEALS, seals); 130 if (r < 0) { 131 printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals); 132 abort(); 133 } 134 } 135 136 static void mfd_fail_add_seals(int fd, unsigned int seals) 137 { 138 int r; 139 unsigned int s; 140 141 r = fcntl(fd, F_GET_SEALS); 142 if (r < 0) 143 s = 0; 144 else 145 s = (unsigned int)r; 146 147 r = fcntl(fd, F_ADD_SEALS, seals); 148 if (r >= 0) { 149 printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n", 150 fd, s, seals); 151 abort(); 152 } 153 } 154 155 static void mfd_assert_size(int fd, size_t size) 156 { 157 struct stat st; 158 int r; 159 160 r = fstat(fd, &st); 161 if (r < 0) { 162 printf("fstat(%d) failed: %m\n", fd); 163 abort(); 164 } else if (st.st_size != size) { 165 printf("wrong file size %lld, but expected %lld\n", 166 (long long)st.st_size, (long long)size); 167 abort(); 168 } 169 } 170 171 static int mfd_assert_dup(int fd) 172 { 173 int r; 174 175 r = dup(fd); 176 if (r < 0) { 177 printf("dup(%d) failed: %m\n", fd); 178 abort(); 179 } 180 181 return r; 182 } 183 184 static void *mfd_assert_mmap_shared(int fd) 185 { 186 void *p; 187 188 p = mmap(NULL, 189 mfd_def_size, 190 PROT_READ | PROT_WRITE, 191 MAP_SHARED, 192 fd, 193 0); 194 if (p == MAP_FAILED) { 195 printf("mmap() failed: %m\n"); 196 abort(); 197 } 198 199 return p; 200 } 201 202 static void *mfd_assert_mmap_private(int fd) 203 { 204 void *p; 205 206 p = mmap(NULL, 207 mfd_def_size, 208 PROT_READ, 209 MAP_PRIVATE, 210 fd, 211 0); 212 if (p == MAP_FAILED) { 213 printf("mmap() failed: %m\n"); 214 abort(); 215 } 216 217 return p; 218 } 219 220 static int mfd_assert_open(int fd, int flags, mode_t mode) 221 { 222 char buf[512]; 223 int r; 224 225 sprintf(buf, "/proc/self/fd/%d", fd); 226 r = open(buf, flags, mode); 227 if (r < 0) { 228 printf("open(%s) failed: %m\n", buf); 229 abort(); 230 } 231 232 return r; 233 } 234 235 static void mfd_fail_open(int fd, int flags, mode_t mode) 236 { 237 char buf[512]; 238 int r; 239 240 sprintf(buf, "/proc/self/fd/%d", fd); 241 r = open(buf, flags, mode); 242 if (r >= 0) { 243 printf("open(%s) didn't fail as expected\n", buf); 244 abort(); 245 } 246 } 247 248 static void mfd_assert_read(int fd) 249 { 250 char buf[16]; 251 void *p; 252 ssize_t l; 253 254 l = read(fd, buf, sizeof(buf)); 255 if (l != sizeof(buf)) { 256 printf("read() failed: %m\n"); 257 abort(); 258 } 259 260 /* verify PROT_READ *is* allowed */ 261 p = mmap(NULL, 262 mfd_def_size, 263 PROT_READ, 264 MAP_PRIVATE, 265 fd, 266 0); 267 if (p == MAP_FAILED) { 268 printf("mmap() failed: %m\n"); 269 abort(); 270 } 271 munmap(p, mfd_def_size); 272 273 /* verify MAP_PRIVATE is *always* allowed (even writable) */ 274 p = mmap(NULL, 275 mfd_def_size, 276 PROT_READ | PROT_WRITE, 277 MAP_PRIVATE, 278 fd, 279 0); 280 if (p == MAP_FAILED) { 281 printf("mmap() failed: %m\n"); 282 abort(); 283 } 284 munmap(p, mfd_def_size); 285 } 286 287 static void mfd_assert_write(int fd) 288 { 289 ssize_t l; 290 void *p; 291 int r; 292 293 /* 294 * huegtlbfs does not support write, but we want to 295 * verify everything else here. 296 */ 297 if (!hugetlbfs_test) { 298 /* verify write() succeeds */ 299 l = write(fd, "\0\0\0\0", 4); 300 if (l != 4) { 301 printf("write() failed: %m\n"); 302 abort(); 303 } 304 } 305 306 /* verify PROT_READ | PROT_WRITE is allowed */ 307 p = mmap(NULL, 308 mfd_def_size, 309 PROT_READ | PROT_WRITE, 310 MAP_SHARED, 311 fd, 312 0); 313 if (p == MAP_FAILED) { 314 printf("mmap() failed: %m\n"); 315 abort(); 316 } 317 *(char *)p = 0; 318 munmap(p, mfd_def_size); 319 320 /* verify PROT_WRITE is allowed */ 321 p = mmap(NULL, 322 mfd_def_size, 323 PROT_WRITE, 324 MAP_SHARED, 325 fd, 326 0); 327 if (p == MAP_FAILED) { 328 printf("mmap() failed: %m\n"); 329 abort(); 330 } 331 *(char *)p = 0; 332 munmap(p, mfd_def_size); 333 334 /* verify PROT_READ with MAP_SHARED is allowed and a following 335 * mprotect(PROT_WRITE) allows writing */ 336 p = mmap(NULL, 337 mfd_def_size, 338 PROT_READ, 339 MAP_SHARED, 340 fd, 341 0); 342 if (p == MAP_FAILED) { 343 printf("mmap() failed: %m\n"); 344 abort(); 345 } 346 347 r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE); 348 if (r < 0) { 349 printf("mprotect() failed: %m\n"); 350 abort(); 351 } 352 353 *(char *)p = 0; 354 munmap(p, mfd_def_size); 355 356 /* verify PUNCH_HOLE works */ 357 r = fallocate(fd, 358 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 359 0, 360 mfd_def_size); 361 if (r < 0) { 362 printf("fallocate(PUNCH_HOLE) failed: %m\n"); 363 abort(); 364 } 365 } 366 367 static void mfd_fail_write(int fd) 368 { 369 ssize_t l; 370 void *p; 371 int r; 372 373 /* verify write() fails */ 374 l = write(fd, "data", 4); 375 if (l != -EPERM) { 376 printf("expected EPERM on write(), but got %d: %m\n", (int)l); 377 abort(); 378 } 379 380 /* verify PROT_READ | PROT_WRITE is not allowed */ 381 p = mmap(NULL, 382 mfd_def_size, 383 PROT_READ | PROT_WRITE, 384 MAP_SHARED, 385 fd, 386 0); 387 if (p != MAP_FAILED) { 388 printf("mmap() didn't fail as expected\n"); 389 abort(); 390 } 391 392 /* verify PROT_WRITE is not allowed */ 393 p = mmap(NULL, 394 mfd_def_size, 395 PROT_WRITE, 396 MAP_SHARED, 397 fd, 398 0); 399 if (p != MAP_FAILED) { 400 printf("mmap() didn't fail as expected\n"); 401 abort(); 402 } 403 404 /* Verify PROT_READ with MAP_SHARED with a following mprotect is not 405 * allowed. Note that for r/w the kernel already prevents the mmap. */ 406 p = mmap(NULL, 407 mfd_def_size, 408 PROT_READ, 409 MAP_SHARED, 410 fd, 411 0); 412 if (p != MAP_FAILED) { 413 r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE); 414 if (r >= 0) { 415 printf("mmap()+mprotect() didn't fail as expected\n"); 416 abort(); 417 } 418 } 419 420 /* verify PUNCH_HOLE fails */ 421 r = fallocate(fd, 422 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 423 0, 424 mfd_def_size); 425 if (r >= 0) { 426 printf("fallocate(PUNCH_HOLE) didn't fail as expected\n"); 427 abort(); 428 } 429 } 430 431 static void mfd_assert_shrink(int fd) 432 { 433 int r, fd2; 434 435 r = ftruncate(fd, mfd_def_size / 2); 436 if (r < 0) { 437 printf("ftruncate(SHRINK) failed: %m\n"); 438 abort(); 439 } 440 441 mfd_assert_size(fd, mfd_def_size / 2); 442 443 fd2 = mfd_assert_open(fd, 444 O_RDWR | O_CREAT | O_TRUNC, 445 S_IRUSR | S_IWUSR); 446 close(fd2); 447 448 mfd_assert_size(fd, 0); 449 } 450 451 static void mfd_fail_shrink(int fd) 452 { 453 int r; 454 455 r = ftruncate(fd, mfd_def_size / 2); 456 if (r >= 0) { 457 printf("ftruncate(SHRINK) didn't fail as expected\n"); 458 abort(); 459 } 460 461 mfd_fail_open(fd, 462 O_RDWR | O_CREAT | O_TRUNC, 463 S_IRUSR | S_IWUSR); 464 } 465 466 static void mfd_assert_grow(int fd) 467 { 468 int r; 469 470 r = ftruncate(fd, mfd_def_size * 2); 471 if (r < 0) { 472 printf("ftruncate(GROW) failed: %m\n"); 473 abort(); 474 } 475 476 mfd_assert_size(fd, mfd_def_size * 2); 477 478 r = fallocate(fd, 479 0, 480 0, 481 mfd_def_size * 4); 482 if (r < 0) { 483 printf("fallocate(ALLOC) failed: %m\n"); 484 abort(); 485 } 486 487 mfd_assert_size(fd, mfd_def_size * 4); 488 } 489 490 static void mfd_fail_grow(int fd) 491 { 492 int r; 493 494 r = ftruncate(fd, mfd_def_size * 2); 495 if (r >= 0) { 496 printf("ftruncate(GROW) didn't fail as expected\n"); 497 abort(); 498 } 499 500 r = fallocate(fd, 501 0, 502 0, 503 mfd_def_size * 4); 504 if (r >= 0) { 505 printf("fallocate(ALLOC) didn't fail as expected\n"); 506 abort(); 507 } 508 } 509 510 static void mfd_assert_grow_write(int fd) 511 { 512 static char *buf; 513 ssize_t l; 514 515 buf = malloc(mfd_def_size * 8); 516 if (!buf) { 517 printf("malloc(%d) failed: %m\n", mfd_def_size * 8); 518 abort(); 519 } 520 521 l = pwrite(fd, buf, mfd_def_size * 8, 0); 522 if (l != (mfd_def_size * 8)) { 523 printf("pwrite() failed: %m\n"); 524 abort(); 525 } 526 527 mfd_assert_size(fd, mfd_def_size * 8); 528 } 529 530 static void mfd_fail_grow_write(int fd) 531 { 532 static char *buf; 533 ssize_t l; 534 535 buf = malloc(mfd_def_size * 8); 536 if (!buf) { 537 printf("malloc(%d) failed: %m\n", mfd_def_size * 8); 538 abort(); 539 } 540 541 l = pwrite(fd, buf, mfd_def_size * 8, 0); 542 if (l == (mfd_def_size * 8)) { 543 printf("pwrite() didn't fail as expected\n"); 544 abort(); 545 } 546 } 547 548 static int idle_thread_fn(void *arg) 549 { 550 sigset_t set; 551 int sig; 552 553 /* dummy waiter; SIGTERM terminates us anyway */ 554 sigemptyset(&set); 555 sigaddset(&set, SIGTERM); 556 sigwait(&set, &sig); 557 558 return 0; 559 } 560 561 static pid_t spawn_idle_thread(unsigned int flags) 562 { 563 uint8_t *stack; 564 pid_t pid; 565 566 stack = malloc(STACK_SIZE); 567 if (!stack) { 568 printf("malloc(STACK_SIZE) failed: %m\n"); 569 abort(); 570 } 571 572 pid = clone(idle_thread_fn, 573 stack + STACK_SIZE, 574 SIGCHLD | flags, 575 NULL); 576 if (pid < 0) { 577 printf("clone() failed: %m\n"); 578 abort(); 579 } 580 581 return pid; 582 } 583 584 static void join_idle_thread(pid_t pid) 585 { 586 kill(pid, SIGTERM); 587 waitpid(pid, NULL, 0); 588 } 589 590 /* 591 * Test memfd_create() syscall 592 * Verify syscall-argument validation, including name checks, flag validation 593 * and more. 594 */ 595 static void test_create(void) 596 { 597 char buf[2048]; 598 int fd; 599 600 printf("%s CREATE\n", MEMFD_STR); 601 602 /* test NULL name */ 603 mfd_fail_new(NULL, 0); 604 605 /* test over-long name (not zero-terminated) */ 606 memset(buf, 0xff, sizeof(buf)); 607 mfd_fail_new(buf, 0); 608 609 /* test over-long zero-terminated name */ 610 memset(buf, 0xff, sizeof(buf)); 611 buf[sizeof(buf) - 1] = 0; 612 mfd_fail_new(buf, 0); 613 614 /* verify "" is a valid name */ 615 fd = mfd_assert_new("", 0, 0); 616 close(fd); 617 618 /* verify invalid O_* open flags */ 619 mfd_fail_new("", 0x0100); 620 mfd_fail_new("", ~MFD_CLOEXEC); 621 mfd_fail_new("", ~MFD_ALLOW_SEALING); 622 mfd_fail_new("", ~0); 623 mfd_fail_new("", 0x80000000U); 624 625 /* verify MFD_CLOEXEC is allowed */ 626 fd = mfd_assert_new("", 0, MFD_CLOEXEC); 627 close(fd); 628 629 if (!hugetlbfs_test) { 630 /* verify MFD_ALLOW_SEALING is allowed */ 631 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING); 632 close(fd); 633 634 /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */ 635 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC); 636 close(fd); 637 } else { 638 /* sealing is not supported on hugetlbfs */ 639 mfd_fail_new("", MFD_ALLOW_SEALING); 640 } 641 } 642 643 /* 644 * Test basic sealing 645 * A very basic sealing test to see whether setting/retrieving seals works. 646 */ 647 static void test_basic(void) 648 { 649 int fd; 650 651 /* hugetlbfs does not contain sealing support */ 652 if (hugetlbfs_test) 653 return; 654 655 printf("%s BASIC\n", MEMFD_STR); 656 657 fd = mfd_assert_new("kern_memfd_basic", 658 mfd_def_size, 659 MFD_CLOEXEC | MFD_ALLOW_SEALING); 660 661 /* add basic seals */ 662 mfd_assert_has_seals(fd, 0); 663 mfd_assert_add_seals(fd, F_SEAL_SHRINK | 664 F_SEAL_WRITE); 665 mfd_assert_has_seals(fd, F_SEAL_SHRINK | 666 F_SEAL_WRITE); 667 668 /* add them again */ 669 mfd_assert_add_seals(fd, F_SEAL_SHRINK | 670 F_SEAL_WRITE); 671 mfd_assert_has_seals(fd, F_SEAL_SHRINK | 672 F_SEAL_WRITE); 673 674 /* add more seals and seal against sealing */ 675 mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL); 676 mfd_assert_has_seals(fd, F_SEAL_SHRINK | 677 F_SEAL_GROW | 678 F_SEAL_WRITE | 679 F_SEAL_SEAL); 680 681 /* verify that sealing no longer works */ 682 mfd_fail_add_seals(fd, F_SEAL_GROW); 683 mfd_fail_add_seals(fd, 0); 684 685 close(fd); 686 687 /* verify sealing does not work without MFD_ALLOW_SEALING */ 688 fd = mfd_assert_new("kern_memfd_basic", 689 mfd_def_size, 690 MFD_CLOEXEC); 691 mfd_assert_has_seals(fd, F_SEAL_SEAL); 692 mfd_fail_add_seals(fd, F_SEAL_SHRINK | 693 F_SEAL_GROW | 694 F_SEAL_WRITE); 695 mfd_assert_has_seals(fd, F_SEAL_SEAL); 696 close(fd); 697 } 698 699 /* 700 * hugetlbfs doesn't support seals or write, so just verify grow and shrink 701 * on a hugetlbfs file created via memfd_create. 702 */ 703 static void test_hugetlbfs_grow_shrink(void) 704 { 705 int fd; 706 707 printf("%s HUGETLBFS-GROW-SHRINK\n", MEMFD_STR); 708 709 fd = mfd_assert_new("kern_memfd_seal_write", 710 mfd_def_size, 711 MFD_CLOEXEC); 712 713 mfd_assert_read(fd); 714 mfd_assert_write(fd); 715 mfd_assert_shrink(fd); 716 mfd_assert_grow(fd); 717 718 close(fd); 719 } 720 721 /* 722 * Test SEAL_WRITE 723 * Test whether SEAL_WRITE actually prevents modifications. 724 */ 725 static void test_seal_write(void) 726 { 727 int fd; 728 729 /* 730 * hugetlbfs does not contain sealing or write support. Just test 731 * basic grow and shrink via test_hugetlbfs_grow_shrink. 732 */ 733 if (hugetlbfs_test) 734 return test_hugetlbfs_grow_shrink(); 735 736 printf("%s SEAL-WRITE\n", MEMFD_STR); 737 738 fd = mfd_assert_new("kern_memfd_seal_write", 739 mfd_def_size, 740 MFD_CLOEXEC | MFD_ALLOW_SEALING); 741 mfd_assert_has_seals(fd, 0); 742 mfd_assert_add_seals(fd, F_SEAL_WRITE); 743 mfd_assert_has_seals(fd, F_SEAL_WRITE); 744 745 mfd_assert_read(fd); 746 mfd_fail_write(fd); 747 mfd_assert_shrink(fd); 748 mfd_assert_grow(fd); 749 mfd_fail_grow_write(fd); 750 751 close(fd); 752 } 753 754 /* 755 * Test SEAL_SHRINK 756 * Test whether SEAL_SHRINK actually prevents shrinking 757 */ 758 static void test_seal_shrink(void) 759 { 760 int fd; 761 762 /* hugetlbfs does not contain sealing support */ 763 if (hugetlbfs_test) 764 return; 765 766 printf("%s SEAL-SHRINK\n", MEMFD_STR); 767 768 fd = mfd_assert_new("kern_memfd_seal_shrink", 769 mfd_def_size, 770 MFD_CLOEXEC | MFD_ALLOW_SEALING); 771 mfd_assert_has_seals(fd, 0); 772 mfd_assert_add_seals(fd, F_SEAL_SHRINK); 773 mfd_assert_has_seals(fd, F_SEAL_SHRINK); 774 775 mfd_assert_read(fd); 776 mfd_assert_write(fd); 777 mfd_fail_shrink(fd); 778 mfd_assert_grow(fd); 779 mfd_assert_grow_write(fd); 780 781 close(fd); 782 } 783 784 /* 785 * Test SEAL_GROW 786 * Test whether SEAL_GROW actually prevents growing 787 */ 788 static void test_seal_grow(void) 789 { 790 int fd; 791 792 /* hugetlbfs does not contain sealing support */ 793 if (hugetlbfs_test) 794 return; 795 796 printf("%s SEAL-GROW\n", MEMFD_STR); 797 798 fd = mfd_assert_new("kern_memfd_seal_grow", 799 mfd_def_size, 800 MFD_CLOEXEC | MFD_ALLOW_SEALING); 801 mfd_assert_has_seals(fd, 0); 802 mfd_assert_add_seals(fd, F_SEAL_GROW); 803 mfd_assert_has_seals(fd, F_SEAL_GROW); 804 805 mfd_assert_read(fd); 806 mfd_assert_write(fd); 807 mfd_assert_shrink(fd); 808 mfd_fail_grow(fd); 809 mfd_fail_grow_write(fd); 810 811 close(fd); 812 } 813 814 /* 815 * Test SEAL_SHRINK | SEAL_GROW 816 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing 817 */ 818 static void test_seal_resize(void) 819 { 820 int fd; 821 822 /* hugetlbfs does not contain sealing support */ 823 if (hugetlbfs_test) 824 return; 825 826 printf("%s SEAL-RESIZE\n", MEMFD_STR); 827 828 fd = mfd_assert_new("kern_memfd_seal_resize", 829 mfd_def_size, 830 MFD_CLOEXEC | MFD_ALLOW_SEALING); 831 mfd_assert_has_seals(fd, 0); 832 mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); 833 mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); 834 835 mfd_assert_read(fd); 836 mfd_assert_write(fd); 837 mfd_fail_shrink(fd); 838 mfd_fail_grow(fd); 839 mfd_fail_grow_write(fd); 840 841 close(fd); 842 } 843 844 /* 845 * hugetlbfs does not support seals. Basic test to dup the memfd created 846 * fd and perform some basic operations on it. 847 */ 848 static void hugetlbfs_dup(char *b_suffix) 849 { 850 int fd, fd2; 851 852 printf("%s HUGETLBFS-DUP %s\n", MEMFD_STR, b_suffix); 853 854 fd = mfd_assert_new("kern_memfd_share_dup", 855 mfd_def_size, 856 MFD_CLOEXEC); 857 858 fd2 = mfd_assert_dup(fd); 859 860 mfd_assert_read(fd); 861 mfd_assert_write(fd); 862 863 mfd_assert_shrink(fd2); 864 mfd_assert_grow(fd2); 865 866 close(fd2); 867 close(fd); 868 } 869 870 /* 871 * Test sharing via dup() 872 * Test that seals are shared between dupped FDs and they're all equal. 873 */ 874 static void test_share_dup(char *banner, char *b_suffix) 875 { 876 int fd, fd2; 877 878 /* 879 * hugetlbfs does not contain sealing support. Perform some 880 * basic testing on dup'ed fd instead via hugetlbfs_dup. 881 */ 882 if (hugetlbfs_test) { 883 hugetlbfs_dup(b_suffix); 884 return; 885 } 886 887 printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); 888 889 fd = mfd_assert_new("kern_memfd_share_dup", 890 mfd_def_size, 891 MFD_CLOEXEC | MFD_ALLOW_SEALING); 892 mfd_assert_has_seals(fd, 0); 893 894 fd2 = mfd_assert_dup(fd); 895 mfd_assert_has_seals(fd2, 0); 896 897 mfd_assert_add_seals(fd, F_SEAL_WRITE); 898 mfd_assert_has_seals(fd, F_SEAL_WRITE); 899 mfd_assert_has_seals(fd2, F_SEAL_WRITE); 900 901 mfd_assert_add_seals(fd2, F_SEAL_SHRINK); 902 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 903 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 904 905 mfd_assert_add_seals(fd, F_SEAL_SEAL); 906 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 907 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 908 909 mfd_fail_add_seals(fd, F_SEAL_GROW); 910 mfd_fail_add_seals(fd2, F_SEAL_GROW); 911 mfd_fail_add_seals(fd, F_SEAL_SEAL); 912 mfd_fail_add_seals(fd2, F_SEAL_SEAL); 913 914 close(fd2); 915 916 mfd_fail_add_seals(fd, F_SEAL_GROW); 917 close(fd); 918 } 919 920 /* 921 * Test sealing with active mmap()s 922 * Modifying seals is only allowed if no other mmap() refs exist. 923 */ 924 static void test_share_mmap(char *banner, char *b_suffix) 925 { 926 int fd; 927 void *p; 928 929 /* hugetlbfs does not contain sealing support */ 930 if (hugetlbfs_test) 931 return; 932 933 printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); 934 935 fd = mfd_assert_new("kern_memfd_share_mmap", 936 mfd_def_size, 937 MFD_CLOEXEC | MFD_ALLOW_SEALING); 938 mfd_assert_has_seals(fd, 0); 939 940 /* shared/writable ref prevents sealing WRITE, but allows others */ 941 p = mfd_assert_mmap_shared(fd); 942 mfd_fail_add_seals(fd, F_SEAL_WRITE); 943 mfd_assert_has_seals(fd, 0); 944 mfd_assert_add_seals(fd, F_SEAL_SHRINK); 945 mfd_assert_has_seals(fd, F_SEAL_SHRINK); 946 munmap(p, mfd_def_size); 947 948 /* readable ref allows sealing */ 949 p = mfd_assert_mmap_private(fd); 950 mfd_assert_add_seals(fd, F_SEAL_WRITE); 951 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 952 munmap(p, mfd_def_size); 953 954 close(fd); 955 } 956 957 /* 958 * Basic test to make sure we can open the hugetlbfs fd via /proc and 959 * perform some simple operations on it. 960 */ 961 static void hugetlbfs_proc_open(char *b_suffix) 962 { 963 int fd, fd2; 964 965 printf("%s HUGETLBFS-PROC-OPEN %s\n", MEMFD_STR, b_suffix); 966 967 fd = mfd_assert_new("kern_memfd_share_open", 968 mfd_def_size, 969 MFD_CLOEXEC); 970 971 fd2 = mfd_assert_open(fd, O_RDWR, 0); 972 973 mfd_assert_read(fd); 974 mfd_assert_write(fd); 975 976 mfd_assert_shrink(fd2); 977 mfd_assert_grow(fd2); 978 979 close(fd2); 980 close(fd); 981 } 982 983 /* 984 * Test sealing with open(/proc/self/fd/%d) 985 * Via /proc we can get access to a separate file-context for the same memfd. 986 * This is *not* like dup(), but like a real separate open(). Make sure the 987 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR. 988 */ 989 static void test_share_open(char *banner, char *b_suffix) 990 { 991 int fd, fd2; 992 993 /* 994 * hugetlbfs does not contain sealing support. So test basic 995 * functionality of using /proc fd via hugetlbfs_proc_open 996 */ 997 if (hugetlbfs_test) { 998 hugetlbfs_proc_open(b_suffix); 999 return; 1000 } 1001 1002 printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); 1003 1004 fd = mfd_assert_new("kern_memfd_share_open", 1005 mfd_def_size, 1006 MFD_CLOEXEC | MFD_ALLOW_SEALING); 1007 mfd_assert_has_seals(fd, 0); 1008 1009 fd2 = mfd_assert_open(fd, O_RDWR, 0); 1010 mfd_assert_add_seals(fd, F_SEAL_WRITE); 1011 mfd_assert_has_seals(fd, F_SEAL_WRITE); 1012 mfd_assert_has_seals(fd2, F_SEAL_WRITE); 1013 1014 mfd_assert_add_seals(fd2, F_SEAL_SHRINK); 1015 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 1016 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 1017 1018 close(fd); 1019 fd = mfd_assert_open(fd2, O_RDONLY, 0); 1020 1021 mfd_fail_add_seals(fd, F_SEAL_SEAL); 1022 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 1023 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 1024 1025 close(fd2); 1026 fd2 = mfd_assert_open(fd, O_RDWR, 0); 1027 1028 mfd_assert_add_seals(fd2, F_SEAL_SEAL); 1029 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 1030 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 1031 1032 close(fd2); 1033 close(fd); 1034 } 1035 1036 /* 1037 * Test sharing via fork() 1038 * Test whether seal-modifications work as expected with forked childs. 1039 */ 1040 static void test_share_fork(char *banner, char *b_suffix) 1041 { 1042 int fd; 1043 pid_t pid; 1044 1045 /* hugetlbfs does not contain sealing support */ 1046 if (hugetlbfs_test) 1047 return; 1048 1049 printf("%s %s %s\n", MEMFD_STR, banner, b_suffix); 1050 1051 fd = mfd_assert_new("kern_memfd_share_fork", 1052 mfd_def_size, 1053 MFD_CLOEXEC | MFD_ALLOW_SEALING); 1054 mfd_assert_has_seals(fd, 0); 1055 1056 pid = spawn_idle_thread(0); 1057 mfd_assert_add_seals(fd, F_SEAL_SEAL); 1058 mfd_assert_has_seals(fd, F_SEAL_SEAL); 1059 1060 mfd_fail_add_seals(fd, F_SEAL_WRITE); 1061 mfd_assert_has_seals(fd, F_SEAL_SEAL); 1062 1063 join_idle_thread(pid); 1064 1065 mfd_fail_add_seals(fd, F_SEAL_WRITE); 1066 mfd_assert_has_seals(fd, F_SEAL_SEAL); 1067 1068 close(fd); 1069 } 1070 1071 int main(int argc, char **argv) 1072 { 1073 pid_t pid; 1074 1075 if (argc == 2) { 1076 if (!strcmp(argv[1], "hugetlbfs")) { 1077 unsigned long hpage_size = default_huge_page_size(); 1078 1079 if (!hpage_size) { 1080 printf("Unable to determine huge page size\n"); 1081 abort(); 1082 } 1083 1084 hugetlbfs_test = 1; 1085 mfd_def_size = hpage_size * 2; 1086 } 1087 } 1088 1089 test_create(); 1090 test_basic(); 1091 1092 test_seal_write(); 1093 test_seal_shrink(); 1094 test_seal_grow(); 1095 test_seal_resize(); 1096 1097 test_share_dup("SHARE-DUP", ""); 1098 test_share_mmap("SHARE-MMAP", ""); 1099 test_share_open("SHARE-OPEN", ""); 1100 test_share_fork("SHARE-FORK", ""); 1101 1102 /* Run test-suite in a multi-threaded environment with a shared 1103 * file-table. */ 1104 pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM); 1105 test_share_dup("SHARE-DUP", SHARED_FT_STR); 1106 test_share_mmap("SHARE-MMAP", SHARED_FT_STR); 1107 test_share_open("SHARE-OPEN", SHARED_FT_STR); 1108 test_share_fork("SHARE-FORK", SHARED_FT_STR); 1109 join_idle_thread(pid); 1110 1111 printf("memfd: DONE\n"); 1112 1113 return 0; 1114 } 1115