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