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