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