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