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