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