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 <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        }
 459
 460        /* verify PUNCH_HOLE fails */
 461        r = fallocate(fd,
 462                      FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
 463                      0,
 464                      mfd_def_size);
 465        if (r >= 0) {
 466                printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
 467                abort();
 468        }
 469}
 470
 471static void mfd_assert_shrink(int fd)
 472{
 473        int r, fd2;
 474
 475        r = ftruncate(fd, mfd_def_size / 2);
 476        if (r < 0) {
 477                printf("ftruncate(SHRINK) failed: %m\n");
 478                abort();
 479        }
 480
 481        mfd_assert_size(fd, mfd_def_size / 2);
 482
 483        fd2 = mfd_assert_open(fd,
 484                              O_RDWR | O_CREAT | O_TRUNC,
 485                              S_IRUSR | S_IWUSR);
 486        close(fd2);
 487
 488        mfd_assert_size(fd, 0);
 489}
 490
 491static void mfd_fail_shrink(int fd)
 492{
 493        int r;
 494
 495        r = ftruncate(fd, mfd_def_size / 2);
 496        if (r >= 0) {
 497                printf("ftruncate(SHRINK) didn't fail as expected\n");
 498                abort();
 499        }
 500
 501        mfd_fail_open(fd,
 502                      O_RDWR | O_CREAT | O_TRUNC,
 503                      S_IRUSR | S_IWUSR);
 504}
 505
 506static void mfd_assert_grow(int fd)
 507{
 508        int r;
 509
 510        r = ftruncate(fd, mfd_def_size * 2);
 511        if (r < 0) {
 512                printf("ftruncate(GROW) failed: %m\n");
 513                abort();
 514        }
 515
 516        mfd_assert_size(fd, mfd_def_size * 2);
 517
 518        r = fallocate(fd,
 519                      0,
 520                      0,
 521                      mfd_def_size * 4);
 522        if (r < 0) {
 523                printf("fallocate(ALLOC) failed: %m\n");
 524                abort();
 525        }
 526
 527        mfd_assert_size(fd, mfd_def_size * 4);
 528}
 529
 530static void mfd_fail_grow(int fd)
 531{
 532        int r;
 533
 534        r = ftruncate(fd, mfd_def_size * 2);
 535        if (r >= 0) {
 536                printf("ftruncate(GROW) didn't fail as expected\n");
 537                abort();
 538        }
 539
 540        r = fallocate(fd,
 541                      0,
 542                      0,
 543                      mfd_def_size * 4);
 544        if (r >= 0) {
 545                printf("fallocate(ALLOC) didn't fail as expected\n");
 546                abort();
 547        }
 548}
 549
 550static void mfd_assert_grow_write(int fd)
 551{
 552        static char *buf;
 553        ssize_t l;
 554
 555        /* hugetlbfs does not support write */
 556        if (hugetlbfs_test)
 557                return;
 558
 559        buf = malloc(mfd_def_size * 8);
 560        if (!buf) {
 561                printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
 562                abort();
 563        }
 564
 565        l = pwrite(fd, buf, mfd_def_size * 8, 0);
 566        if (l != (mfd_def_size * 8)) {
 567                printf("pwrite() failed: %m\n");
 568                abort();
 569        }
 570
 571        mfd_assert_size(fd, mfd_def_size * 8);
 572}
 573
 574static void mfd_fail_grow_write(int fd)
 575{
 576        static char *buf;
 577        ssize_t l;
 578
 579        /* hugetlbfs does not support write */
 580        if (hugetlbfs_test)
 581                return;
 582
 583        buf = malloc(mfd_def_size * 8);
 584        if (!buf) {
 585                printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
 586                abort();
 587        }
 588
 589        l = pwrite(fd, buf, mfd_def_size * 8, 0);
 590        if (l == (mfd_def_size * 8)) {
 591                printf("pwrite() didn't fail as expected\n");
 592                abort();
 593        }
 594}
 595
 596static int idle_thread_fn(void *arg)
 597{
 598        sigset_t set;
 599        int sig;
 600
 601        /* dummy waiter; SIGTERM terminates us anyway */
 602        sigemptyset(&set);
 603        sigaddset(&set, SIGTERM);
 604        sigwait(&set, &sig);
 605
 606        return 0;
 607}
 608
 609static pid_t spawn_idle_thread(unsigned int flags)
 610{
 611        uint8_t *stack;
 612        pid_t pid;
 613
 614        stack = malloc(STACK_SIZE);
 615        if (!stack) {
 616                printf("malloc(STACK_SIZE) failed: %m\n");
 617                abort();
 618        }
 619
 620        pid = clone(idle_thread_fn,
 621                    stack + STACK_SIZE,
 622                    SIGCHLD | flags,
 623                    NULL);
 624        if (pid < 0) {
 625                printf("clone() failed: %m\n");
 626                abort();
 627        }
 628
 629        return pid;
 630}
 631
 632static void join_idle_thread(pid_t pid)
 633{
 634        kill(pid, SIGTERM);
 635        waitpid(pid, NULL, 0);
 636}
 637
 638/*
 639 * Test memfd_create() syscall
 640 * Verify syscall-argument validation, including name checks, flag validation
 641 * and more.
 642 */
 643static void test_create(void)
 644{
 645        char buf[2048];
 646        int fd;
 647
 648        printf("%s CREATE\n", memfd_str);
 649
 650        /* test NULL name */
 651        mfd_fail_new(NULL, 0);
 652
 653        /* test over-long name (not zero-terminated) */
 654        memset(buf, 0xff, sizeof(buf));
 655        mfd_fail_new(buf, 0);
 656
 657        /* test over-long zero-terminated name */
 658        memset(buf, 0xff, sizeof(buf));
 659        buf[sizeof(buf) - 1] = 0;
 660        mfd_fail_new(buf, 0);
 661
 662        /* verify "" is a valid name */
 663        fd = mfd_assert_new("", 0, 0);
 664        close(fd);
 665
 666        /* verify invalid O_* open flags */
 667        mfd_fail_new("", 0x0100);
 668        mfd_fail_new("", ~MFD_CLOEXEC);
 669        mfd_fail_new("", ~MFD_ALLOW_SEALING);
 670        mfd_fail_new("", ~0);
 671        mfd_fail_new("", 0x80000000U);
 672
 673        /* verify MFD_CLOEXEC is allowed */
 674        fd = mfd_assert_new("", 0, MFD_CLOEXEC);
 675        close(fd);
 676
 677        /* verify MFD_ALLOW_SEALING is allowed */
 678        fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
 679        close(fd);
 680
 681        /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
 682        fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
 683        close(fd);
 684}
 685
 686/*
 687 * Test basic sealing
 688 * A very basic sealing test to see whether setting/retrieving seals works.
 689 */
 690static void test_basic(void)
 691{
 692        int fd;
 693
 694        printf("%s BASIC\n", memfd_str);
 695
 696        fd = mfd_assert_new("kern_memfd_basic",
 697                            mfd_def_size,
 698                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 699
 700        /* add basic seals */
 701        mfd_assert_has_seals(fd, 0);
 702        mfd_assert_add_seals(fd, F_SEAL_SHRINK |
 703                                 F_SEAL_WRITE);
 704        mfd_assert_has_seals(fd, F_SEAL_SHRINK |
 705                                 F_SEAL_WRITE);
 706
 707        /* add them again */
 708        mfd_assert_add_seals(fd, F_SEAL_SHRINK |
 709                                 F_SEAL_WRITE);
 710        mfd_assert_has_seals(fd, F_SEAL_SHRINK |
 711                                 F_SEAL_WRITE);
 712
 713        /* add more seals and seal against sealing */
 714        mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
 715        mfd_assert_has_seals(fd, F_SEAL_SHRINK |
 716                                 F_SEAL_GROW |
 717                                 F_SEAL_WRITE |
 718                                 F_SEAL_SEAL);
 719
 720        /* verify that sealing no longer works */
 721        mfd_fail_add_seals(fd, F_SEAL_GROW);
 722        mfd_fail_add_seals(fd, 0);
 723
 724        close(fd);
 725
 726        /* verify sealing does not work without MFD_ALLOW_SEALING */
 727        fd = mfd_assert_new("kern_memfd_basic",
 728                            mfd_def_size,
 729                            MFD_CLOEXEC);
 730        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 731        mfd_fail_add_seals(fd, F_SEAL_SHRINK |
 732                               F_SEAL_GROW |
 733                               F_SEAL_WRITE);
 734        mfd_assert_has_seals(fd, F_SEAL_SEAL);
 735        close(fd);
 736}
 737
 738/*
 739 * Test SEAL_WRITE
 740 * Test whether SEAL_WRITE actually prevents modifications.
 741 */
 742static void test_seal_write(void)
 743{
 744        int fd;
 745
 746        printf("%s SEAL-WRITE\n", memfd_str);
 747
 748        fd = mfd_assert_new("kern_memfd_seal_write",
 749                            mfd_def_size,
 750                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 751        mfd_assert_has_seals(fd, 0);
 752        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 753        mfd_assert_has_seals(fd, F_SEAL_WRITE);
 754
 755        mfd_assert_read(fd);
 756        mfd_fail_write(fd);
 757        mfd_assert_shrink(fd);
 758        mfd_assert_grow(fd);
 759        mfd_fail_grow_write(fd);
 760
 761        close(fd);
 762}
 763
 764/*
 765 * Test SEAL_FUTURE_WRITE
 766 * Test whether SEAL_FUTURE_WRITE actually prevents modifications.
 767 */
 768static void test_seal_future_write(void)
 769{
 770        int fd, fd2;
 771        void *p;
 772
 773        printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
 774
 775        fd = mfd_assert_new("kern_memfd_seal_future_write",
 776                            mfd_def_size,
 777                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 778
 779        p = mfd_assert_mmap_shared(fd);
 780
 781        mfd_assert_has_seals(fd, 0);
 782
 783        mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
 784        mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
 785
 786        /* read should pass, writes should fail */
 787        mfd_assert_read(fd);
 788        mfd_assert_read_shared(fd);
 789        mfd_fail_write(fd);
 790
 791        fd2 = mfd_assert_reopen_fd(fd);
 792        /* read should pass, writes should still fail */
 793        mfd_assert_read(fd2);
 794        mfd_assert_read_shared(fd2);
 795        mfd_fail_write(fd2);
 796
 797        mfd_assert_fork_private_write(fd);
 798
 799        munmap(p, mfd_def_size);
 800        close(fd2);
 801        close(fd);
 802}
 803
 804/*
 805 * Test SEAL_SHRINK
 806 * Test whether SEAL_SHRINK actually prevents shrinking
 807 */
 808static void test_seal_shrink(void)
 809{
 810        int fd;
 811
 812        printf("%s SEAL-SHRINK\n", memfd_str);
 813
 814        fd = mfd_assert_new("kern_memfd_seal_shrink",
 815                            mfd_def_size,
 816                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 817        mfd_assert_has_seals(fd, 0);
 818        mfd_assert_add_seals(fd, F_SEAL_SHRINK);
 819        mfd_assert_has_seals(fd, F_SEAL_SHRINK);
 820
 821        mfd_assert_read(fd);
 822        mfd_assert_write(fd);
 823        mfd_fail_shrink(fd);
 824        mfd_assert_grow(fd);
 825        mfd_assert_grow_write(fd);
 826
 827        close(fd);
 828}
 829
 830/*
 831 * Test SEAL_GROW
 832 * Test whether SEAL_GROW actually prevents growing
 833 */
 834static void test_seal_grow(void)
 835{
 836        int fd;
 837
 838        printf("%s SEAL-GROW\n", memfd_str);
 839
 840        fd = mfd_assert_new("kern_memfd_seal_grow",
 841                            mfd_def_size,
 842                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 843        mfd_assert_has_seals(fd, 0);
 844        mfd_assert_add_seals(fd, F_SEAL_GROW);
 845        mfd_assert_has_seals(fd, F_SEAL_GROW);
 846
 847        mfd_assert_read(fd);
 848        mfd_assert_write(fd);
 849        mfd_assert_shrink(fd);
 850        mfd_fail_grow(fd);
 851        mfd_fail_grow_write(fd);
 852
 853        close(fd);
 854}
 855
 856/*
 857 * Test SEAL_SHRINK | SEAL_GROW
 858 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
 859 */
 860static void test_seal_resize(void)
 861{
 862        int fd;
 863
 864        printf("%s SEAL-RESIZE\n", memfd_str);
 865
 866        fd = mfd_assert_new("kern_memfd_seal_resize",
 867                            mfd_def_size,
 868                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 869        mfd_assert_has_seals(fd, 0);
 870        mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
 871        mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
 872
 873        mfd_assert_read(fd);
 874        mfd_assert_write(fd);
 875        mfd_fail_shrink(fd);
 876        mfd_fail_grow(fd);
 877        mfd_fail_grow_write(fd);
 878
 879        close(fd);
 880}
 881
 882/*
 883 * Test sharing via dup()
 884 * Test that seals are shared between dupped FDs and they're all equal.
 885 */
 886static void test_share_dup(char *banner, char *b_suffix)
 887{
 888        int fd, fd2;
 889
 890        printf("%s %s %s\n", memfd_str, banner, b_suffix);
 891
 892        fd = mfd_assert_new("kern_memfd_share_dup",
 893                            mfd_def_size,
 894                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 895        mfd_assert_has_seals(fd, 0);
 896
 897        fd2 = mfd_assert_dup(fd);
 898        mfd_assert_has_seals(fd2, 0);
 899
 900        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 901        mfd_assert_has_seals(fd, F_SEAL_WRITE);
 902        mfd_assert_has_seals(fd2, F_SEAL_WRITE);
 903
 904        mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
 905        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 906        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
 907
 908        mfd_assert_add_seals(fd, F_SEAL_SEAL);
 909        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 910        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 911
 912        mfd_fail_add_seals(fd, F_SEAL_GROW);
 913        mfd_fail_add_seals(fd2, F_SEAL_GROW);
 914        mfd_fail_add_seals(fd, F_SEAL_SEAL);
 915        mfd_fail_add_seals(fd2, F_SEAL_SEAL);
 916
 917        close(fd2);
 918
 919        mfd_fail_add_seals(fd, F_SEAL_GROW);
 920        close(fd);
 921}
 922
 923/*
 924 * Test sealing with active mmap()s
 925 * Modifying seals is only allowed if no other mmap() refs exist.
 926 */
 927static void test_share_mmap(char *banner, char *b_suffix)
 928{
 929        int fd;
 930        void *p;
 931
 932        printf("%s %s %s\n", memfd_str,  banner, b_suffix);
 933
 934        fd = mfd_assert_new("kern_memfd_share_mmap",
 935                            mfd_def_size,
 936                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 937        mfd_assert_has_seals(fd, 0);
 938
 939        /* shared/writable ref prevents sealing WRITE, but allows others */
 940        p = mfd_assert_mmap_shared(fd);
 941        mfd_fail_add_seals(fd, F_SEAL_WRITE);
 942        mfd_assert_has_seals(fd, 0);
 943        mfd_assert_add_seals(fd, F_SEAL_SHRINK);
 944        mfd_assert_has_seals(fd, F_SEAL_SHRINK);
 945        munmap(p, mfd_def_size);
 946
 947        /* readable ref allows sealing */
 948        p = mfd_assert_mmap_private(fd);
 949        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 950        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 951        munmap(p, mfd_def_size);
 952
 953        close(fd);
 954}
 955
 956/*
 957 * Test sealing with open(/proc/self/fd/%d)
 958 * Via /proc we can get access to a separate file-context for the same memfd.
 959 * This is *not* like dup(), but like a real separate open(). Make sure the
 960 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
 961 */
 962static void test_share_open(char *banner, char *b_suffix)
 963{
 964        int fd, fd2;
 965
 966        printf("%s %s %s\n", memfd_str, banner, b_suffix);
 967
 968        fd = mfd_assert_new("kern_memfd_share_open",
 969                            mfd_def_size,
 970                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
 971        mfd_assert_has_seals(fd, 0);
 972
 973        fd2 = mfd_assert_open(fd, O_RDWR, 0);
 974        mfd_assert_add_seals(fd, F_SEAL_WRITE);
 975        mfd_assert_has_seals(fd, F_SEAL_WRITE);
 976        mfd_assert_has_seals(fd2, F_SEAL_WRITE);
 977
 978        mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
 979        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 980        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
 981
 982        close(fd);
 983        fd = mfd_assert_open(fd2, O_RDONLY, 0);
 984
 985        mfd_fail_add_seals(fd, F_SEAL_SEAL);
 986        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
 987        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
 988
 989        close(fd2);
 990        fd2 = mfd_assert_open(fd, O_RDWR, 0);
 991
 992        mfd_assert_add_seals(fd2, F_SEAL_SEAL);
 993        mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 994        mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
 995
 996        close(fd2);
 997        close(fd);
 998}
 999
1000/*
1001 * Test sharing via fork()
1002 * Test whether seal-modifications work as expected with forked childs.
1003 */
1004static void test_share_fork(char *banner, char *b_suffix)
1005{
1006        int fd;
1007        pid_t pid;
1008
1009        printf("%s %s %s\n", memfd_str, banner, b_suffix);
1010
1011        fd = mfd_assert_new("kern_memfd_share_fork",
1012                            mfd_def_size,
1013                            MFD_CLOEXEC | MFD_ALLOW_SEALING);
1014        mfd_assert_has_seals(fd, 0);
1015
1016        pid = spawn_idle_thread(0);
1017        mfd_assert_add_seals(fd, F_SEAL_SEAL);
1018        mfd_assert_has_seals(fd, F_SEAL_SEAL);
1019
1020        mfd_fail_add_seals(fd, F_SEAL_WRITE);
1021        mfd_assert_has_seals(fd, F_SEAL_SEAL);
1022
1023        join_idle_thread(pid);
1024
1025        mfd_fail_add_seals(fd, F_SEAL_WRITE);
1026        mfd_assert_has_seals(fd, F_SEAL_SEAL);
1027
1028        close(fd);
1029}
1030
1031int main(int argc, char **argv)
1032{
1033        pid_t pid;
1034
1035        if (argc == 2) {
1036                if (!strcmp(argv[1], "hugetlbfs")) {
1037                        unsigned long hpage_size = default_huge_page_size();
1038
1039                        if (!hpage_size) {
1040                                printf("Unable to determine huge page size\n");
1041                                abort();
1042                        }
1043
1044                        hugetlbfs_test = 1;
1045                        memfd_str = MEMFD_HUGE_STR;
1046                        mfd_def_size = hpage_size * 2;
1047                } else {
1048                        printf("Unknown option: %s\n", argv[1]);
1049                        abort();
1050                }
1051        }
1052
1053        test_create();
1054        test_basic();
1055
1056        test_seal_write();
1057        test_seal_future_write();
1058        test_seal_shrink();
1059        test_seal_grow();
1060        test_seal_resize();
1061
1062        test_share_dup("SHARE-DUP", "");
1063        test_share_mmap("SHARE-MMAP", "");
1064        test_share_open("SHARE-OPEN", "");
1065        test_share_fork("SHARE-FORK", "");
1066
1067        /* Run test-suite in a multi-threaded environment with a shared
1068         * file-table. */
1069        pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
1070        test_share_dup("SHARE-DUP", SHARED_FT_STR);
1071        test_share_mmap("SHARE-MMAP", SHARED_FT_STR);
1072        test_share_open("SHARE-OPEN", SHARED_FT_STR);
1073        test_share_fork("SHARE-FORK", SHARED_FT_STR);
1074        join_idle_thread(pid);
1075
1076        printf("memfd: DONE\n");
1077
1078        return 0;
1079}
1080