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