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