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
23static int sys_memfd_create(const char *name,
24			    unsigned int flags)
25{
26	return syscall(__NR_memfd_create, name, flags);
27}
28
29static 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
49static 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
62static 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
75static 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
86static 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
99static 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
118static 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
134static 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
147static 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
165static 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
183static 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
198static 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
211static 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
250static 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
324static 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
388static 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
408static 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
423static 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
447static 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
467static 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
481static 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
493static 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
506static 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
529static 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 */
540static 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 */
585static 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 */
635static 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 */
659static 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 */
683static 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 */
707static 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 */
731static 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 */
770static 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 */
803static 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 */
843static 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
868int 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}
912