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 }
1115