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