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_fork_private_write(int fd) 294 { 295 int *p; 296 pid_t pid; 297 298 p = mmap(NULL, 299 mfd_def_size, 300 PROT_READ | PROT_WRITE, 301 MAP_PRIVATE, 302 fd, 303 0); 304 if (p == MAP_FAILED) { 305 printf("mmap() failed: %m\n"); 306 abort(); 307 } 308 309 p[0] = 22; 310 311 pid = fork(); 312 if (pid == 0) { 313 p[0] = 33; 314 exit(0); 315 } else { 316 waitpid(pid, NULL, 0); 317 318 if (p[0] != 22) { 319 printf("MAP_PRIVATE copy-on-write failed: %m\n"); 320 abort(); 321 } 322 } 323 324 munmap(p, mfd_def_size); 325 } 326 327 static void mfd_assert_write(int fd) 328 { 329 ssize_t l; 330 void *p; 331 int r; 332 333 /* 334 * huegtlbfs does not support write, but we want to 335 * verify everything else here. 336 */ 337 if (!hugetlbfs_test) { 338 /* verify write() succeeds */ 339 l = write(fd, "\0\0\0\0", 4); 340 if (l != 4) { 341 printf("write() failed: %m\n"); 342 abort(); 343 } 344 } 345 346 /* verify PROT_READ | PROT_WRITE is allowed */ 347 p = mmap(NULL, 348 mfd_def_size, 349 PROT_READ | PROT_WRITE, 350 MAP_SHARED, 351 fd, 352 0); 353 if (p == MAP_FAILED) { 354 printf("mmap() failed: %m\n"); 355 abort(); 356 } 357 *(char *)p = 0; 358 munmap(p, mfd_def_size); 359 360 /* verify PROT_WRITE is allowed */ 361 p = mmap(NULL, 362 mfd_def_size, 363 PROT_WRITE, 364 MAP_SHARED, 365 fd, 366 0); 367 if (p == MAP_FAILED) { 368 printf("mmap() failed: %m\n"); 369 abort(); 370 } 371 *(char *)p = 0; 372 munmap(p, mfd_def_size); 373 374 /* verify PROT_READ with MAP_SHARED is allowed and a following 375 * mprotect(PROT_WRITE) allows writing */ 376 p = mmap(NULL, 377 mfd_def_size, 378 PROT_READ, 379 MAP_SHARED, 380 fd, 381 0); 382 if (p == MAP_FAILED) { 383 printf("mmap() failed: %m\n"); 384 abort(); 385 } 386 387 r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE); 388 if (r < 0) { 389 printf("mprotect() failed: %m\n"); 390 abort(); 391 } 392 393 *(char *)p = 0; 394 munmap(p, mfd_def_size); 395 396 /* verify PUNCH_HOLE works */ 397 r = fallocate(fd, 398 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 399 0, 400 mfd_def_size); 401 if (r < 0) { 402 printf("fallocate(PUNCH_HOLE) failed: %m\n"); 403 abort(); 404 } 405 } 406 407 static void mfd_fail_write(int fd) 408 { 409 ssize_t l; 410 void *p; 411 int r; 412 413 /* verify write() fails */ 414 l = write(fd, "data", 4); 415 if (l != -EPERM) { 416 printf("expected EPERM on write(), but got %d: %m\n", (int)l); 417 abort(); 418 } 419 420 /* verify PROT_READ | PROT_WRITE is not allowed */ 421 p = mmap(NULL, 422 mfd_def_size, 423 PROT_READ | PROT_WRITE, 424 MAP_SHARED, 425 fd, 426 0); 427 if (p != MAP_FAILED) { 428 printf("mmap() didn't fail as expected\n"); 429 abort(); 430 } 431 432 /* verify PROT_WRITE is not allowed */ 433 p = mmap(NULL, 434 mfd_def_size, 435 PROT_WRITE, 436 MAP_SHARED, 437 fd, 438 0); 439 if (p != MAP_FAILED) { 440 printf("mmap() didn't fail as expected\n"); 441 abort(); 442 } 443 444 /* Verify PROT_READ with MAP_SHARED with a following mprotect is not 445 * allowed. Note that for r/w the kernel already prevents the mmap. */ 446 p = mmap(NULL, 447 mfd_def_size, 448 PROT_READ, 449 MAP_SHARED, 450 fd, 451 0); 452 if (p != MAP_FAILED) { 453 r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE); 454 if (r >= 0) { 455 printf("mmap()+mprotect() didn't fail as expected\n"); 456 abort(); 457 } 458 } 459 460 /* verify PUNCH_HOLE fails */ 461 r = fallocate(fd, 462 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 463 0, 464 mfd_def_size); 465 if (r >= 0) { 466 printf("fallocate(PUNCH_HOLE) didn't fail as expected\n"); 467 abort(); 468 } 469 } 470 471 static void mfd_assert_shrink(int fd) 472 { 473 int r, fd2; 474 475 r = ftruncate(fd, mfd_def_size / 2); 476 if (r < 0) { 477 printf("ftruncate(SHRINK) failed: %m\n"); 478 abort(); 479 } 480 481 mfd_assert_size(fd, mfd_def_size / 2); 482 483 fd2 = mfd_assert_open(fd, 484 O_RDWR | O_CREAT | O_TRUNC, 485 S_IRUSR | S_IWUSR); 486 close(fd2); 487 488 mfd_assert_size(fd, 0); 489 } 490 491 static void mfd_fail_shrink(int fd) 492 { 493 int r; 494 495 r = ftruncate(fd, mfd_def_size / 2); 496 if (r >= 0) { 497 printf("ftruncate(SHRINK) didn't fail as expected\n"); 498 abort(); 499 } 500 501 mfd_fail_open(fd, 502 O_RDWR | O_CREAT | O_TRUNC, 503 S_IRUSR | S_IWUSR); 504 } 505 506 static void mfd_assert_grow(int fd) 507 { 508 int r; 509 510 r = ftruncate(fd, mfd_def_size * 2); 511 if (r < 0) { 512 printf("ftruncate(GROW) failed: %m\n"); 513 abort(); 514 } 515 516 mfd_assert_size(fd, mfd_def_size * 2); 517 518 r = fallocate(fd, 519 0, 520 0, 521 mfd_def_size * 4); 522 if (r < 0) { 523 printf("fallocate(ALLOC) failed: %m\n"); 524 abort(); 525 } 526 527 mfd_assert_size(fd, mfd_def_size * 4); 528 } 529 530 static void mfd_fail_grow(int fd) 531 { 532 int r; 533 534 r = ftruncate(fd, mfd_def_size * 2); 535 if (r >= 0) { 536 printf("ftruncate(GROW) didn't fail as expected\n"); 537 abort(); 538 } 539 540 r = fallocate(fd, 541 0, 542 0, 543 mfd_def_size * 4); 544 if (r >= 0) { 545 printf("fallocate(ALLOC) didn't fail as expected\n"); 546 abort(); 547 } 548 } 549 550 static void mfd_assert_grow_write(int fd) 551 { 552 static char *buf; 553 ssize_t l; 554 555 /* hugetlbfs does not support write */ 556 if (hugetlbfs_test) 557 return; 558 559 buf = malloc(mfd_def_size * 8); 560 if (!buf) { 561 printf("malloc(%zu) failed: %m\n", mfd_def_size * 8); 562 abort(); 563 } 564 565 l = pwrite(fd, buf, mfd_def_size * 8, 0); 566 if (l != (mfd_def_size * 8)) { 567 printf("pwrite() failed: %m\n"); 568 abort(); 569 } 570 571 mfd_assert_size(fd, mfd_def_size * 8); 572 } 573 574 static void mfd_fail_grow_write(int fd) 575 { 576 static char *buf; 577 ssize_t l; 578 579 /* hugetlbfs does not support write */ 580 if (hugetlbfs_test) 581 return; 582 583 buf = malloc(mfd_def_size * 8); 584 if (!buf) { 585 printf("malloc(%zu) failed: %m\n", mfd_def_size * 8); 586 abort(); 587 } 588 589 l = pwrite(fd, buf, mfd_def_size * 8, 0); 590 if (l == (mfd_def_size * 8)) { 591 printf("pwrite() didn't fail as expected\n"); 592 abort(); 593 } 594 } 595 596 static int idle_thread_fn(void *arg) 597 { 598 sigset_t set; 599 int sig; 600 601 /* dummy waiter; SIGTERM terminates us anyway */ 602 sigemptyset(&set); 603 sigaddset(&set, SIGTERM); 604 sigwait(&set, &sig); 605 606 return 0; 607 } 608 609 static pid_t spawn_idle_thread(unsigned int flags) 610 { 611 uint8_t *stack; 612 pid_t pid; 613 614 stack = malloc(STACK_SIZE); 615 if (!stack) { 616 printf("malloc(STACK_SIZE) failed: %m\n"); 617 abort(); 618 } 619 620 pid = clone(idle_thread_fn, 621 stack + STACK_SIZE, 622 SIGCHLD | flags, 623 NULL); 624 if (pid < 0) { 625 printf("clone() failed: %m\n"); 626 abort(); 627 } 628 629 return pid; 630 } 631 632 static void join_idle_thread(pid_t pid) 633 { 634 kill(pid, SIGTERM); 635 waitpid(pid, NULL, 0); 636 } 637 638 /* 639 * Test memfd_create() syscall 640 * Verify syscall-argument validation, including name checks, flag validation 641 * and more. 642 */ 643 static void test_create(void) 644 { 645 char buf[2048]; 646 int fd; 647 648 printf("%s CREATE\n", memfd_str); 649 650 /* test NULL name */ 651 mfd_fail_new(NULL, 0); 652 653 /* test over-long name (not zero-terminated) */ 654 memset(buf, 0xff, sizeof(buf)); 655 mfd_fail_new(buf, 0); 656 657 /* test over-long zero-terminated name */ 658 memset(buf, 0xff, sizeof(buf)); 659 buf[sizeof(buf) - 1] = 0; 660 mfd_fail_new(buf, 0); 661 662 /* verify "" is a valid name */ 663 fd = mfd_assert_new("", 0, 0); 664 close(fd); 665 666 /* verify invalid O_* open flags */ 667 mfd_fail_new("", 0x0100); 668 mfd_fail_new("", ~MFD_CLOEXEC); 669 mfd_fail_new("", ~MFD_ALLOW_SEALING); 670 mfd_fail_new("", ~0); 671 mfd_fail_new("", 0x80000000U); 672 673 /* verify MFD_CLOEXEC is allowed */ 674 fd = mfd_assert_new("", 0, MFD_CLOEXEC); 675 close(fd); 676 677 /* verify MFD_ALLOW_SEALING is allowed */ 678 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING); 679 close(fd); 680 681 /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */ 682 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC); 683 close(fd); 684 } 685 686 /* 687 * Test basic sealing 688 * A very basic sealing test to see whether setting/retrieving seals works. 689 */ 690 static void test_basic(void) 691 { 692 int fd; 693 694 printf("%s BASIC\n", memfd_str); 695 696 fd = mfd_assert_new("kern_memfd_basic", 697 mfd_def_size, 698 MFD_CLOEXEC | MFD_ALLOW_SEALING); 699 700 /* add basic seals */ 701 mfd_assert_has_seals(fd, 0); 702 mfd_assert_add_seals(fd, F_SEAL_SHRINK | 703 F_SEAL_WRITE); 704 mfd_assert_has_seals(fd, F_SEAL_SHRINK | 705 F_SEAL_WRITE); 706 707 /* add them again */ 708 mfd_assert_add_seals(fd, F_SEAL_SHRINK | 709 F_SEAL_WRITE); 710 mfd_assert_has_seals(fd, F_SEAL_SHRINK | 711 F_SEAL_WRITE); 712 713 /* add more seals and seal against sealing */ 714 mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL); 715 mfd_assert_has_seals(fd, F_SEAL_SHRINK | 716 F_SEAL_GROW | 717 F_SEAL_WRITE | 718 F_SEAL_SEAL); 719 720 /* verify that sealing no longer works */ 721 mfd_fail_add_seals(fd, F_SEAL_GROW); 722 mfd_fail_add_seals(fd, 0); 723 724 close(fd); 725 726 /* verify sealing does not work without MFD_ALLOW_SEALING */ 727 fd = mfd_assert_new("kern_memfd_basic", 728 mfd_def_size, 729 MFD_CLOEXEC); 730 mfd_assert_has_seals(fd, F_SEAL_SEAL); 731 mfd_fail_add_seals(fd, F_SEAL_SHRINK | 732 F_SEAL_GROW | 733 F_SEAL_WRITE); 734 mfd_assert_has_seals(fd, F_SEAL_SEAL); 735 close(fd); 736 } 737 738 /* 739 * Test SEAL_WRITE 740 * Test whether SEAL_WRITE actually prevents modifications. 741 */ 742 static void test_seal_write(void) 743 { 744 int fd; 745 746 printf("%s SEAL-WRITE\n", memfd_str); 747 748 fd = mfd_assert_new("kern_memfd_seal_write", 749 mfd_def_size, 750 MFD_CLOEXEC | MFD_ALLOW_SEALING); 751 mfd_assert_has_seals(fd, 0); 752 mfd_assert_add_seals(fd, F_SEAL_WRITE); 753 mfd_assert_has_seals(fd, F_SEAL_WRITE); 754 755 mfd_assert_read(fd); 756 mfd_fail_write(fd); 757 mfd_assert_shrink(fd); 758 mfd_assert_grow(fd); 759 mfd_fail_grow_write(fd); 760 761 close(fd); 762 } 763 764 /* 765 * Test SEAL_FUTURE_WRITE 766 * Test whether SEAL_FUTURE_WRITE actually prevents modifications. 767 */ 768 static void test_seal_future_write(void) 769 { 770 int fd, fd2; 771 void *p; 772 773 printf("%s SEAL-FUTURE-WRITE\n", memfd_str); 774 775 fd = mfd_assert_new("kern_memfd_seal_future_write", 776 mfd_def_size, 777 MFD_CLOEXEC | MFD_ALLOW_SEALING); 778 779 p = mfd_assert_mmap_shared(fd); 780 781 mfd_assert_has_seals(fd, 0); 782 783 mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE); 784 mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE); 785 786 /* read should pass, writes should fail */ 787 mfd_assert_read(fd); 788 mfd_assert_read_shared(fd); 789 mfd_fail_write(fd); 790 791 fd2 = mfd_assert_reopen_fd(fd); 792 /* read should pass, writes should still fail */ 793 mfd_assert_read(fd2); 794 mfd_assert_read_shared(fd2); 795 mfd_fail_write(fd2); 796 797 mfd_assert_fork_private_write(fd); 798 799 munmap(p, mfd_def_size); 800 close(fd2); 801 close(fd); 802 } 803 804 /* 805 * Test SEAL_SHRINK 806 * Test whether SEAL_SHRINK actually prevents shrinking 807 */ 808 static void test_seal_shrink(void) 809 { 810 int fd; 811 812 printf("%s SEAL-SHRINK\n", memfd_str); 813 814 fd = mfd_assert_new("kern_memfd_seal_shrink", 815 mfd_def_size, 816 MFD_CLOEXEC | MFD_ALLOW_SEALING); 817 mfd_assert_has_seals(fd, 0); 818 mfd_assert_add_seals(fd, F_SEAL_SHRINK); 819 mfd_assert_has_seals(fd, F_SEAL_SHRINK); 820 821 mfd_assert_read(fd); 822 mfd_assert_write(fd); 823 mfd_fail_shrink(fd); 824 mfd_assert_grow(fd); 825 mfd_assert_grow_write(fd); 826 827 close(fd); 828 } 829 830 /* 831 * Test SEAL_GROW 832 * Test whether SEAL_GROW actually prevents growing 833 */ 834 static void test_seal_grow(void) 835 { 836 int fd; 837 838 printf("%s SEAL-GROW\n", memfd_str); 839 840 fd = mfd_assert_new("kern_memfd_seal_grow", 841 mfd_def_size, 842 MFD_CLOEXEC | MFD_ALLOW_SEALING); 843 mfd_assert_has_seals(fd, 0); 844 mfd_assert_add_seals(fd, F_SEAL_GROW); 845 mfd_assert_has_seals(fd, F_SEAL_GROW); 846 847 mfd_assert_read(fd); 848 mfd_assert_write(fd); 849 mfd_assert_shrink(fd); 850 mfd_fail_grow(fd); 851 mfd_fail_grow_write(fd); 852 853 close(fd); 854 } 855 856 /* 857 * Test SEAL_SHRINK | SEAL_GROW 858 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing 859 */ 860 static void test_seal_resize(void) 861 { 862 int fd; 863 864 printf("%s SEAL-RESIZE\n", memfd_str); 865 866 fd = mfd_assert_new("kern_memfd_seal_resize", 867 mfd_def_size, 868 MFD_CLOEXEC | MFD_ALLOW_SEALING); 869 mfd_assert_has_seals(fd, 0); 870 mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); 871 mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); 872 873 mfd_assert_read(fd); 874 mfd_assert_write(fd); 875 mfd_fail_shrink(fd); 876 mfd_fail_grow(fd); 877 mfd_fail_grow_write(fd); 878 879 close(fd); 880 } 881 882 /* 883 * Test sharing via dup() 884 * Test that seals are shared between dupped FDs and they're all equal. 885 */ 886 static void test_share_dup(char *banner, char *b_suffix) 887 { 888 int fd, fd2; 889 890 printf("%s %s %s\n", memfd_str, banner, b_suffix); 891 892 fd = mfd_assert_new("kern_memfd_share_dup", 893 mfd_def_size, 894 MFD_CLOEXEC | MFD_ALLOW_SEALING); 895 mfd_assert_has_seals(fd, 0); 896 897 fd2 = mfd_assert_dup(fd); 898 mfd_assert_has_seals(fd2, 0); 899 900 mfd_assert_add_seals(fd, F_SEAL_WRITE); 901 mfd_assert_has_seals(fd, F_SEAL_WRITE); 902 mfd_assert_has_seals(fd2, F_SEAL_WRITE); 903 904 mfd_assert_add_seals(fd2, F_SEAL_SHRINK); 905 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 906 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 907 908 mfd_assert_add_seals(fd, F_SEAL_SEAL); 909 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 910 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 911 912 mfd_fail_add_seals(fd, F_SEAL_GROW); 913 mfd_fail_add_seals(fd2, F_SEAL_GROW); 914 mfd_fail_add_seals(fd, F_SEAL_SEAL); 915 mfd_fail_add_seals(fd2, F_SEAL_SEAL); 916 917 close(fd2); 918 919 mfd_fail_add_seals(fd, F_SEAL_GROW); 920 close(fd); 921 } 922 923 /* 924 * Test sealing with active mmap()s 925 * Modifying seals is only allowed if no other mmap() refs exist. 926 */ 927 static void test_share_mmap(char *banner, char *b_suffix) 928 { 929 int fd; 930 void *p; 931 932 printf("%s %s %s\n", memfd_str, banner, b_suffix); 933 934 fd = mfd_assert_new("kern_memfd_share_mmap", 935 mfd_def_size, 936 MFD_CLOEXEC | MFD_ALLOW_SEALING); 937 mfd_assert_has_seals(fd, 0); 938 939 /* shared/writable ref prevents sealing WRITE, but allows others */ 940 p = mfd_assert_mmap_shared(fd); 941 mfd_fail_add_seals(fd, F_SEAL_WRITE); 942 mfd_assert_has_seals(fd, 0); 943 mfd_assert_add_seals(fd, F_SEAL_SHRINK); 944 mfd_assert_has_seals(fd, F_SEAL_SHRINK); 945 munmap(p, mfd_def_size); 946 947 /* readable ref allows sealing */ 948 p = mfd_assert_mmap_private(fd); 949 mfd_assert_add_seals(fd, F_SEAL_WRITE); 950 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 951 munmap(p, mfd_def_size); 952 953 close(fd); 954 } 955 956 /* 957 * Test sealing with open(/proc/self/fd/%d) 958 * Via /proc we can get access to a separate file-context for the same memfd. 959 * This is *not* like dup(), but like a real separate open(). Make sure the 960 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR. 961 */ 962 static void test_share_open(char *banner, char *b_suffix) 963 { 964 int fd, fd2; 965 966 printf("%s %s %s\n", memfd_str, banner, b_suffix); 967 968 fd = mfd_assert_new("kern_memfd_share_open", 969 mfd_def_size, 970 MFD_CLOEXEC | MFD_ALLOW_SEALING); 971 mfd_assert_has_seals(fd, 0); 972 973 fd2 = mfd_assert_open(fd, O_RDWR, 0); 974 mfd_assert_add_seals(fd, F_SEAL_WRITE); 975 mfd_assert_has_seals(fd, F_SEAL_WRITE); 976 mfd_assert_has_seals(fd2, F_SEAL_WRITE); 977 978 mfd_assert_add_seals(fd2, F_SEAL_SHRINK); 979 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 980 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 981 982 close(fd); 983 fd = mfd_assert_open(fd2, O_RDONLY, 0); 984 985 mfd_fail_add_seals(fd, F_SEAL_SEAL); 986 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); 987 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); 988 989 close(fd2); 990 fd2 = mfd_assert_open(fd, O_RDWR, 0); 991 992 mfd_assert_add_seals(fd2, F_SEAL_SEAL); 993 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 994 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); 995 996 close(fd2); 997 close(fd); 998 } 999 1000 /* 1001 * Test sharing via fork() 1002 * Test whether seal-modifications work as expected with forked childs. 1003 */ 1004 static void test_share_fork(char *banner, char *b_suffix) 1005 { 1006 int fd; 1007 pid_t pid; 1008 1009 printf("%s %s %s\n", memfd_str, banner, b_suffix); 1010 1011 fd = mfd_assert_new("kern_memfd_share_fork", 1012 mfd_def_size, 1013 MFD_CLOEXEC | MFD_ALLOW_SEALING); 1014 mfd_assert_has_seals(fd, 0); 1015 1016 pid = spawn_idle_thread(0); 1017 mfd_assert_add_seals(fd, F_SEAL_SEAL); 1018 mfd_assert_has_seals(fd, F_SEAL_SEAL); 1019 1020 mfd_fail_add_seals(fd, F_SEAL_WRITE); 1021 mfd_assert_has_seals(fd, F_SEAL_SEAL); 1022 1023 join_idle_thread(pid); 1024 1025 mfd_fail_add_seals(fd, F_SEAL_WRITE); 1026 mfd_assert_has_seals(fd, F_SEAL_SEAL); 1027 1028 close(fd); 1029 } 1030 1031 int main(int argc, char **argv) 1032 { 1033 pid_t pid; 1034 1035 if (argc == 2) { 1036 if (!strcmp(argv[1], "hugetlbfs")) { 1037 unsigned long hpage_size = default_huge_page_size(); 1038 1039 if (!hpage_size) { 1040 printf("Unable to determine huge page size\n"); 1041 abort(); 1042 } 1043 1044 hugetlbfs_test = 1; 1045 memfd_str = MEMFD_HUGE_STR; 1046 mfd_def_size = hpage_size * 2; 1047 } else { 1048 printf("Unknown option: %s\n", argv[1]); 1049 abort(); 1050 } 1051 } 1052 1053 test_create(); 1054 test_basic(); 1055 1056 test_seal_write(); 1057 test_seal_future_write(); 1058 test_seal_shrink(); 1059 test_seal_grow(); 1060 test_seal_resize(); 1061 1062 test_share_dup("SHARE-DUP", ""); 1063 test_share_mmap("SHARE-MMAP", ""); 1064 test_share_open("SHARE-OPEN", ""); 1065 test_share_fork("SHARE-FORK", ""); 1066 1067 /* Run test-suite in a multi-threaded environment with a shared 1068 * file-table. */ 1069 pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM); 1070 test_share_dup("SHARE-DUP", SHARED_FT_STR); 1071 test_share_mmap("SHARE-MMAP", SHARED_FT_STR); 1072 test_share_open("SHARE-OPEN", SHARED_FT_STR); 1073 test_share_fork("SHARE-FORK", SHARED_FT_STR); 1074 join_idle_thread(pid); 1075 1076 printf("memfd: DONE\n"); 1077 1078 return 0; 1079 } 1080