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