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