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