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