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