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