Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #define _GNU_SOURCE
0003 #define __EXPORTED_HEADERS__
0004 
0005 #include <errno.h>
0006 #include <inttypes.h>
0007 #include <limits.h>
0008 #include <linux/falloc.h>
0009 #include <fcntl.h>
0010 #include <linux/memfd.h>
0011 #include <sched.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <signal.h>
0015 #include <string.h>
0016 #include <sys/mman.h>
0017 #include <sys/stat.h>
0018 #include <sys/syscall.h>
0019 #include <sys/wait.h>
0020 #include <unistd.h>
0021 
0022 #include "common.h"
0023 
0024 #define MEMFD_STR   "memfd:"
0025 #define MEMFD_HUGE_STR  "memfd-hugetlb:"
0026 #define SHARED_FT_STR   "(shared file-table)"
0027 
0028 #define MFD_DEF_SIZE 8192
0029 #define STACK_SIZE 65536
0030 
0031 /*
0032  * Default is not to test hugetlbfs
0033  */
0034 static size_t mfd_def_size = MFD_DEF_SIZE;
0035 static const char *memfd_str = MEMFD_STR;
0036 
0037 static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
0038 {
0039     int r, fd;
0040 
0041     fd = sys_memfd_create(name, flags);
0042     if (fd < 0) {
0043         printf("memfd_create(\"%s\", %u) failed: %m\n",
0044                name, flags);
0045         abort();
0046     }
0047 
0048     r = ftruncate(fd, sz);
0049     if (r < 0) {
0050         printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
0051         abort();
0052     }
0053 
0054     return fd;
0055 }
0056 
0057 static int mfd_assert_reopen_fd(int fd_in)
0058 {
0059     int fd;
0060     char path[100];
0061 
0062     sprintf(path, "/proc/self/fd/%d", fd_in);
0063 
0064     fd = open(path, O_RDWR);
0065     if (fd < 0) {
0066         printf("re-open of existing fd %d failed\n", fd_in);
0067         abort();
0068     }
0069 
0070     return fd;
0071 }
0072 
0073 static void mfd_fail_new(const char *name, unsigned int flags)
0074 {
0075     int r;
0076 
0077     r = sys_memfd_create(name, flags);
0078     if (r >= 0) {
0079         printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
0080                name, flags);
0081         close(r);
0082         abort();
0083     }
0084 }
0085 
0086 static unsigned int mfd_assert_get_seals(int fd)
0087 {
0088     int r;
0089 
0090     r = fcntl(fd, F_GET_SEALS);
0091     if (r < 0) {
0092         printf("GET_SEALS(%d) failed: %m\n", fd);
0093         abort();
0094     }
0095 
0096     return (unsigned int)r;
0097 }
0098 
0099 static void mfd_assert_has_seals(int fd, unsigned int seals)
0100 {
0101     unsigned int s;
0102 
0103     s = mfd_assert_get_seals(fd);
0104     if (s != seals) {
0105         printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd);
0106         abort();
0107     }
0108 }
0109 
0110 static void mfd_assert_add_seals(int fd, unsigned int seals)
0111 {
0112     int r;
0113     unsigned int s;
0114 
0115     s = mfd_assert_get_seals(fd);
0116     r = fcntl(fd, F_ADD_SEALS, seals);
0117     if (r < 0) {
0118         printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
0119         abort();
0120     }
0121 }
0122 
0123 static void mfd_fail_add_seals(int fd, unsigned int seals)
0124 {
0125     int r;
0126     unsigned int s;
0127 
0128     r = fcntl(fd, F_GET_SEALS);
0129     if (r < 0)
0130         s = 0;
0131     else
0132         s = (unsigned int)r;
0133 
0134     r = fcntl(fd, F_ADD_SEALS, seals);
0135     if (r >= 0) {
0136         printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
0137                 fd, s, seals);
0138         abort();
0139     }
0140 }
0141 
0142 static void mfd_assert_size(int fd, size_t size)
0143 {
0144     struct stat st;
0145     int r;
0146 
0147     r = fstat(fd, &st);
0148     if (r < 0) {
0149         printf("fstat(%d) failed: %m\n", fd);
0150         abort();
0151     } else if (st.st_size != size) {
0152         printf("wrong file size %lld, but expected %lld\n",
0153                (long long)st.st_size, (long long)size);
0154         abort();
0155     }
0156 }
0157 
0158 static int mfd_assert_dup(int fd)
0159 {
0160     int r;
0161 
0162     r = dup(fd);
0163     if (r < 0) {
0164         printf("dup(%d) failed: %m\n", fd);
0165         abort();
0166     }
0167 
0168     return r;
0169 }
0170 
0171 static void *mfd_assert_mmap_shared(int fd)
0172 {
0173     void *p;
0174 
0175     p = mmap(NULL,
0176          mfd_def_size,
0177          PROT_READ | PROT_WRITE,
0178          MAP_SHARED,
0179          fd,
0180          0);
0181     if (p == MAP_FAILED) {
0182         printf("mmap() failed: %m\n");
0183         abort();
0184     }
0185 
0186     return p;
0187 }
0188 
0189 static void *mfd_assert_mmap_private(int fd)
0190 {
0191     void *p;
0192 
0193     p = mmap(NULL,
0194          mfd_def_size,
0195          PROT_READ,
0196          MAP_PRIVATE,
0197          fd,
0198          0);
0199     if (p == MAP_FAILED) {
0200         printf("mmap() failed: %m\n");
0201         abort();
0202     }
0203 
0204     return p;
0205 }
0206 
0207 static int mfd_assert_open(int fd, int flags, mode_t mode)
0208 {
0209     char buf[512];
0210     int r;
0211 
0212     sprintf(buf, "/proc/self/fd/%d", fd);
0213     r = open(buf, flags, mode);
0214     if (r < 0) {
0215         printf("open(%s) failed: %m\n", buf);
0216         abort();
0217     }
0218 
0219     return r;
0220 }
0221 
0222 static void mfd_fail_open(int fd, int flags, mode_t mode)
0223 {
0224     char buf[512];
0225     int r;
0226 
0227     sprintf(buf, "/proc/self/fd/%d", fd);
0228     r = open(buf, flags, mode);
0229     if (r >= 0) {
0230         printf("open(%s) didn't fail as expected\n", buf);
0231         abort();
0232     }
0233 }
0234 
0235 static void mfd_assert_read(int fd)
0236 {
0237     char buf[16];
0238     void *p;
0239     ssize_t l;
0240 
0241     l = read(fd, buf, sizeof(buf));
0242     if (l != sizeof(buf)) {
0243         printf("read() failed: %m\n");
0244         abort();
0245     }
0246 
0247     /* verify PROT_READ *is* allowed */
0248     p = mmap(NULL,
0249          mfd_def_size,
0250          PROT_READ,
0251          MAP_PRIVATE,
0252          fd,
0253          0);
0254     if (p == MAP_FAILED) {
0255         printf("mmap() failed: %m\n");
0256         abort();
0257     }
0258     munmap(p, mfd_def_size);
0259 
0260     /* verify MAP_PRIVATE is *always* allowed (even writable) */
0261     p = mmap(NULL,
0262          mfd_def_size,
0263          PROT_READ | PROT_WRITE,
0264          MAP_PRIVATE,
0265          fd,
0266          0);
0267     if (p == MAP_FAILED) {
0268         printf("mmap() failed: %m\n");
0269         abort();
0270     }
0271     munmap(p, mfd_def_size);
0272 }
0273 
0274 /* Test that PROT_READ + MAP_SHARED mappings work. */
0275 static void mfd_assert_read_shared(int fd)
0276 {
0277     void *p;
0278 
0279     /* verify PROT_READ and MAP_SHARED *is* allowed */
0280     p = mmap(NULL,
0281          mfd_def_size,
0282          PROT_READ,
0283          MAP_SHARED,
0284          fd,
0285          0);
0286     if (p == MAP_FAILED) {
0287         printf("mmap() failed: %m\n");
0288         abort();
0289     }
0290     munmap(p, mfd_def_size);
0291 }
0292 
0293 static void mfd_assert_fork_private_write(int fd)
0294 {
0295     int *p;
0296     pid_t pid;
0297 
0298     p = mmap(NULL,
0299          mfd_def_size,
0300          PROT_READ | PROT_WRITE,
0301          MAP_PRIVATE,
0302          fd,
0303          0);
0304     if (p == MAP_FAILED) {
0305         printf("mmap() failed: %m\n");
0306         abort();
0307     }
0308 
0309     p[0] = 22;
0310 
0311     pid = fork();
0312     if (pid == 0) {
0313         p[0] = 33;
0314         exit(0);
0315     } else {
0316         waitpid(pid, NULL, 0);
0317 
0318         if (p[0] != 22) {
0319             printf("MAP_PRIVATE copy-on-write failed: %m\n");
0320             abort();
0321         }
0322     }
0323 
0324     munmap(p, mfd_def_size);
0325 }
0326 
0327 static void mfd_assert_write(int fd)
0328 {
0329     ssize_t l;
0330     void *p;
0331     int r;
0332 
0333     /*
0334      * huegtlbfs does not support write, but we want to
0335      * verify everything else here.
0336      */
0337     if (!hugetlbfs_test) {
0338         /* verify write() succeeds */
0339         l = write(fd, "\0\0\0\0", 4);
0340         if (l != 4) {
0341             printf("write() failed: %m\n");
0342             abort();
0343         }
0344     }
0345 
0346     /* verify PROT_READ | PROT_WRITE is allowed */
0347     p = mmap(NULL,
0348          mfd_def_size,
0349          PROT_READ | PROT_WRITE,
0350          MAP_SHARED,
0351          fd,
0352          0);
0353     if (p == MAP_FAILED) {
0354         printf("mmap() failed: %m\n");
0355         abort();
0356     }
0357     *(char *)p = 0;
0358     munmap(p, mfd_def_size);
0359 
0360     /* verify PROT_WRITE is allowed */
0361     p = mmap(NULL,
0362          mfd_def_size,
0363          PROT_WRITE,
0364          MAP_SHARED,
0365          fd,
0366          0);
0367     if (p == MAP_FAILED) {
0368         printf("mmap() failed: %m\n");
0369         abort();
0370     }
0371     *(char *)p = 0;
0372     munmap(p, mfd_def_size);
0373 
0374     /* verify PROT_READ with MAP_SHARED is allowed and a following
0375      * mprotect(PROT_WRITE) allows writing */
0376     p = mmap(NULL,
0377          mfd_def_size,
0378          PROT_READ,
0379          MAP_SHARED,
0380          fd,
0381          0);
0382     if (p == MAP_FAILED) {
0383         printf("mmap() failed: %m\n");
0384         abort();
0385     }
0386 
0387     r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
0388     if (r < 0) {
0389         printf("mprotect() failed: %m\n");
0390         abort();
0391     }
0392 
0393     *(char *)p = 0;
0394     munmap(p, mfd_def_size);
0395 
0396     /* verify PUNCH_HOLE works */
0397     r = fallocate(fd,
0398               FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0399               0,
0400               mfd_def_size);
0401     if (r < 0) {
0402         printf("fallocate(PUNCH_HOLE) failed: %m\n");
0403         abort();
0404     }
0405 }
0406 
0407 static void mfd_fail_write(int fd)
0408 {
0409     ssize_t l;
0410     void *p;
0411     int r;
0412 
0413     /* verify write() fails */
0414     l = write(fd, "data", 4);
0415     if (l != -EPERM) {
0416         printf("expected EPERM on write(), but got %d: %m\n", (int)l);
0417         abort();
0418     }
0419 
0420     /* verify PROT_READ | PROT_WRITE is not allowed */
0421     p = mmap(NULL,
0422          mfd_def_size,
0423          PROT_READ | PROT_WRITE,
0424          MAP_SHARED,
0425          fd,
0426          0);
0427     if (p != MAP_FAILED) {
0428         printf("mmap() didn't fail as expected\n");
0429         abort();
0430     }
0431 
0432     /* verify PROT_WRITE is not allowed */
0433     p = mmap(NULL,
0434          mfd_def_size,
0435          PROT_WRITE,
0436          MAP_SHARED,
0437          fd,
0438          0);
0439     if (p != MAP_FAILED) {
0440         printf("mmap() didn't fail as expected\n");
0441         abort();
0442     }
0443 
0444     /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
0445      * allowed. Note that for r/w the kernel already prevents the mmap. */
0446     p = mmap(NULL,
0447          mfd_def_size,
0448          PROT_READ,
0449          MAP_SHARED,
0450          fd,
0451          0);
0452     if (p != MAP_FAILED) {
0453         r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
0454         if (r >= 0) {
0455             printf("mmap()+mprotect() didn't fail as expected\n");
0456             abort();
0457         }
0458         munmap(p, mfd_def_size);
0459     }
0460 
0461     /* verify PUNCH_HOLE fails */
0462     r = fallocate(fd,
0463               FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0464               0,
0465               mfd_def_size);
0466     if (r >= 0) {
0467         printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
0468         abort();
0469     }
0470 }
0471 
0472 static void mfd_assert_shrink(int fd)
0473 {
0474     int r, fd2;
0475 
0476     r = ftruncate(fd, mfd_def_size / 2);
0477     if (r < 0) {
0478         printf("ftruncate(SHRINK) failed: %m\n");
0479         abort();
0480     }
0481 
0482     mfd_assert_size(fd, mfd_def_size / 2);
0483 
0484     fd2 = mfd_assert_open(fd,
0485                   O_RDWR | O_CREAT | O_TRUNC,
0486                   S_IRUSR | S_IWUSR);
0487     close(fd2);
0488 
0489     mfd_assert_size(fd, 0);
0490 }
0491 
0492 static void mfd_fail_shrink(int fd)
0493 {
0494     int r;
0495 
0496     r = ftruncate(fd, mfd_def_size / 2);
0497     if (r >= 0) {
0498         printf("ftruncate(SHRINK) didn't fail as expected\n");
0499         abort();
0500     }
0501 
0502     mfd_fail_open(fd,
0503               O_RDWR | O_CREAT | O_TRUNC,
0504               S_IRUSR | S_IWUSR);
0505 }
0506 
0507 static void mfd_assert_grow(int fd)
0508 {
0509     int r;
0510 
0511     r = ftruncate(fd, mfd_def_size * 2);
0512     if (r < 0) {
0513         printf("ftruncate(GROW) failed: %m\n");
0514         abort();
0515     }
0516 
0517     mfd_assert_size(fd, mfd_def_size * 2);
0518 
0519     r = fallocate(fd,
0520               0,
0521               0,
0522               mfd_def_size * 4);
0523     if (r < 0) {
0524         printf("fallocate(ALLOC) failed: %m\n");
0525         abort();
0526     }
0527 
0528     mfd_assert_size(fd, mfd_def_size * 4);
0529 }
0530 
0531 static void mfd_fail_grow(int fd)
0532 {
0533     int r;
0534 
0535     r = ftruncate(fd, mfd_def_size * 2);
0536     if (r >= 0) {
0537         printf("ftruncate(GROW) didn't fail as expected\n");
0538         abort();
0539     }
0540 
0541     r = fallocate(fd,
0542               0,
0543               0,
0544               mfd_def_size * 4);
0545     if (r >= 0) {
0546         printf("fallocate(ALLOC) didn't fail as expected\n");
0547         abort();
0548     }
0549 }
0550 
0551 static void mfd_assert_grow_write(int fd)
0552 {
0553     static char *buf;
0554     ssize_t l;
0555 
0556     /* hugetlbfs does not support write */
0557     if (hugetlbfs_test)
0558         return;
0559 
0560     buf = malloc(mfd_def_size * 8);
0561     if (!buf) {
0562         printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
0563         abort();
0564     }
0565 
0566     l = pwrite(fd, buf, mfd_def_size * 8, 0);
0567     if (l != (mfd_def_size * 8)) {
0568         printf("pwrite() failed: %m\n");
0569         abort();
0570     }
0571 
0572     mfd_assert_size(fd, mfd_def_size * 8);
0573 }
0574 
0575 static void mfd_fail_grow_write(int fd)
0576 {
0577     static char *buf;
0578     ssize_t l;
0579 
0580     /* hugetlbfs does not support write */
0581     if (hugetlbfs_test)
0582         return;
0583 
0584     buf = malloc(mfd_def_size * 8);
0585     if (!buf) {
0586         printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
0587         abort();
0588     }
0589 
0590     l = pwrite(fd, buf, mfd_def_size * 8, 0);
0591     if (l == (mfd_def_size * 8)) {
0592         printf("pwrite() didn't fail as expected\n");
0593         abort();
0594     }
0595 }
0596 
0597 static int idle_thread_fn(void *arg)
0598 {
0599     sigset_t set;
0600     int sig;
0601 
0602     /* dummy waiter; SIGTERM terminates us anyway */
0603     sigemptyset(&set);
0604     sigaddset(&set, SIGTERM);
0605     sigwait(&set, &sig);
0606 
0607     return 0;
0608 }
0609 
0610 static pid_t spawn_idle_thread(unsigned int flags)
0611 {
0612     uint8_t *stack;
0613     pid_t pid;
0614 
0615     stack = malloc(STACK_SIZE);
0616     if (!stack) {
0617         printf("malloc(STACK_SIZE) failed: %m\n");
0618         abort();
0619     }
0620 
0621     pid = clone(idle_thread_fn,
0622             stack + STACK_SIZE,
0623             SIGCHLD | flags,
0624             NULL);
0625     if (pid < 0) {
0626         printf("clone() failed: %m\n");
0627         abort();
0628     }
0629 
0630     return pid;
0631 }
0632 
0633 static void join_idle_thread(pid_t pid)
0634 {
0635     kill(pid, SIGTERM);
0636     waitpid(pid, NULL, 0);
0637 }
0638 
0639 /*
0640  * Test memfd_create() syscall
0641  * Verify syscall-argument validation, including name checks, flag validation
0642  * and more.
0643  */
0644 static void test_create(void)
0645 {
0646     char buf[2048];
0647     int fd;
0648 
0649     printf("%s CREATE\n", memfd_str);
0650 
0651     /* test NULL name */
0652     mfd_fail_new(NULL, 0);
0653 
0654     /* test over-long name (not zero-terminated) */
0655     memset(buf, 0xff, sizeof(buf));
0656     mfd_fail_new(buf, 0);
0657 
0658     /* test over-long zero-terminated name */
0659     memset(buf, 0xff, sizeof(buf));
0660     buf[sizeof(buf) - 1] = 0;
0661     mfd_fail_new(buf, 0);
0662 
0663     /* verify "" is a valid name */
0664     fd = mfd_assert_new("", 0, 0);
0665     close(fd);
0666 
0667     /* verify invalid O_* open flags */
0668     mfd_fail_new("", 0x0100);
0669     mfd_fail_new("", ~MFD_CLOEXEC);
0670     mfd_fail_new("", ~MFD_ALLOW_SEALING);
0671     mfd_fail_new("", ~0);
0672     mfd_fail_new("", 0x80000000U);
0673 
0674     /* verify MFD_CLOEXEC is allowed */
0675     fd = mfd_assert_new("", 0, MFD_CLOEXEC);
0676     close(fd);
0677 
0678     /* verify MFD_ALLOW_SEALING is allowed */
0679     fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
0680     close(fd);
0681 
0682     /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
0683     fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
0684     close(fd);
0685 }
0686 
0687 /*
0688  * Test basic sealing
0689  * A very basic sealing test to see whether setting/retrieving seals works.
0690  */
0691 static void test_basic(void)
0692 {
0693     int fd;
0694 
0695     printf("%s BASIC\n", memfd_str);
0696 
0697     fd = mfd_assert_new("kern_memfd_basic",
0698                 mfd_def_size,
0699                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0700 
0701     /* add basic seals */
0702     mfd_assert_has_seals(fd, 0);
0703     mfd_assert_add_seals(fd, F_SEAL_SHRINK |
0704                  F_SEAL_WRITE);
0705     mfd_assert_has_seals(fd, F_SEAL_SHRINK |
0706                  F_SEAL_WRITE);
0707 
0708     /* add them again */
0709     mfd_assert_add_seals(fd, F_SEAL_SHRINK |
0710                  F_SEAL_WRITE);
0711     mfd_assert_has_seals(fd, F_SEAL_SHRINK |
0712                  F_SEAL_WRITE);
0713 
0714     /* add more seals and seal against sealing */
0715     mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
0716     mfd_assert_has_seals(fd, F_SEAL_SHRINK |
0717                  F_SEAL_GROW |
0718                  F_SEAL_WRITE |
0719                  F_SEAL_SEAL);
0720 
0721     /* verify that sealing no longer works */
0722     mfd_fail_add_seals(fd, F_SEAL_GROW);
0723     mfd_fail_add_seals(fd, 0);
0724 
0725     close(fd);
0726 
0727     /* verify sealing does not work without MFD_ALLOW_SEALING */
0728     fd = mfd_assert_new("kern_memfd_basic",
0729                 mfd_def_size,
0730                 MFD_CLOEXEC);
0731     mfd_assert_has_seals(fd, F_SEAL_SEAL);
0732     mfd_fail_add_seals(fd, F_SEAL_SHRINK |
0733                    F_SEAL_GROW |
0734                    F_SEAL_WRITE);
0735     mfd_assert_has_seals(fd, F_SEAL_SEAL);
0736     close(fd);
0737 }
0738 
0739 /*
0740  * Test SEAL_WRITE
0741  * Test whether SEAL_WRITE actually prevents modifications.
0742  */
0743 static void test_seal_write(void)
0744 {
0745     int fd;
0746 
0747     printf("%s SEAL-WRITE\n", memfd_str);
0748 
0749     fd = mfd_assert_new("kern_memfd_seal_write",
0750                 mfd_def_size,
0751                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0752     mfd_assert_has_seals(fd, 0);
0753     mfd_assert_add_seals(fd, F_SEAL_WRITE);
0754     mfd_assert_has_seals(fd, F_SEAL_WRITE);
0755 
0756     mfd_assert_read(fd);
0757     mfd_fail_write(fd);
0758     mfd_assert_shrink(fd);
0759     mfd_assert_grow(fd);
0760     mfd_fail_grow_write(fd);
0761 
0762     close(fd);
0763 }
0764 
0765 /*
0766  * Test SEAL_FUTURE_WRITE
0767  * Test whether SEAL_FUTURE_WRITE actually prevents modifications.
0768  */
0769 static void test_seal_future_write(void)
0770 {
0771     int fd, fd2;
0772     void *p;
0773 
0774     printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
0775 
0776     fd = mfd_assert_new("kern_memfd_seal_future_write",
0777                 mfd_def_size,
0778                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0779 
0780     p = mfd_assert_mmap_shared(fd);
0781 
0782     mfd_assert_has_seals(fd, 0);
0783 
0784     mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
0785     mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
0786 
0787     /* read should pass, writes should fail */
0788     mfd_assert_read(fd);
0789     mfd_assert_read_shared(fd);
0790     mfd_fail_write(fd);
0791 
0792     fd2 = mfd_assert_reopen_fd(fd);
0793     /* read should pass, writes should still fail */
0794     mfd_assert_read(fd2);
0795     mfd_assert_read_shared(fd2);
0796     mfd_fail_write(fd2);
0797 
0798     mfd_assert_fork_private_write(fd);
0799 
0800     munmap(p, mfd_def_size);
0801     close(fd2);
0802     close(fd);
0803 }
0804 
0805 /*
0806  * Test SEAL_SHRINK
0807  * Test whether SEAL_SHRINK actually prevents shrinking
0808  */
0809 static void test_seal_shrink(void)
0810 {
0811     int fd;
0812 
0813     printf("%s SEAL-SHRINK\n", memfd_str);
0814 
0815     fd = mfd_assert_new("kern_memfd_seal_shrink",
0816                 mfd_def_size,
0817                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0818     mfd_assert_has_seals(fd, 0);
0819     mfd_assert_add_seals(fd, F_SEAL_SHRINK);
0820     mfd_assert_has_seals(fd, F_SEAL_SHRINK);
0821 
0822     mfd_assert_read(fd);
0823     mfd_assert_write(fd);
0824     mfd_fail_shrink(fd);
0825     mfd_assert_grow(fd);
0826     mfd_assert_grow_write(fd);
0827 
0828     close(fd);
0829 }
0830 
0831 /*
0832  * Test SEAL_GROW
0833  * Test whether SEAL_GROW actually prevents growing
0834  */
0835 static void test_seal_grow(void)
0836 {
0837     int fd;
0838 
0839     printf("%s SEAL-GROW\n", memfd_str);
0840 
0841     fd = mfd_assert_new("kern_memfd_seal_grow",
0842                 mfd_def_size,
0843                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0844     mfd_assert_has_seals(fd, 0);
0845     mfd_assert_add_seals(fd, F_SEAL_GROW);
0846     mfd_assert_has_seals(fd, F_SEAL_GROW);
0847 
0848     mfd_assert_read(fd);
0849     mfd_assert_write(fd);
0850     mfd_assert_shrink(fd);
0851     mfd_fail_grow(fd);
0852     mfd_fail_grow_write(fd);
0853 
0854     close(fd);
0855 }
0856 
0857 /*
0858  * Test SEAL_SHRINK | SEAL_GROW
0859  * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
0860  */
0861 static void test_seal_resize(void)
0862 {
0863     int fd;
0864 
0865     printf("%s SEAL-RESIZE\n", memfd_str);
0866 
0867     fd = mfd_assert_new("kern_memfd_seal_resize",
0868                 mfd_def_size,
0869                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0870     mfd_assert_has_seals(fd, 0);
0871     mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
0872     mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
0873 
0874     mfd_assert_read(fd);
0875     mfd_assert_write(fd);
0876     mfd_fail_shrink(fd);
0877     mfd_fail_grow(fd);
0878     mfd_fail_grow_write(fd);
0879 
0880     close(fd);
0881 }
0882 
0883 /*
0884  * Test sharing via dup()
0885  * Test that seals are shared between dupped FDs and they're all equal.
0886  */
0887 static void test_share_dup(char *banner, char *b_suffix)
0888 {
0889     int fd, fd2;
0890 
0891     printf("%s %s %s\n", memfd_str, banner, b_suffix);
0892 
0893     fd = mfd_assert_new("kern_memfd_share_dup",
0894                 mfd_def_size,
0895                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0896     mfd_assert_has_seals(fd, 0);
0897 
0898     fd2 = mfd_assert_dup(fd);
0899     mfd_assert_has_seals(fd2, 0);
0900 
0901     mfd_assert_add_seals(fd, F_SEAL_WRITE);
0902     mfd_assert_has_seals(fd, F_SEAL_WRITE);
0903     mfd_assert_has_seals(fd2, F_SEAL_WRITE);
0904 
0905     mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
0906     mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
0907     mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
0908 
0909     mfd_assert_add_seals(fd, F_SEAL_SEAL);
0910     mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
0911     mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
0912 
0913     mfd_fail_add_seals(fd, F_SEAL_GROW);
0914     mfd_fail_add_seals(fd2, F_SEAL_GROW);
0915     mfd_fail_add_seals(fd, F_SEAL_SEAL);
0916     mfd_fail_add_seals(fd2, F_SEAL_SEAL);
0917 
0918     close(fd2);
0919 
0920     mfd_fail_add_seals(fd, F_SEAL_GROW);
0921     close(fd);
0922 }
0923 
0924 /*
0925  * Test sealing with active mmap()s
0926  * Modifying seals is only allowed if no other mmap() refs exist.
0927  */
0928 static void test_share_mmap(char *banner, char *b_suffix)
0929 {
0930     int fd;
0931     void *p;
0932 
0933     printf("%s %s %s\n", memfd_str,  banner, b_suffix);
0934 
0935     fd = mfd_assert_new("kern_memfd_share_mmap",
0936                 mfd_def_size,
0937                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0938     mfd_assert_has_seals(fd, 0);
0939 
0940     /* shared/writable ref prevents sealing WRITE, but allows others */
0941     p = mfd_assert_mmap_shared(fd);
0942     mfd_fail_add_seals(fd, F_SEAL_WRITE);
0943     mfd_assert_has_seals(fd, 0);
0944     mfd_assert_add_seals(fd, F_SEAL_SHRINK);
0945     mfd_assert_has_seals(fd, F_SEAL_SHRINK);
0946     munmap(p, mfd_def_size);
0947 
0948     /* readable ref allows sealing */
0949     p = mfd_assert_mmap_private(fd);
0950     mfd_assert_add_seals(fd, F_SEAL_WRITE);
0951     mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
0952     munmap(p, mfd_def_size);
0953 
0954     close(fd);
0955 }
0956 
0957 /*
0958  * Test sealing with open(/proc/self/fd/%d)
0959  * Via /proc we can get access to a separate file-context for the same memfd.
0960  * This is *not* like dup(), but like a real separate open(). Make sure the
0961  * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
0962  */
0963 static void test_share_open(char *banner, char *b_suffix)
0964 {
0965     int fd, fd2;
0966 
0967     printf("%s %s %s\n", memfd_str, banner, b_suffix);
0968 
0969     fd = mfd_assert_new("kern_memfd_share_open",
0970                 mfd_def_size,
0971                 MFD_CLOEXEC | MFD_ALLOW_SEALING);
0972     mfd_assert_has_seals(fd, 0);
0973 
0974     fd2 = mfd_assert_open(fd, O_RDWR, 0);
0975     mfd_assert_add_seals(fd, F_SEAL_WRITE);
0976     mfd_assert_has_seals(fd, F_SEAL_WRITE);
0977     mfd_assert_has_seals(fd2, F_SEAL_WRITE);
0978 
0979     mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
0980     mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
0981     mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
0982 
0983     close(fd);
0984     fd = mfd_assert_open(fd2, O_RDONLY, 0);
0985 
0986     mfd_fail_add_seals(fd, F_SEAL_SEAL);
0987     mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
0988     mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
0989 
0990     close(fd2);
0991     fd2 = mfd_assert_open(fd, O_RDWR, 0);
0992 
0993     mfd_assert_add_seals(fd2, F_SEAL_SEAL);
0994     mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
0995     mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
0996 
0997     close(fd2);
0998     close(fd);
0999 }
1000 
1001 /*
1002  * Test sharing via fork()
1003  * Test whether seal-modifications work as expected with forked childs.
1004  */
1005 static 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 
1032 int 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 }