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