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