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