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