linux/tools/testing/selftests/memfd/memfd_test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#define _GNU_SOURCE
   3#define __EXPORTED_HEADERS__
   4
   5#include <errno.h>
   6#include <inttypes.h>
   7#include <limits.h>
   8#include <linux/falloc.h>
   9#include <linux/fcntl.h>
  10#include <linux/memfd.h>
  11#include <sched.h>
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <signal.h>
  15#include <string.h>
  16#include <sys/mman.h>
  17#include <sys/stat.h>
  18#include <sys/syscall.h>
  19#include <sys/wait.h>
  20#include <unistd.h>
  21
  22#include "common.h"
  23
  24#define MEMFD_STR       "memfd:"
  25#define MEMFD_HUGE_STR  "memfd-hugetlb:"
  26#define SHARED_FT_STR   "(shared file-table)"
  27
  28#define MFD_DEF_SIZE 8192
  29#define STACK_SIZE 65536
  30
  31/*
  32 * Default is not to test hugetlbfs
  33 */
  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 r, 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_write(int fd)
 294{
 295        ssize_t l;
 296        void *p;
 297        int r;
 298
 299        /*
 300         * huegtlbfs does not support write, but we want to
 301         * verify everything else here.
 302         */
 303        if (!hugetlbfs_test) {
 304                /* verify write() succeeds */
 305                l = write(fd, "\0\0\0\0", 4);
 306                if (l != 4) {
 307                        printf("write() failed: %m\n");
 308                        abort();
 309                }
 310        }
 311
 312        /* verify PROT_READ | PROT_WRITE is allowed */
 313        p = mmap(NULL,
 314                 mfd_def_size,
 315                 PROT_READ | PROT_WRITE,
 316                 MAP_SHARED,
 317                 fd,
 318                 0);
 319        if (p == MAP_FAILED) {
 320                printf("mmap() failed: %m\n");
 321                abort();
 322        }
 323        *(char *)p = 0;
 324        munmap(p, mfd_def_size);
 325
 326        /* verify PROT_WRITE is allowed */
 327        p = mmap(NULL,
 328                 mfd_def_size,
 329                 PROT_WRITE,
 330                 MAP_SHARED,
 331                 fd,
 332                 0);
 333        if (p == MAP_FAILED) {
 334                printf("mmap() failed: %m\n");
 335                abort();
 336        }
 337        *(char *)p = 0;
 338        munmap(p, mfd_def_size);
 339
 340        /* verify PROT_READ with MAP_SHARED is allowed and a following
 341         * mprotect(PROT_WRITE) allows writing */
 342        p = mmap(NULL,
 343                 mfd_def_size,
 344                 PROT_READ,
 345                 MAP_SHARED,
 346                 fd,
 347                 0);
 348        if (p == MAP_FAILED) {
 349                printf("mmap() failed: %m\n");
 350                abort();
 351        }
 352
 353        r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
 354        if (r < 0) {
 355                printf("mprotect() failed: %m\n");
 356                abort();
 357        }
 358
 359        *(char *)p = 0;
 360        munmap(p, mfd_def_size);
 361
 362        /* verify PUNCH_HOLE works */
 363        r = fallocate(fd,
 364                      FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
 365                      0,
 366                      mfd_def_size);
 367        if (r < 0) {
 368                printf("fallocate(PUNCH_HOLE) failed: %m\n");
 369                abort();
 370        }
 371}
 372
 373static void mfd_fail_write(int fd)
 374{
 375        ssize_t l;
 376        void *p;
 377        int r;
 378
 379        /* verify write() fails */
 380        l = write(fd, "data", 4);
 381        if (l != -EPERM) {
 382                printf("expected EPERM on write(), but got %d: %m\n", (int)l);
 383                abort();
 384        }
 385
 386        /* verify PROT_READ | PROT_WRITE is not allowed */
 387        p = mmap(NULL,
 388                 mfd_def_size,
 389                 PROT_READ | PROT_WRITE,
 390                 MAP_SHARED,
 391                 fd,
 392                 0);
 393        if (p != MAP_FAILED) {
 394                printf("mmap() didn't fail as expected\n");
 395                abort();
 396        }
 397
 398        /* verify PROT_WRITE is not allowed */
 399        p = mmap(NULL,
 400                 mfd_def_size,
 401                 PROT_WRITE,
 402                 MAP_SHARED,
 403                 fd,
 404                 0);
 405        if (p != MAP_FAILED) {
 406                printf("mmap() didn't fail as expected\n");
 407                abort();
 408        }
 409
 410        /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
 411         * allowed. Note that for r/w the kernel already prevents the mmap. */
 412        p = mmap(NULL,
 413                 mfd_def_size,
 414                 PROT_READ,
 415                 MAP_SHARED,
 416                 fd,
 417                 0);
 418        if (p != MAP_FAILED) {
 419                r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
 420                if (r >= 0) {
 421                        printf("mmap()+mprotect() didn't fail as expected\n");
 422                        abort();
 423                }
 424        }
 425
 426        /* verify PUNCH_HOLE fails */
 427        r = fallocate(fd,
 428                      FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
 429                      0,
 430                      mfd_def_size);
 431        if (r >= 0) {
 432                printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
 433                abort();
 434        }
 435}
 436
 437static void mfd_assert_shrink(int fd)
 438{
 439        int r, fd2;
 440
 441        r = ftruncate(fd, mfd_def_size / 2);
 442        if (r < 0) {
 443                printf("ftruncate(SHRINK) failed: %m\n");
 444                abort();
 445        }
 446
 447        mfd_assert_size(fd, mfd_def_size / 2);
 448
 449        fd2 = mfd_assert_open(fd,
 450                              O_RDWR | O_CREAT | O_TRUNC,
 451                              S_IRUSR | S_IWUSR);
 452        close(fd2);
 453
 454        mfd_assert_size(fd, 0);
 455}
 456
 457static void mfd_fail_shrink(int fd)
 458{
 459        int r;
 460
 461        r = ftruncate(fd, mfd_def_size / 2);
 462        if (r >= 0) {
 463                printf("ftruncate(SHRINK) didn't fail as expected\n");
 464                abort();
 465        }
 466
 467        mfd_fail_open(fd,
 468                      O_RDWR | O_CREAT | O_TRUNC,
 469                      S_IRUSR | S_IWUSR);
 470}
 471
 472static void mfd_assert_grow(int fd)
 473{
 474        int r;
 475
 476        r = ftruncate(fd, mfd_def_size * 2);
 477        if (r < 0) {
 478                printf("ftruncate(GROW) failed: %m\n");
 479                abort();
 480        }
 481
 482        mfd_assert_size(fd, mfd_def_size * 2);
 483
 484        r = fallocate(fd,
 485                      0,
 486                      0,
 487                      mfd_def_size * 4);
 488        if (r < 0) {
 489                printf("fallocate(ALLOC) failed: %m\n");
 490                abort();
 491        }
 492
 493        mfd_assert_size(fd, mfd_def_size * 4);
 494}
 495
 496static void mfd_fail_grow(int fd)
 497{
 498        int r;
 499
 500        r = ftruncate(fd, mfd_def_size * 2);
 501        if (r >= 0) {
 502                printf("ftruncate(GROW) didn't fail as expected\n");
 503                abort();
 504        }
 505
 506        r = fallocate(fd,
 507                      0,
 508                      0,
 509                      mfd_def_size * 4);
 510        if (r >= 0) {
 511                printf("fallocate(ALLOC) didn't fail as expected\n");
 512                abort();
 513        }
 514}
 515
 516static void mfd_assert_grow_write(int fd)
 517{
 518        static char *buf;
 519        ssize_t l;
 520
 521        /* hugetlbfs does not support write */
 522        if (hugetlbfs_test)
 523                return;
 524
 525        buf = malloc(mfd_def_size * 8);
 526        if (!buf) {
 527                printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
 528                abort();
 529        }
 530
 531        l = pwrite(fd, buf, mfd_def_size * 8, 0);
 532        if (l != (mfd_def_size * 8)) {
 533                printf("pwrite() failed: %m\n");
 534                abort();
 535        }
 536
 537        mfd_assert_size(fd, mfd_def_size * 8);
 538}
 539
 540static void mfd_fail_grow_write(int fd)
 541{
 542        static char *buf;
 543        ssize_t l;
 544
 545        /* hugetlbfs does not support write */
 546        if (hugetlbfs_test)
 547                return;
 548
 549        buf = malloc(mfd_def_size * 8);
 550        if (!buf) {
 551                printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
 552                abort();
 553        }
 554
 555        l = pwrite(fd, buf, mfd_def_size * 8, 0);
 556        if (l == (mfd_def_size * 8)) {
 557                printf("pwrite() didn't fail as expected\n");
 558                abort();
 559        }
 560}
 561
 562static int idle_thread_fn(void *arg)
 563{
 564        sigset_t set;
 565        int sig;
 566
 567        /* dummy waiter; SIGTERM terminates us anyway */
 568        sigemptyset(&set);
 569        sigaddset(&set, SIGTERM);
 570        sigwait(&set, &sig);
 571
 572        return 0;
 573}
 574
 575static pid_t spawn_idle_thread(unsigned int flags)
 576{
 577        uint8_t *stack;
 578        pid_t pid;
 579
 580        stack = malloc(STACK_SIZE);
 581        if (!stack) {
 582                printf("malloc(STACK_SIZE) failed: %m\n");
 583                abort();
 584        }
 585
 586        pid = clone(idle_thread_fn,
 587                    stack + STACK_SIZE,
 588                    SIGCHLD | flags,
 589                    NULL);
 590        if (pid < 0) {
 591                printf("clone() failed: %m\n");
 592                abort();
 593        }
 594
 595        return pid;
 596}
 597
 598static void join_idle_thread(pid_t pid)
 599{
 600        kill(pid, SIGTERM);
 601        waitpid(pid, NULL, 0);
 602}
 603
 604/*
 605 * Test memfd_create() syscall
 606 * Verify syscall-argument validation, including name checks, flag validation
 607 * and more.
 608 */
 609static void test_create(void)
 610{
 611        char buf[2048];
 612        int fd;
 613
 614        printf("%s CREATE\n", memfd_str);
 615
 616        /* test NULL name */
 617        mfd_fail_new(NULL, 0);
 618
 619        /* test over-long name (not zero-terminated) */
 620        memset(buf, 0xff, sizeof(buf));
 621        mfd_fail_new(buf, 0);
 622
 623        /* test over-long zero-terminated name */
 624        memset(buf, 0xff, sizeof(buf));
 625        buf[sizeof(buf) - 1] = 0;
 626        mfd_fail_new(buf, 0);
 627
 628        /* verify "" is a valid name */
 629        fd = mfd_assert_new("", 0, 0);
 630        close(fd);
 631
 632        /* verify invalid O_* open flags */
 633        mfd_fail_new("", 0x0100);
 634        mfd_fail_new("", ~MFD_CLOEXEC);
 635        mfd_fail_new("", ~MFD_ALLOW_SEALING);
 636        mfd_fail_new("", ~0);
 637        mfd_fail_new("", 0x80000000U);
 638
 639        /* verify MFD_CLOEXEC is allowed */
 640        fd = mfd_assert_new("", 0, MFD_CLOEXEC);
 641        close(fd);
 642
 643        /* verify MFD_ALLOW_SEALING is allowed */
 644        fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
 645        close(fd);
 646
 647        /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
 648        fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
 649        close(fd);
 650}
 651
 652/*
 653 * Test basic sealing
 654 * A very basic sealing test to see whether setting/retrieving seals works.
 655 */
 656static void test_basic(void)
 657{
 658        int fd;
 659
 660        printf("%s BASIC\n", memfd_str);
 661
 662        fd = mfd_assert_new("kern_memfd_basic",
 663                            mfd_def_size,
 664                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 665
 666        /* add basic seals */
 667        mfd_assert_has_seals(fd, 0);
 668        mfd_assert_add_seals(fd, F_SEAL_SHRINK |
 669                                 F_SEAL_WRITE);
 670        mfd_assert_has_seals(fd, F_SEAL_SHRINK |
 671                                 F_SEAL_WRITE);
 672
 673        /* add them again */
 674        mfd_assert_add_seals(fd, F_SEAL_SHRINK |
 675                                 F_SEAL_WRITE);
 676        mfd_assert_has_seals(fd, F_SEAL_SHRINK |
 677                                 F_SEAL_WRITE);
 678
 679        /* add more seals and seal against sealing */
 680        mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
 681        mfd_assert_has_seals(fd, F_SEAL_SHRINK |
 682                                 F_SEAL_GROW |
 683                                 F_SEAL_WRITE |
 684                                 F_SEAL_SEAL);
 685
 686        /* verify that sealing no longer works */
 687        mfd_fail_add_seals(fd, F_SEAL_GROW);
 688        mfd_fail_add_seals(fd, 0);
 689
 690        close(fd);
 691
 692        /* verify sealing does not work without MFD_ALLOW_SEALING */
 693        fd = mfd_assert_new("kern_memfd_basic",
 694                            mfd_def_size,
 695                            MFD_CLOEXEC);
 696        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 697        mfd_fail_add_seals(fd, F_SEAL_SHRINK |
 698                               F_SEAL_GROW |
 699                               F_SEAL_WRITE);
 700        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 701        close(fd);
 702}
 703
 704/*
 705 * Test SEAL_WRITE
 706 * Test whether SEAL_WRITE actually prevents modifications.
 707 */
 708static void test_seal_write(void)
 709{
 710        int fd;
 711
 712        printf("%s SEAL-WRITE\n", memfd_str);
 713
 714        fd = mfd_assert_new("kern_memfd_seal_write",
 715                            mfd_def_size,
 716                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 717        mfd_assert_has_seals(fd, 0);
 718        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 719        mfd_assert_has_seals(fd, F_SEAL_WRITE);
 720
 721        mfd_assert_read(fd);
 722        mfd_fail_write(fd);
 723        mfd_assert_shrink(fd);
 724        mfd_assert_grow(fd);
 725        mfd_fail_grow_write(fd);
 726
 727        close(fd);
 728}
 729
 730/*
 731 * Test SEAL_FUTURE_WRITE
 732 * Test whether SEAL_FUTURE_WRITE actually prevents modifications.
 733 */
 734static void test_seal_future_write(void)
 735{
 736        int fd, fd2;
 737        void *p;
 738
 739        printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
 740
 741        fd = mfd_assert_new("kern_memfd_seal_future_write",
 742                            mfd_def_size,
 743                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 744
 745        p = mfd_assert_mmap_shared(fd);
 746
 747        mfd_assert_has_seals(fd, 0);
 748
 749        mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
 750        mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
 751
 752        /* read should pass, writes should fail */
 753        mfd_assert_read(fd);
 754        mfd_assert_read_shared(fd);
 755        mfd_fail_write(fd);
 756
 757        fd2 = mfd_assert_reopen_fd(fd);
 758        /* read should pass, writes should still fail */
 759        mfd_assert_read(fd2);
 760        mfd_assert_read_shared(fd2);
 761        mfd_fail_write(fd2);
 762
 763        munmap(p, mfd_def_size);
 764        close(fd2);
 765        close(fd);
 766}
 767
 768/*
 769 * Test SEAL_SHRINK
 770 * Test whether SEAL_SHRINK actually prevents shrinking
 771 */
 772static void test_seal_shrink(void)
 773{
 774        int fd;
 775
 776        printf("%s SEAL-SHRINK\n", memfd_str);
 777
 778        fd = mfd_assert_new("kern_memfd_seal_shrink",
 779                            mfd_def_size,
 780                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 781        mfd_assert_has_seals(fd, 0);
 782        mfd_assert_add_seals(fd, F_SEAL_SHRINK);
 783        mfd_assert_has_seals(fd, F_SEAL_SHRINK);
 784
 785        mfd_assert_read(fd);
 786        mfd_assert_write(fd);
 787        mfd_fail_shrink(fd);
 788        mfd_assert_grow(fd);
 789        mfd_assert_grow_write(fd);
 790
 791        close(fd);
 792}
 793
 794/*
 795 * Test SEAL_GROW
 796 * Test whether SEAL_GROW actually prevents growing
 797 */
 798static void test_seal_grow(void)
 799{
 800        int fd;
 801
 802        printf("%s SEAL-GROW\n", memfd_str);
 803
 804        fd = mfd_assert_new("kern_memfd_seal_grow",
 805                            mfd_def_size,
 806                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 807        mfd_assert_has_seals(fd, 0);
 808        mfd_assert_add_seals(fd, F_SEAL_GROW);
 809        mfd_assert_has_seals(fd, F_SEAL_GROW);
 810
 811        mfd_assert_read(fd);
 812        mfd_assert_write(fd);
 813        mfd_assert_shrink(fd);
 814        mfd_fail_grow(fd);
 815        mfd_fail_grow_write(fd);
 816
 817        close(fd);
 818}
 819
 820/*
 821 * Test SEAL_SHRINK | SEAL_GROW
 822 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
 823 */
 824static void test_seal_resize(void)
 825{
 826        int fd;
 827
 828        printf("%s SEAL-RESIZE\n", memfd_str);
 829
 830        fd = mfd_assert_new("kern_memfd_seal_resize",
 831                            mfd_def_size,
 832                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 833        mfd_assert_has_seals(fd, 0);
 834        mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
 835        mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
 836
 837        mfd_assert_read(fd);
 838        mfd_assert_write(fd);
 839        mfd_fail_shrink(fd);
 840        mfd_fail_grow(fd);
 841        mfd_fail_grow_write(fd);
 842
 843        close(fd);
 844}
 845
 846/*
 847 * Test sharing via dup()
 848 * Test that seals are shared between dupped FDs and they're all equal.
 849 */
 850static void test_share_dup(char *banner, char *b_suffix)
 851{
 852        int fd, fd2;
 853
 854        printf("%s %s %s\n", memfd_str, banner, b_suffix);
 855
 856        fd = mfd_assert_new("kern_memfd_share_dup",
 857                            mfd_def_size,
 858                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 859        mfd_assert_has_seals(fd, 0);
 860
 861        fd2 = mfd_assert_dup(fd);
 862        mfd_assert_has_seals(fd2, 0);
 863
 864        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 865        mfd_assert_has_seals(fd, F_SEAL_WRITE);
 866        mfd_assert_has_seals(fd2, F_SEAL_WRITE);
 867
 868        mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
 869        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 870        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
 871
 872        mfd_assert_add_seals(fd, F_SEAL_SEAL);
 873        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 874        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 875
 876        mfd_fail_add_seals(fd, F_SEAL_GROW);
 877        mfd_fail_add_seals(fd2, F_SEAL_GROW);
 878        mfd_fail_add_seals(fd, F_SEAL_SEAL);
 879        mfd_fail_add_seals(fd2, F_SEAL_SEAL);
 880
 881        close(fd2);
 882
 883        mfd_fail_add_seals(fd, F_SEAL_GROW);
 884        close(fd);
 885}
 886
 887/*
 888 * Test sealing with active mmap()s
 889 * Modifying seals is only allowed if no other mmap() refs exist.
 890 */
 891static void test_share_mmap(char *banner, char *b_suffix)
 892{
 893        int fd;
 894        void *p;
 895
 896        printf("%s %s %s\n", memfd_str,  banner, b_suffix);
 897
 898        fd = mfd_assert_new("kern_memfd_share_mmap",
 899                            mfd_def_size,
 900                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 901        mfd_assert_has_seals(fd, 0);
 902
 903        /* shared/writable ref prevents sealing WRITE, but allows others */
 904        p = mfd_assert_mmap_shared(fd);
 905        mfd_fail_add_seals(fd, F_SEAL_WRITE);
 906        mfd_assert_has_seals(fd, 0);
 907        mfd_assert_add_seals(fd, F_SEAL_SHRINK);
 908        mfd_assert_has_seals(fd, F_SEAL_SHRINK);
 909        munmap(p, mfd_def_size);
 910
 911        /* readable ref allows sealing */
 912        p = mfd_assert_mmap_private(fd);
 913        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 914        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 915        munmap(p, mfd_def_size);
 916
 917        close(fd);
 918}
 919
 920/*
 921 * Test sealing with open(/proc/self/fd/%d)
 922 * Via /proc we can get access to a separate file-context for the same memfd.
 923 * This is *not* like dup(), but like a real separate open(). Make sure the
 924 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
 925 */
 926static void test_share_open(char *banner, char *b_suffix)
 927{
 928        int fd, fd2;
 929
 930        printf("%s %s %s\n", memfd_str, banner, b_suffix);
 931
 932        fd = mfd_assert_new("kern_memfd_share_open",
 933                            mfd_def_size,
 934                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 935        mfd_assert_has_seals(fd, 0);
 936
 937        fd2 = mfd_assert_open(fd, O_RDWR, 0);
 938        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 939        mfd_assert_has_seals(fd, F_SEAL_WRITE);
 940        mfd_assert_has_seals(fd2, F_SEAL_WRITE);
 941
 942        mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
 943        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 944        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
 945
 946        close(fd);
 947        fd = mfd_assert_open(fd2, O_RDONLY, 0);
 948
 949        mfd_fail_add_seals(fd, F_SEAL_SEAL);
 950        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 951        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
 952
 953        close(fd2);
 954        fd2 = mfd_assert_open(fd, O_RDWR, 0);
 955
 956        mfd_assert_add_seals(fd2, F_SEAL_SEAL);
 957        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 958        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 959
 960        close(fd2);
 961        close(fd);
 962}
 963
 964/*
 965 * Test sharing via fork()
 966 * Test whether seal-modifications work as expected with forked childs.
 967 */
 968static void test_share_fork(char *banner, char *b_suffix)
 969{
 970        int fd;
 971        pid_t pid;
 972
 973        printf("%s %s %s\n", memfd_str, banner, b_suffix);
 974
 975        fd = mfd_assert_new("kern_memfd_share_fork",
 976                            mfd_def_size,
 977                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 978        mfd_assert_has_seals(fd, 0);
 979
 980        pid = spawn_idle_thread(0);
 981        mfd_assert_add_seals(fd, F_SEAL_SEAL);
 982        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 983
 984        mfd_fail_add_seals(fd, F_SEAL_WRITE);
 985        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 986
 987        join_idle_thread(pid);
 988
 989        mfd_fail_add_seals(fd, F_SEAL_WRITE);
 990        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 991
 992        close(fd);
 993}
 994
 995int main(int argc, char **argv)
 996{
 997        pid_t pid;
 998
 999        if (argc == 2) {
1000                if (!strcmp(argv[1], "hugetlbfs")) {
1001                        unsigned long hpage_size = default_huge_page_size();
1002
1003                        if (!hpage_size) {
1004                                printf("Unable to determine huge page size\n");
1005                                abort();
1006                        }
1007
1008                        hugetlbfs_test = 1;
1009                        memfd_str = MEMFD_HUGE_STR;
1010                        mfd_def_size = hpage_size * 2;
1011                } else {
1012                        printf("Unknown option: %s\n", argv[1]);
1013                        abort();
1014                }
1015        }
1016
1017        test_create();
1018        test_basic();
1019
1020        test_seal_write();
1021        test_seal_future_write();
1022        test_seal_shrink();
1023        test_seal_grow();
1024        test_seal_resize();
1025
1026        test_share_dup("SHARE-DUP", "");
1027        test_share_mmap("SHARE-MMAP", "");
1028        test_share_open("SHARE-OPEN", "");
1029        test_share_fork("SHARE-FORK", "");
1030
1031        /* Run test-suite in a multi-threaded environment with a shared
1032         * file-table. */
1033        pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
1034        test_share_dup("SHARE-DUP", SHARED_FT_STR);
1035        test_share_mmap("SHARE-MMAP", SHARED_FT_STR);
1036        test_share_open("SHARE-OPEN", SHARED_FT_STR);
1037        test_share_fork("SHARE-FORK", SHARED_FT_STR);
1038        join_idle_thread(pid);
1039
1040        printf("memfd: DONE\n");
1041
1042        return 0;
1043}
1044