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