cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

memfd_test.c (21407B)


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