xref: /openbmc/linux/tools/testing/selftests/memfd/memfd_test.c (revision 55e43d6abd078ed6d219902ce8cb4d68e3c993ba)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
24f5ce5e8SDavid Herrmann #define _GNU_SOURCE
34f5ce5e8SDavid Herrmann #define __EXPORTED_HEADERS__
44f5ce5e8SDavid Herrmann 
54f5ce5e8SDavid Herrmann #include <errno.h>
64f5ce5e8SDavid Herrmann #include <inttypes.h>
74f5ce5e8SDavid Herrmann #include <limits.h>
84f5ce5e8SDavid Herrmann #include <linux/falloc.h>
91c49e378SMichael Ellerman #include <fcntl.h>
104f5ce5e8SDavid Herrmann #include <linux/memfd.h>
114f5ce5e8SDavid Herrmann #include <sched.h>
12*8b7dfdf3SIsaac J. Manjarres #include <stdbool.h>
134f5ce5e8SDavid Herrmann #include <stdio.h>
144f5ce5e8SDavid Herrmann #include <stdlib.h>
154f5ce5e8SDavid Herrmann #include <signal.h>
164f5ce5e8SDavid Herrmann #include <string.h>
174f5ce5e8SDavid Herrmann #include <sys/mman.h>
184f5ce5e8SDavid Herrmann #include <sys/stat.h>
194f5ce5e8SDavid Herrmann #include <sys/syscall.h>
20c1ee4831SBen Hutchings #include <sys/wait.h>
214f5ce5e8SDavid Herrmann #include <unistd.h>
226469b66eSAleksa Sarai #include <ctype.h>
234f5ce5e8SDavid Herrmann 
2429f34d1dSMarc-André Lureau #include "common.h"
2529f34d1dSMarc-André Lureau 
261f522a48SMike Kravetz #define MEMFD_STR	"memfd:"
273037aeb9SMarc-André Lureau #define MEMFD_HUGE_STR	"memfd-hugetlb:"
281f522a48SMike Kravetz #define SHARED_FT_STR	"(shared file-table)"
291f522a48SMike Kravetz 
304f5ce5e8SDavid Herrmann #define MFD_DEF_SIZE 8192
311f78dda2SChunyan Zhang #define STACK_SIZE 65536
324f5ce5e8SDavid Herrmann 
3332d118adSDaniel Verkamp #define F_SEAL_EXEC	0x0020
3432d118adSDaniel Verkamp 
3511f75a01SJeff Xu #define F_WX_SEALS (F_SEAL_SHRINK | \
3611f75a01SJeff Xu 		    F_SEAL_GROW | \
3711f75a01SJeff Xu 		    F_SEAL_WRITE | \
3811f75a01SJeff Xu 		    F_SEAL_FUTURE_WRITE | \
3911f75a01SJeff Xu 		    F_SEAL_EXEC)
4011f75a01SJeff Xu 
4111f75a01SJeff Xu #define MFD_NOEXEC_SEAL	0x0008U
4211f75a01SJeff Xu 
431f522a48SMike Kravetz /*
441f522a48SMike Kravetz  * Default is not to test hugetlbfs
451f522a48SMike Kravetz  */
461f522a48SMike Kravetz static size_t mfd_def_size = MFD_DEF_SIZE;
473037aeb9SMarc-André Lureau static const char *memfd_str = MEMFD_STR;
483cc0c373SJeff Xu static int newpid_thread_fn2(void *arg);
493cc0c373SJeff Xu static void join_newpid_thread(pid_t pid);
501f522a48SMike Kravetz 
fd2name(int fd,char * buf,size_t bufsize)5132d118adSDaniel Verkamp static ssize_t fd2name(int fd, char *buf, size_t bufsize)
5232d118adSDaniel Verkamp {
5332d118adSDaniel Verkamp 	char buf1[PATH_MAX];
5432d118adSDaniel Verkamp 	int size;
5532d118adSDaniel Verkamp 	ssize_t nbytes;
5632d118adSDaniel Verkamp 
5732d118adSDaniel Verkamp 	size = snprintf(buf1, PATH_MAX, "/proc/self/fd/%d", fd);
5832d118adSDaniel Verkamp 	if (size < 0) {
5932d118adSDaniel Verkamp 		printf("snprintf(%d) failed on %m\n", fd);
6032d118adSDaniel Verkamp 		abort();
6132d118adSDaniel Verkamp 	}
6232d118adSDaniel Verkamp 
6332d118adSDaniel Verkamp 	/*
6432d118adSDaniel Verkamp 	 * reserver one byte for string termination.
6532d118adSDaniel Verkamp 	 */
6632d118adSDaniel Verkamp 	nbytes = readlink(buf1, buf, bufsize-1);
6732d118adSDaniel Verkamp 	if (nbytes == -1) {
6832d118adSDaniel Verkamp 		printf("readlink(%s) failed %m\n", buf1);
6932d118adSDaniel Verkamp 		abort();
7032d118adSDaniel Verkamp 	}
7132d118adSDaniel Verkamp 	buf[nbytes] = '\0';
7232d118adSDaniel Verkamp 	return nbytes;
7332d118adSDaniel Verkamp }
7432d118adSDaniel Verkamp 
mfd_assert_new(const char * name,loff_t sz,unsigned int flags)754f5ce5e8SDavid Herrmann static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
764f5ce5e8SDavid Herrmann {
774f5ce5e8SDavid Herrmann 	int r, fd;
784f5ce5e8SDavid Herrmann 
794f5ce5e8SDavid Herrmann 	fd = sys_memfd_create(name, flags);
804f5ce5e8SDavid Herrmann 	if (fd < 0) {
814f5ce5e8SDavid Herrmann 		printf("memfd_create(\"%s\", %u) failed: %m\n",
824f5ce5e8SDavid Herrmann 		       name, flags);
834f5ce5e8SDavid Herrmann 		abort();
844f5ce5e8SDavid Herrmann 	}
854f5ce5e8SDavid Herrmann 
864f5ce5e8SDavid Herrmann 	r = ftruncate(fd, sz);
874f5ce5e8SDavid Herrmann 	if (r < 0) {
884f5ce5e8SDavid Herrmann 		printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
894f5ce5e8SDavid Herrmann 		abort();
904f5ce5e8SDavid Herrmann 	}
914f5ce5e8SDavid Herrmann 
924f5ce5e8SDavid Herrmann 	return fd;
934f5ce5e8SDavid Herrmann }
944f5ce5e8SDavid Herrmann 
sysctl_assert_write(const char * val)9511f75a01SJeff Xu static void sysctl_assert_write(const char *val)
9611f75a01SJeff Xu {
9711f75a01SJeff Xu 	int fd = open("/proc/sys/vm/memfd_noexec", O_WRONLY | O_CLOEXEC);
9811f75a01SJeff Xu 
9911f75a01SJeff Xu 	if (fd < 0) {
1006469b66eSAleksa Sarai 		printf("open sysctl failed: %m\n");
10111f75a01SJeff Xu 		abort();
10211f75a01SJeff Xu 	}
10311f75a01SJeff Xu 
10411f75a01SJeff Xu 	if (write(fd, val, strlen(val)) < 0) {
1056469b66eSAleksa Sarai 		printf("write sysctl %s failed: %m\n", val);
10611f75a01SJeff Xu 		abort();
10711f75a01SJeff Xu 	}
10811f75a01SJeff Xu }
10911f75a01SJeff Xu 
sysctl_fail_write(const char * val)11011f75a01SJeff Xu static void sysctl_fail_write(const char *val)
11111f75a01SJeff Xu {
11211f75a01SJeff Xu 	int fd = open("/proc/sys/vm/memfd_noexec", O_WRONLY | O_CLOEXEC);
11311f75a01SJeff Xu 
11411f75a01SJeff Xu 	if (fd < 0) {
1156469b66eSAleksa Sarai 		printf("open sysctl failed: %m\n");
11611f75a01SJeff Xu 		abort();
11711f75a01SJeff Xu 	}
11811f75a01SJeff Xu 
11911f75a01SJeff Xu 	if (write(fd, val, strlen(val)) >= 0) {
12011f75a01SJeff Xu 		printf("write sysctl %s succeeded, but failure expected\n",
12111f75a01SJeff Xu 				val);
12211f75a01SJeff Xu 		abort();
12311f75a01SJeff Xu 	}
12411f75a01SJeff Xu }
12511f75a01SJeff Xu 
sysctl_assert_equal(const char * val)1266469b66eSAleksa Sarai static void sysctl_assert_equal(const char *val)
1276469b66eSAleksa Sarai {
1286469b66eSAleksa Sarai 	char *p, buf[128] = {};
1296469b66eSAleksa Sarai 	int fd = open("/proc/sys/vm/memfd_noexec", O_RDONLY | O_CLOEXEC);
1306469b66eSAleksa Sarai 
1316469b66eSAleksa Sarai 	if (fd < 0) {
1326469b66eSAleksa Sarai 		printf("open sysctl failed: %m\n");
1336469b66eSAleksa Sarai 		abort();
1346469b66eSAleksa Sarai 	}
1356469b66eSAleksa Sarai 
1366469b66eSAleksa Sarai 	if (read(fd, buf, sizeof(buf)) < 0) {
1376469b66eSAleksa Sarai 		printf("read sysctl failed: %m\n");
1386469b66eSAleksa Sarai 		abort();
1396469b66eSAleksa Sarai 	}
1406469b66eSAleksa Sarai 
1416469b66eSAleksa Sarai 	/* Strip trailing whitespace. */
1426469b66eSAleksa Sarai 	p = buf;
1436469b66eSAleksa Sarai 	while (!isspace(*p))
1446469b66eSAleksa Sarai 		p++;
1456469b66eSAleksa Sarai 	*p = '\0';
1466469b66eSAleksa Sarai 
1476469b66eSAleksa Sarai 	if (strcmp(buf, val) != 0) {
1486469b66eSAleksa Sarai 		printf("unexpected sysctl value: expected %s, got %s\n", val, buf);
1496469b66eSAleksa Sarai 		abort();
1506469b66eSAleksa Sarai 	}
1516469b66eSAleksa Sarai }
1526469b66eSAleksa Sarai 
mfd_assert_reopen_fd(int fd_in)15354402986SJoel Fernandes (Google) static int mfd_assert_reopen_fd(int fd_in)
15454402986SJoel Fernandes (Google) {
155d42990f4SGreg Thelen 	int fd;
15654402986SJoel Fernandes (Google) 	char path[100];
15754402986SJoel Fernandes (Google) 
15854402986SJoel Fernandes (Google) 	sprintf(path, "/proc/self/fd/%d", fd_in);
15954402986SJoel Fernandes (Google) 
16054402986SJoel Fernandes (Google) 	fd = open(path, O_RDWR);
16154402986SJoel Fernandes (Google) 	if (fd < 0) {
16254402986SJoel Fernandes (Google) 		printf("re-open of existing fd %d failed\n", fd_in);
16354402986SJoel Fernandes (Google) 		abort();
16454402986SJoel Fernandes (Google) 	}
16554402986SJoel Fernandes (Google) 
16654402986SJoel Fernandes (Google) 	return fd;
16754402986SJoel Fernandes (Google) }
16854402986SJoel Fernandes (Google) 
mfd_fail_new(const char * name,unsigned int flags)1694f5ce5e8SDavid Herrmann static void mfd_fail_new(const char *name, unsigned int flags)
1704f5ce5e8SDavid Herrmann {
1714f5ce5e8SDavid Herrmann 	int r;
1724f5ce5e8SDavid Herrmann 
1734f5ce5e8SDavid Herrmann 	r = sys_memfd_create(name, flags);
1744f5ce5e8SDavid Herrmann 	if (r >= 0) {
1754f5ce5e8SDavid Herrmann 		printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
1764f5ce5e8SDavid Herrmann 		       name, flags);
1774f5ce5e8SDavid Herrmann 		close(r);
1784f5ce5e8SDavid Herrmann 		abort();
1794f5ce5e8SDavid Herrmann 	}
1804f5ce5e8SDavid Herrmann }
1814f5ce5e8SDavid Herrmann 
mfd_assert_get_seals(int fd)18257e67900SPranith Kumar static unsigned int mfd_assert_get_seals(int fd)
1834f5ce5e8SDavid Herrmann {
18457e67900SPranith Kumar 	int r;
1854f5ce5e8SDavid Herrmann 
1864f5ce5e8SDavid Herrmann 	r = fcntl(fd, F_GET_SEALS);
1874f5ce5e8SDavid Herrmann 	if (r < 0) {
1884f5ce5e8SDavid Herrmann 		printf("GET_SEALS(%d) failed: %m\n", fd);
1894f5ce5e8SDavid Herrmann 		abort();
1904f5ce5e8SDavid Herrmann 	}
1914f5ce5e8SDavid Herrmann 
19257e67900SPranith Kumar 	return (unsigned int)r;
1934f5ce5e8SDavid Herrmann }
1944f5ce5e8SDavid Herrmann 
mfd_assert_has_seals(int fd,unsigned int seals)19557e67900SPranith Kumar static void mfd_assert_has_seals(int fd, unsigned int seals)
1964f5ce5e8SDavid Herrmann {
19732d118adSDaniel Verkamp 	char buf[PATH_MAX];
19832d118adSDaniel Verkamp 	int nbytes;
19957e67900SPranith Kumar 	unsigned int s;
20032d118adSDaniel Verkamp 	fd2name(fd, buf, PATH_MAX);
2014f5ce5e8SDavid Herrmann 
2024f5ce5e8SDavid Herrmann 	s = mfd_assert_get_seals(fd);
2034f5ce5e8SDavid Herrmann 	if (s != seals) {
20432d118adSDaniel Verkamp 		printf("%u != %u = GET_SEALS(%s)\n", seals, s, buf);
2054f5ce5e8SDavid Herrmann 		abort();
2064f5ce5e8SDavid Herrmann 	}
2074f5ce5e8SDavid Herrmann }
2084f5ce5e8SDavid Herrmann 
mfd_assert_add_seals(int fd,unsigned int seals)20957e67900SPranith Kumar static void mfd_assert_add_seals(int fd, unsigned int seals)
2104f5ce5e8SDavid Herrmann {
21157e67900SPranith Kumar 	int r;
21257e67900SPranith Kumar 	unsigned int s;
2134f5ce5e8SDavid Herrmann 
2144f5ce5e8SDavid Herrmann 	s = mfd_assert_get_seals(fd);
2154f5ce5e8SDavid Herrmann 	r = fcntl(fd, F_ADD_SEALS, seals);
2164f5ce5e8SDavid Herrmann 	if (r < 0) {
21757e67900SPranith Kumar 		printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
2184f5ce5e8SDavid Herrmann 		abort();
2194f5ce5e8SDavid Herrmann 	}
2204f5ce5e8SDavid Herrmann }
2214f5ce5e8SDavid Herrmann 
mfd_fail_add_seals(int fd,unsigned int seals)22257e67900SPranith Kumar static void mfd_fail_add_seals(int fd, unsigned int seals)
2234f5ce5e8SDavid Herrmann {
22457e67900SPranith Kumar 	int r;
22557e67900SPranith Kumar 	unsigned int s;
2264f5ce5e8SDavid Herrmann 
2274f5ce5e8SDavid Herrmann 	r = fcntl(fd, F_GET_SEALS);
2284f5ce5e8SDavid Herrmann 	if (r < 0)
2294f5ce5e8SDavid Herrmann 		s = 0;
2304f5ce5e8SDavid Herrmann 	else
23157e67900SPranith Kumar 		s = (unsigned int)r;
2324f5ce5e8SDavid Herrmann 
2334f5ce5e8SDavid Herrmann 	r = fcntl(fd, F_ADD_SEALS, seals);
2344f5ce5e8SDavid Herrmann 	if (r >= 0) {
23557e67900SPranith Kumar 		printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
23657e67900SPranith Kumar 				fd, s, seals);
2374f5ce5e8SDavid Herrmann 		abort();
2384f5ce5e8SDavid Herrmann 	}
2394f5ce5e8SDavid Herrmann }
2404f5ce5e8SDavid Herrmann 
mfd_assert_size(int fd,size_t size)2414f5ce5e8SDavid Herrmann static void mfd_assert_size(int fd, size_t size)
2424f5ce5e8SDavid Herrmann {
2434f5ce5e8SDavid Herrmann 	struct stat st;
2444f5ce5e8SDavid Herrmann 	int r;
2454f5ce5e8SDavid Herrmann 
2464f5ce5e8SDavid Herrmann 	r = fstat(fd, &st);
2474f5ce5e8SDavid Herrmann 	if (r < 0) {
2484f5ce5e8SDavid Herrmann 		printf("fstat(%d) failed: %m\n", fd);
2494f5ce5e8SDavid Herrmann 		abort();
2504f5ce5e8SDavid Herrmann 	} else if (st.st_size != size) {
2514f5ce5e8SDavid Herrmann 		printf("wrong file size %lld, but expected %lld\n",
2524f5ce5e8SDavid Herrmann 		       (long long)st.st_size, (long long)size);
2534f5ce5e8SDavid Herrmann 		abort();
2544f5ce5e8SDavid Herrmann 	}
2554f5ce5e8SDavid Herrmann }
2564f5ce5e8SDavid Herrmann 
mfd_assert_dup(int fd)2574f5ce5e8SDavid Herrmann static int mfd_assert_dup(int fd)
2584f5ce5e8SDavid Herrmann {
2594f5ce5e8SDavid Herrmann 	int r;
2604f5ce5e8SDavid Herrmann 
2614f5ce5e8SDavid Herrmann 	r = dup(fd);
2624f5ce5e8SDavid Herrmann 	if (r < 0) {
2634f5ce5e8SDavid Herrmann 		printf("dup(%d) failed: %m\n", fd);
2644f5ce5e8SDavid Herrmann 		abort();
2654f5ce5e8SDavid Herrmann 	}
2664f5ce5e8SDavid Herrmann 
2674f5ce5e8SDavid Herrmann 	return r;
2684f5ce5e8SDavid Herrmann }
2694f5ce5e8SDavid Herrmann 
mfd_assert_mmap_shared(int fd)2704f5ce5e8SDavid Herrmann static void *mfd_assert_mmap_shared(int fd)
2714f5ce5e8SDavid Herrmann {
2724f5ce5e8SDavid Herrmann 	void *p;
2734f5ce5e8SDavid Herrmann 
2744f5ce5e8SDavid Herrmann 	p = mmap(NULL,
2751f522a48SMike Kravetz 		 mfd_def_size,
2764f5ce5e8SDavid Herrmann 		 PROT_READ | PROT_WRITE,
2774f5ce5e8SDavid Herrmann 		 MAP_SHARED,
2784f5ce5e8SDavid Herrmann 		 fd,
2794f5ce5e8SDavid Herrmann 		 0);
2804f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
2814f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
2824f5ce5e8SDavid Herrmann 		abort();
2834f5ce5e8SDavid Herrmann 	}
2844f5ce5e8SDavid Herrmann 
2854f5ce5e8SDavid Herrmann 	return p;
2864f5ce5e8SDavid Herrmann }
2874f5ce5e8SDavid Herrmann 
mfd_assert_mmap_private(int fd)2884f5ce5e8SDavid Herrmann static void *mfd_assert_mmap_private(int fd)
2894f5ce5e8SDavid Herrmann {
2904f5ce5e8SDavid Herrmann 	void *p;
2914f5ce5e8SDavid Herrmann 
2924f5ce5e8SDavid Herrmann 	p = mmap(NULL,
2931f522a48SMike Kravetz 		 mfd_def_size,
2944f5ce5e8SDavid Herrmann 		 PROT_READ,
2954f5ce5e8SDavid Herrmann 		 MAP_PRIVATE,
2964f5ce5e8SDavid Herrmann 		 fd,
2974f5ce5e8SDavid Herrmann 		 0);
2984f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
2994f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
3004f5ce5e8SDavid Herrmann 		abort();
3014f5ce5e8SDavid Herrmann 	}
3024f5ce5e8SDavid Herrmann 
3034f5ce5e8SDavid Herrmann 	return p;
3044f5ce5e8SDavid Herrmann }
3054f5ce5e8SDavid Herrmann 
mfd_assert_open(int fd,int flags,mode_t mode)3064f5ce5e8SDavid Herrmann static int mfd_assert_open(int fd, int flags, mode_t mode)
3074f5ce5e8SDavid Herrmann {
3084f5ce5e8SDavid Herrmann 	char buf[512];
3094f5ce5e8SDavid Herrmann 	int r;
3104f5ce5e8SDavid Herrmann 
3114f5ce5e8SDavid Herrmann 	sprintf(buf, "/proc/self/fd/%d", fd);
3124f5ce5e8SDavid Herrmann 	r = open(buf, flags, mode);
3134f5ce5e8SDavid Herrmann 	if (r < 0) {
3144f5ce5e8SDavid Herrmann 		printf("open(%s) failed: %m\n", buf);
3154f5ce5e8SDavid Herrmann 		abort();
3164f5ce5e8SDavid Herrmann 	}
3174f5ce5e8SDavid Herrmann 
3184f5ce5e8SDavid Herrmann 	return r;
3194f5ce5e8SDavid Herrmann }
3204f5ce5e8SDavid Herrmann 
mfd_fail_open(int fd,int flags,mode_t mode)3214f5ce5e8SDavid Herrmann static void mfd_fail_open(int fd, int flags, mode_t mode)
3224f5ce5e8SDavid Herrmann {
3234f5ce5e8SDavid Herrmann 	char buf[512];
3244f5ce5e8SDavid Herrmann 	int r;
3254f5ce5e8SDavid Herrmann 
3264f5ce5e8SDavid Herrmann 	sprintf(buf, "/proc/self/fd/%d", fd);
3274f5ce5e8SDavid Herrmann 	r = open(buf, flags, mode);
3284f5ce5e8SDavid Herrmann 	if (r >= 0) {
3292ed36928SPranith Kumar 		printf("open(%s) didn't fail as expected\n", buf);
3304f5ce5e8SDavid Herrmann 		abort();
3314f5ce5e8SDavid Herrmann 	}
3324f5ce5e8SDavid Herrmann }
3334f5ce5e8SDavid Herrmann 
mfd_assert_read(int fd)3344f5ce5e8SDavid Herrmann static void mfd_assert_read(int fd)
3354f5ce5e8SDavid Herrmann {
3364f5ce5e8SDavid Herrmann 	char buf[16];
3374f5ce5e8SDavid Herrmann 	void *p;
3384f5ce5e8SDavid Herrmann 	ssize_t l;
3394f5ce5e8SDavid Herrmann 
3404f5ce5e8SDavid Herrmann 	l = read(fd, buf, sizeof(buf));
3414f5ce5e8SDavid Herrmann 	if (l != sizeof(buf)) {
3424f5ce5e8SDavid Herrmann 		printf("read() failed: %m\n");
3434f5ce5e8SDavid Herrmann 		abort();
3444f5ce5e8SDavid Herrmann 	}
3454f5ce5e8SDavid Herrmann 
3464f5ce5e8SDavid Herrmann 	/* verify PROT_READ *is* allowed */
3474f5ce5e8SDavid Herrmann 	p = mmap(NULL,
3481f522a48SMike Kravetz 		 mfd_def_size,
3494f5ce5e8SDavid Herrmann 		 PROT_READ,
3504f5ce5e8SDavid Herrmann 		 MAP_PRIVATE,
3514f5ce5e8SDavid Herrmann 		 fd,
3524f5ce5e8SDavid Herrmann 		 0);
3534f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
3544f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
3554f5ce5e8SDavid Herrmann 		abort();
3564f5ce5e8SDavid Herrmann 	}
3571f522a48SMike Kravetz 	munmap(p, mfd_def_size);
3584f5ce5e8SDavid Herrmann 
3594f5ce5e8SDavid Herrmann 	/* verify MAP_PRIVATE is *always* allowed (even writable) */
3604f5ce5e8SDavid Herrmann 	p = mmap(NULL,
3611f522a48SMike Kravetz 		 mfd_def_size,
3624f5ce5e8SDavid Herrmann 		 PROT_READ | PROT_WRITE,
3634f5ce5e8SDavid Herrmann 		 MAP_PRIVATE,
3644f5ce5e8SDavid Herrmann 		 fd,
3654f5ce5e8SDavid Herrmann 		 0);
3664f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
3674f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
3684f5ce5e8SDavid Herrmann 		abort();
3694f5ce5e8SDavid Herrmann 	}
3701f522a48SMike Kravetz 	munmap(p, mfd_def_size);
3714f5ce5e8SDavid Herrmann }
3724f5ce5e8SDavid Herrmann 
37354402986SJoel Fernandes (Google) /* Test that PROT_READ + MAP_SHARED mappings work. */
mfd_assert_read_shared(int fd)37454402986SJoel Fernandes (Google) static void mfd_assert_read_shared(int fd)
37554402986SJoel Fernandes (Google) {
37654402986SJoel Fernandes (Google) 	void *p;
37754402986SJoel Fernandes (Google) 
37854402986SJoel Fernandes (Google) 	/* verify PROT_READ and MAP_SHARED *is* allowed */
37954402986SJoel Fernandes (Google) 	p = mmap(NULL,
38054402986SJoel Fernandes (Google) 		 mfd_def_size,
38154402986SJoel Fernandes (Google) 		 PROT_READ,
38254402986SJoel Fernandes (Google) 		 MAP_SHARED,
38354402986SJoel Fernandes (Google) 		 fd,
38454402986SJoel Fernandes (Google) 		 0);
38554402986SJoel Fernandes (Google) 	if (p == MAP_FAILED) {
38654402986SJoel Fernandes (Google) 		printf("mmap() failed: %m\n");
38754402986SJoel Fernandes (Google) 		abort();
38854402986SJoel Fernandes (Google) 	}
38954402986SJoel Fernandes (Google) 	munmap(p, mfd_def_size);
39054402986SJoel Fernandes (Google) }
39154402986SJoel Fernandes (Google) 
mfd_assert_fork_private_write(int fd)3922e53c4e1SJoel Fernandes (Google) static void mfd_assert_fork_private_write(int fd)
3932e53c4e1SJoel Fernandes (Google) {
3942e53c4e1SJoel Fernandes (Google) 	int *p;
3952e53c4e1SJoel Fernandes (Google) 	pid_t pid;
3962e53c4e1SJoel Fernandes (Google) 
3972e53c4e1SJoel Fernandes (Google) 	p = mmap(NULL,
3982e53c4e1SJoel Fernandes (Google) 		 mfd_def_size,
3992e53c4e1SJoel Fernandes (Google) 		 PROT_READ | PROT_WRITE,
4002e53c4e1SJoel Fernandes (Google) 		 MAP_PRIVATE,
4012e53c4e1SJoel Fernandes (Google) 		 fd,
4022e53c4e1SJoel Fernandes (Google) 		 0);
4032e53c4e1SJoel Fernandes (Google) 	if (p == MAP_FAILED) {
4042e53c4e1SJoel Fernandes (Google) 		printf("mmap() failed: %m\n");
4052e53c4e1SJoel Fernandes (Google) 		abort();
4062e53c4e1SJoel Fernandes (Google) 	}
4072e53c4e1SJoel Fernandes (Google) 
4082e53c4e1SJoel Fernandes (Google) 	p[0] = 22;
4092e53c4e1SJoel Fernandes (Google) 
4102e53c4e1SJoel Fernandes (Google) 	pid = fork();
4112e53c4e1SJoel Fernandes (Google) 	if (pid == 0) {
4122e53c4e1SJoel Fernandes (Google) 		p[0] = 33;
4132e53c4e1SJoel Fernandes (Google) 		exit(0);
4142e53c4e1SJoel Fernandes (Google) 	} else {
4152e53c4e1SJoel Fernandes (Google) 		waitpid(pid, NULL, 0);
4162e53c4e1SJoel Fernandes (Google) 
4172e53c4e1SJoel Fernandes (Google) 		if (p[0] != 22) {
4182e53c4e1SJoel Fernandes (Google) 			printf("MAP_PRIVATE copy-on-write failed: %m\n");
4192e53c4e1SJoel Fernandes (Google) 			abort();
4202e53c4e1SJoel Fernandes (Google) 		}
4212e53c4e1SJoel Fernandes (Google) 	}
4222e53c4e1SJoel Fernandes (Google) 
4232e53c4e1SJoel Fernandes (Google) 	munmap(p, mfd_def_size);
4242e53c4e1SJoel Fernandes (Google) }
4252e53c4e1SJoel Fernandes (Google) 
mfd_assert_write(int fd)4264f5ce5e8SDavid Herrmann static void mfd_assert_write(int fd)
4274f5ce5e8SDavid Herrmann {
4284f5ce5e8SDavid Herrmann 	ssize_t l;
4294f5ce5e8SDavid Herrmann 	void *p;
4304f5ce5e8SDavid Herrmann 	int r;
4314f5ce5e8SDavid Herrmann 
4321f522a48SMike Kravetz 	/*
4331f522a48SMike Kravetz 	 * huegtlbfs does not support write, but we want to
4341f522a48SMike Kravetz 	 * verify everything else here.
4351f522a48SMike Kravetz 	 */
4361f522a48SMike Kravetz 	if (!hugetlbfs_test) {
4374f5ce5e8SDavid Herrmann 		/* verify write() succeeds */
4384f5ce5e8SDavid Herrmann 		l = write(fd, "\0\0\0\0", 4);
4394f5ce5e8SDavid Herrmann 		if (l != 4) {
4404f5ce5e8SDavid Herrmann 			printf("write() failed: %m\n");
4414f5ce5e8SDavid Herrmann 			abort();
4424f5ce5e8SDavid Herrmann 		}
4431f522a48SMike Kravetz 	}
4444f5ce5e8SDavid Herrmann 
4454f5ce5e8SDavid Herrmann 	/* verify PROT_READ | PROT_WRITE is allowed */
4464f5ce5e8SDavid Herrmann 	p = mmap(NULL,
4471f522a48SMike Kravetz 		 mfd_def_size,
4484f5ce5e8SDavid Herrmann 		 PROT_READ | PROT_WRITE,
4494f5ce5e8SDavid Herrmann 		 MAP_SHARED,
4504f5ce5e8SDavid Herrmann 		 fd,
4514f5ce5e8SDavid Herrmann 		 0);
4524f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
4534f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
4544f5ce5e8SDavid Herrmann 		abort();
4554f5ce5e8SDavid Herrmann 	}
4564f5ce5e8SDavid Herrmann 	*(char *)p = 0;
4571f522a48SMike Kravetz 	munmap(p, mfd_def_size);
4584f5ce5e8SDavid Herrmann 
4594f5ce5e8SDavid Herrmann 	/* verify PROT_WRITE is allowed */
4604f5ce5e8SDavid Herrmann 	p = mmap(NULL,
4611f522a48SMike Kravetz 		 mfd_def_size,
4624f5ce5e8SDavid Herrmann 		 PROT_WRITE,
4634f5ce5e8SDavid Herrmann 		 MAP_SHARED,
4644f5ce5e8SDavid Herrmann 		 fd,
4654f5ce5e8SDavid Herrmann 		 0);
4664f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
4674f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
4684f5ce5e8SDavid Herrmann 		abort();
4694f5ce5e8SDavid Herrmann 	}
4704f5ce5e8SDavid Herrmann 	*(char *)p = 0;
4711f522a48SMike Kravetz 	munmap(p, mfd_def_size);
4724f5ce5e8SDavid Herrmann 
4734f5ce5e8SDavid Herrmann 	/* verify PROT_READ with MAP_SHARED is allowed and a following
4744f5ce5e8SDavid Herrmann 	 * mprotect(PROT_WRITE) allows writing */
4754f5ce5e8SDavid Herrmann 	p = mmap(NULL,
4761f522a48SMike Kravetz 		 mfd_def_size,
4774f5ce5e8SDavid Herrmann 		 PROT_READ,
4784f5ce5e8SDavid Herrmann 		 MAP_SHARED,
4794f5ce5e8SDavid Herrmann 		 fd,
4804f5ce5e8SDavid Herrmann 		 0);
4814f5ce5e8SDavid Herrmann 	if (p == MAP_FAILED) {
4824f5ce5e8SDavid Herrmann 		printf("mmap() failed: %m\n");
4834f5ce5e8SDavid Herrmann 		abort();
4844f5ce5e8SDavid Herrmann 	}
4854f5ce5e8SDavid Herrmann 
4861f522a48SMike Kravetz 	r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
4874f5ce5e8SDavid Herrmann 	if (r < 0) {
4884f5ce5e8SDavid Herrmann 		printf("mprotect() failed: %m\n");
4894f5ce5e8SDavid Herrmann 		abort();
4904f5ce5e8SDavid Herrmann 	}
4914f5ce5e8SDavid Herrmann 
4924f5ce5e8SDavid Herrmann 	*(char *)p = 0;
4931f522a48SMike Kravetz 	munmap(p, mfd_def_size);
4944f5ce5e8SDavid Herrmann 
4954f5ce5e8SDavid Herrmann 	/* verify PUNCH_HOLE works */
4964f5ce5e8SDavid Herrmann 	r = fallocate(fd,
4974f5ce5e8SDavid Herrmann 		      FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
4984f5ce5e8SDavid Herrmann 		      0,
4991f522a48SMike Kravetz 		      mfd_def_size);
5004f5ce5e8SDavid Herrmann 	if (r < 0) {
5014f5ce5e8SDavid Herrmann 		printf("fallocate(PUNCH_HOLE) failed: %m\n");
5024f5ce5e8SDavid Herrmann 		abort();
5034f5ce5e8SDavid Herrmann 	}
5044f5ce5e8SDavid Herrmann }
5054f5ce5e8SDavid Herrmann 
mfd_fail_write(int fd)5064f5ce5e8SDavid Herrmann static void mfd_fail_write(int fd)
5074f5ce5e8SDavid Herrmann {
5084f5ce5e8SDavid Herrmann 	ssize_t l;
5094f5ce5e8SDavid Herrmann 	void *p;
5104f5ce5e8SDavid Herrmann 	int r;
5114f5ce5e8SDavid Herrmann 
5124f5ce5e8SDavid Herrmann 	/* verify write() fails */
5134f5ce5e8SDavid Herrmann 	l = write(fd, "data", 4);
5144f5ce5e8SDavid Herrmann 	if (l != -EPERM) {
5154f5ce5e8SDavid Herrmann 		printf("expected EPERM on write(), but got %d: %m\n", (int)l);
5164f5ce5e8SDavid Herrmann 		abort();
5174f5ce5e8SDavid Herrmann 	}
5184f5ce5e8SDavid Herrmann 
5194f5ce5e8SDavid Herrmann 	/* verify PROT_READ | PROT_WRITE is not allowed */
5204f5ce5e8SDavid Herrmann 	p = mmap(NULL,
5211f522a48SMike Kravetz 		 mfd_def_size,
5224f5ce5e8SDavid Herrmann 		 PROT_READ | PROT_WRITE,
5234f5ce5e8SDavid Herrmann 		 MAP_SHARED,
5244f5ce5e8SDavid Herrmann 		 fd,
5254f5ce5e8SDavid Herrmann 		 0);
5264f5ce5e8SDavid Herrmann 	if (p != MAP_FAILED) {
5274f5ce5e8SDavid Herrmann 		printf("mmap() didn't fail as expected\n");
5284f5ce5e8SDavid Herrmann 		abort();
5294f5ce5e8SDavid Herrmann 	}
5304f5ce5e8SDavid Herrmann 
5314f5ce5e8SDavid Herrmann 	/* verify PROT_WRITE is not allowed */
5324f5ce5e8SDavid Herrmann 	p = mmap(NULL,
5331f522a48SMike Kravetz 		 mfd_def_size,
5344f5ce5e8SDavid Herrmann 		 PROT_WRITE,
5354f5ce5e8SDavid Herrmann 		 MAP_SHARED,
5364f5ce5e8SDavid Herrmann 		 fd,
5374f5ce5e8SDavid Herrmann 		 0);
5384f5ce5e8SDavid Herrmann 	if (p != MAP_FAILED) {
5394f5ce5e8SDavid Herrmann 		printf("mmap() didn't fail as expected\n");
5404f5ce5e8SDavid Herrmann 		abort();
5414f5ce5e8SDavid Herrmann 	}
5424f5ce5e8SDavid Herrmann 
5434f5ce5e8SDavid Herrmann 	/* Verify PROT_READ with MAP_SHARED with a following mprotect is not
5444f5ce5e8SDavid Herrmann 	 * allowed. Note that for r/w the kernel already prevents the mmap. */
5454f5ce5e8SDavid Herrmann 	p = mmap(NULL,
5461f522a48SMike Kravetz 		 mfd_def_size,
5474f5ce5e8SDavid Herrmann 		 PROT_READ,
5484f5ce5e8SDavid Herrmann 		 MAP_SHARED,
5494f5ce5e8SDavid Herrmann 		 fd,
5504f5ce5e8SDavid Herrmann 		 0);
5514f5ce5e8SDavid Herrmann 	if (p != MAP_FAILED) {
5521f522a48SMike Kravetz 		r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
5534f5ce5e8SDavid Herrmann 		if (r >= 0) {
5544f5ce5e8SDavid Herrmann 			printf("mmap()+mprotect() didn't fail as expected\n");
5554f5ce5e8SDavid Herrmann 			abort();
5564f5ce5e8SDavid Herrmann 		}
557fda153c8SMike Kravetz 		munmap(p, mfd_def_size);
5584f5ce5e8SDavid Herrmann 	}
5594f5ce5e8SDavid Herrmann 
5604f5ce5e8SDavid Herrmann 	/* verify PUNCH_HOLE fails */
5614f5ce5e8SDavid Herrmann 	r = fallocate(fd,
5624f5ce5e8SDavid Herrmann 		      FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
5634f5ce5e8SDavid Herrmann 		      0,
5641f522a48SMike Kravetz 		      mfd_def_size);
5654f5ce5e8SDavid Herrmann 	if (r >= 0) {
5664f5ce5e8SDavid Herrmann 		printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
5674f5ce5e8SDavid Herrmann 		abort();
5684f5ce5e8SDavid Herrmann 	}
5694f5ce5e8SDavid Herrmann }
5704f5ce5e8SDavid Herrmann 
mfd_assert_shrink(int fd)5714f5ce5e8SDavid Herrmann static void mfd_assert_shrink(int fd)
5724f5ce5e8SDavid Herrmann {
5734f5ce5e8SDavid Herrmann 	int r, fd2;
5744f5ce5e8SDavid Herrmann 
5751f522a48SMike Kravetz 	r = ftruncate(fd, mfd_def_size / 2);
5764f5ce5e8SDavid Herrmann 	if (r < 0) {
5774f5ce5e8SDavid Herrmann 		printf("ftruncate(SHRINK) failed: %m\n");
5784f5ce5e8SDavid Herrmann 		abort();
5794f5ce5e8SDavid Herrmann 	}
5804f5ce5e8SDavid Herrmann 
5811f522a48SMike Kravetz 	mfd_assert_size(fd, mfd_def_size / 2);
5824f5ce5e8SDavid Herrmann 
5834f5ce5e8SDavid Herrmann 	fd2 = mfd_assert_open(fd,
5844f5ce5e8SDavid Herrmann 			      O_RDWR | O_CREAT | O_TRUNC,
5854f5ce5e8SDavid Herrmann 			      S_IRUSR | S_IWUSR);
5864f5ce5e8SDavid Herrmann 	close(fd2);
5874f5ce5e8SDavid Herrmann 
5884f5ce5e8SDavid Herrmann 	mfd_assert_size(fd, 0);
5894f5ce5e8SDavid Herrmann }
5904f5ce5e8SDavid Herrmann 
mfd_fail_shrink(int fd)5914f5ce5e8SDavid Herrmann static void mfd_fail_shrink(int fd)
5924f5ce5e8SDavid Herrmann {
5934f5ce5e8SDavid Herrmann 	int r;
5944f5ce5e8SDavid Herrmann 
5951f522a48SMike Kravetz 	r = ftruncate(fd, mfd_def_size / 2);
5964f5ce5e8SDavid Herrmann 	if (r >= 0) {
5974f5ce5e8SDavid Herrmann 		printf("ftruncate(SHRINK) didn't fail as expected\n");
5984f5ce5e8SDavid Herrmann 		abort();
5994f5ce5e8SDavid Herrmann 	}
6004f5ce5e8SDavid Herrmann 
6014f5ce5e8SDavid Herrmann 	mfd_fail_open(fd,
6024f5ce5e8SDavid Herrmann 		      O_RDWR | O_CREAT | O_TRUNC,
6034f5ce5e8SDavid Herrmann 		      S_IRUSR | S_IWUSR);
6044f5ce5e8SDavid Herrmann }
6054f5ce5e8SDavid Herrmann 
mfd_assert_grow(int fd)6064f5ce5e8SDavid Herrmann static void mfd_assert_grow(int fd)
6074f5ce5e8SDavid Herrmann {
6084f5ce5e8SDavid Herrmann 	int r;
6094f5ce5e8SDavid Herrmann 
6101f522a48SMike Kravetz 	r = ftruncate(fd, mfd_def_size * 2);
6114f5ce5e8SDavid Herrmann 	if (r < 0) {
6124f5ce5e8SDavid Herrmann 		printf("ftruncate(GROW) failed: %m\n");
6134f5ce5e8SDavid Herrmann 		abort();
6144f5ce5e8SDavid Herrmann 	}
6154f5ce5e8SDavid Herrmann 
6161f522a48SMike Kravetz 	mfd_assert_size(fd, mfd_def_size * 2);
6174f5ce5e8SDavid Herrmann 
6184f5ce5e8SDavid Herrmann 	r = fallocate(fd,
6194f5ce5e8SDavid Herrmann 		      0,
6204f5ce5e8SDavid Herrmann 		      0,
6211f522a48SMike Kravetz 		      mfd_def_size * 4);
6224f5ce5e8SDavid Herrmann 	if (r < 0) {
6234f5ce5e8SDavid Herrmann 		printf("fallocate(ALLOC) failed: %m\n");
6244f5ce5e8SDavid Herrmann 		abort();
6254f5ce5e8SDavid Herrmann 	}
6264f5ce5e8SDavid Herrmann 
6271f522a48SMike Kravetz 	mfd_assert_size(fd, mfd_def_size * 4);
6284f5ce5e8SDavid Herrmann }
6294f5ce5e8SDavid Herrmann 
mfd_fail_grow(int fd)6304f5ce5e8SDavid Herrmann static void mfd_fail_grow(int fd)
6314f5ce5e8SDavid Herrmann {
6324f5ce5e8SDavid Herrmann 	int r;
6334f5ce5e8SDavid Herrmann 
6341f522a48SMike Kravetz 	r = ftruncate(fd, mfd_def_size * 2);
6354f5ce5e8SDavid Herrmann 	if (r >= 0) {
6364f5ce5e8SDavid Herrmann 		printf("ftruncate(GROW) didn't fail as expected\n");
6374f5ce5e8SDavid Herrmann 		abort();
6384f5ce5e8SDavid Herrmann 	}
6394f5ce5e8SDavid Herrmann 
6404f5ce5e8SDavid Herrmann 	r = fallocate(fd,
6414f5ce5e8SDavid Herrmann 		      0,
6424f5ce5e8SDavid Herrmann 		      0,
6431f522a48SMike Kravetz 		      mfd_def_size * 4);
6444f5ce5e8SDavid Herrmann 	if (r >= 0) {
6454f5ce5e8SDavid Herrmann 		printf("fallocate(ALLOC) didn't fail as expected\n");
6464f5ce5e8SDavid Herrmann 		abort();
6474f5ce5e8SDavid Herrmann 	}
6484f5ce5e8SDavid Herrmann }
6494f5ce5e8SDavid Herrmann 
mfd_assert_grow_write(int fd)6504f5ce5e8SDavid Herrmann static void mfd_assert_grow_write(int fd)
6514f5ce5e8SDavid Herrmann {
6521f522a48SMike Kravetz 	static char *buf;
6534f5ce5e8SDavid Herrmann 	ssize_t l;
6544f5ce5e8SDavid Herrmann 
65572497845SMarc-André Lureau 	/* hugetlbfs does not support write */
65672497845SMarc-André Lureau 	if (hugetlbfs_test)
65772497845SMarc-André Lureau 		return;
65872497845SMarc-André Lureau 
6591f522a48SMike Kravetz 	buf = malloc(mfd_def_size * 8);
6601f522a48SMike Kravetz 	if (!buf) {
6617d33d2b5SLei Yang 		printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
6621f522a48SMike Kravetz 		abort();
6631f522a48SMike Kravetz 	}
6641f522a48SMike Kravetz 
6651f522a48SMike Kravetz 	l = pwrite(fd, buf, mfd_def_size * 8, 0);
6661f522a48SMike Kravetz 	if (l != (mfd_def_size * 8)) {
6674f5ce5e8SDavid Herrmann 		printf("pwrite() failed: %m\n");
6684f5ce5e8SDavid Herrmann 		abort();
6694f5ce5e8SDavid Herrmann 	}
6704f5ce5e8SDavid Herrmann 
6711f522a48SMike Kravetz 	mfd_assert_size(fd, mfd_def_size * 8);
6724f5ce5e8SDavid Herrmann }
6734f5ce5e8SDavid Herrmann 
mfd_fail_grow_write(int fd)6744f5ce5e8SDavid Herrmann static void mfd_fail_grow_write(int fd)
6754f5ce5e8SDavid Herrmann {
6761f522a48SMike Kravetz 	static char *buf;
6774f5ce5e8SDavid Herrmann 	ssize_t l;
6784f5ce5e8SDavid Herrmann 
67972497845SMarc-André Lureau 	/* hugetlbfs does not support write */
68072497845SMarc-André Lureau 	if (hugetlbfs_test)
68172497845SMarc-André Lureau 		return;
68272497845SMarc-André Lureau 
6831f522a48SMike Kravetz 	buf = malloc(mfd_def_size * 8);
6841f522a48SMike Kravetz 	if (!buf) {
6857d33d2b5SLei Yang 		printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
6861f522a48SMike Kravetz 		abort();
6871f522a48SMike Kravetz 	}
6881f522a48SMike Kravetz 
6891f522a48SMike Kravetz 	l = pwrite(fd, buf, mfd_def_size * 8, 0);
6901f522a48SMike Kravetz 	if (l == (mfd_def_size * 8)) {
6914f5ce5e8SDavid Herrmann 		printf("pwrite() didn't fail as expected\n");
6924f5ce5e8SDavid Herrmann 		abort();
6934f5ce5e8SDavid Herrmann 	}
6944f5ce5e8SDavid Herrmann }
6954f5ce5e8SDavid Herrmann 
mfd_assert_mode(int fd,int mode)69632d118adSDaniel Verkamp static void mfd_assert_mode(int fd, int mode)
69732d118adSDaniel Verkamp {
69832d118adSDaniel Verkamp 	struct stat st;
69932d118adSDaniel Verkamp 	char buf[PATH_MAX];
70032d118adSDaniel Verkamp 	int nbytes;
70132d118adSDaniel Verkamp 
70232d118adSDaniel Verkamp 	fd2name(fd, buf, PATH_MAX);
70332d118adSDaniel Verkamp 
70432d118adSDaniel Verkamp 	if (fstat(fd, &st) < 0) {
70532d118adSDaniel Verkamp 		printf("fstat(%s) failed: %m\n", buf);
70632d118adSDaniel Verkamp 		abort();
70732d118adSDaniel Verkamp 	}
70832d118adSDaniel Verkamp 
70932d118adSDaniel Verkamp 	if ((st.st_mode & 07777) != mode) {
71032d118adSDaniel Verkamp 		printf("fstat(%s) wrong file mode 0%04o, but expected 0%04o\n",
71132d118adSDaniel Verkamp 		       buf, (int)st.st_mode & 07777, mode);
71232d118adSDaniel Verkamp 		abort();
71332d118adSDaniel Verkamp 	}
71432d118adSDaniel Verkamp }
71532d118adSDaniel Verkamp 
mfd_assert_chmod(int fd,int mode)71632d118adSDaniel Verkamp static void mfd_assert_chmod(int fd, int mode)
71732d118adSDaniel Verkamp {
71832d118adSDaniel Verkamp 	char buf[PATH_MAX];
71932d118adSDaniel Verkamp 	int nbytes;
72032d118adSDaniel Verkamp 
72132d118adSDaniel Verkamp 	fd2name(fd, buf, PATH_MAX);
72232d118adSDaniel Verkamp 
72332d118adSDaniel Verkamp 	if (fchmod(fd, mode) < 0) {
72432d118adSDaniel Verkamp 		printf("fchmod(%s, 0%04o) failed: %m\n", buf, mode);
72532d118adSDaniel Verkamp 		abort();
72632d118adSDaniel Verkamp 	}
72732d118adSDaniel Verkamp 
72832d118adSDaniel Verkamp 	mfd_assert_mode(fd, mode);
72932d118adSDaniel Verkamp }
73032d118adSDaniel Verkamp 
mfd_fail_chmod(int fd,int mode)73132d118adSDaniel Verkamp static void mfd_fail_chmod(int fd, int mode)
73232d118adSDaniel Verkamp {
73332d118adSDaniel Verkamp 	struct stat st;
73432d118adSDaniel Verkamp 	char buf[PATH_MAX];
73532d118adSDaniel Verkamp 	int nbytes;
73632d118adSDaniel Verkamp 
73732d118adSDaniel Verkamp 	fd2name(fd, buf, PATH_MAX);
73832d118adSDaniel Verkamp 
73932d118adSDaniel Verkamp 	if (fstat(fd, &st) < 0) {
74032d118adSDaniel Verkamp 		printf("fstat(%s) failed: %m\n", buf);
74132d118adSDaniel Verkamp 		abort();
74232d118adSDaniel Verkamp 	}
74332d118adSDaniel Verkamp 
74432d118adSDaniel Verkamp 	if (fchmod(fd, mode) == 0) {
74532d118adSDaniel Verkamp 		printf("fchmod(%s, 0%04o) didn't fail as expected\n",
74632d118adSDaniel Verkamp 		       buf, mode);
74732d118adSDaniel Verkamp 		abort();
74832d118adSDaniel Verkamp 	}
74932d118adSDaniel Verkamp 
75032d118adSDaniel Verkamp 	/* verify that file mode bits did not change */
75132d118adSDaniel Verkamp 	mfd_assert_mode(fd, st.st_mode & 07777);
75232d118adSDaniel Verkamp }
75332d118adSDaniel Verkamp 
idle_thread_fn(void * arg)7544f5ce5e8SDavid Herrmann static int idle_thread_fn(void *arg)
7554f5ce5e8SDavid Herrmann {
7564f5ce5e8SDavid Herrmann 	sigset_t set;
7574f5ce5e8SDavid Herrmann 	int sig;
7584f5ce5e8SDavid Herrmann 
7594f5ce5e8SDavid Herrmann 	/* dummy waiter; SIGTERM terminates us anyway */
7604f5ce5e8SDavid Herrmann 	sigemptyset(&set);
7614f5ce5e8SDavid Herrmann 	sigaddset(&set, SIGTERM);
7624f5ce5e8SDavid Herrmann 	sigwait(&set, &sig);
7634f5ce5e8SDavid Herrmann 
7644f5ce5e8SDavid Herrmann 	return 0;
7654f5ce5e8SDavid Herrmann }
7664f5ce5e8SDavid Herrmann 
spawn_thread(unsigned int flags,int (* fn)(void *),void * arg)7676469b66eSAleksa Sarai static pid_t spawn_thread(unsigned int flags, int (*fn)(void *), void *arg)
7684f5ce5e8SDavid Herrmann {
7694f5ce5e8SDavid Herrmann 	uint8_t *stack;
7704f5ce5e8SDavid Herrmann 	pid_t pid;
7714f5ce5e8SDavid Herrmann 
7724f5ce5e8SDavid Herrmann 	stack = malloc(STACK_SIZE);
7734f5ce5e8SDavid Herrmann 	if (!stack) {
7744f5ce5e8SDavid Herrmann 		printf("malloc(STACK_SIZE) failed: %m\n");
7754f5ce5e8SDavid Herrmann 		abort();
7764f5ce5e8SDavid Herrmann 	}
7774f5ce5e8SDavid Herrmann 
7786469b66eSAleksa Sarai 	pid = clone(fn, stack + STACK_SIZE, SIGCHLD | flags, arg);
7794f5ce5e8SDavid Herrmann 	if (pid < 0) {
7804f5ce5e8SDavid Herrmann 		printf("clone() failed: %m\n");
7814f5ce5e8SDavid Herrmann 		abort();
7824f5ce5e8SDavid Herrmann 	}
7834f5ce5e8SDavid Herrmann 
7844f5ce5e8SDavid Herrmann 	return pid;
7854f5ce5e8SDavid Herrmann }
7864f5ce5e8SDavid Herrmann 
join_thread(pid_t pid)7876469b66eSAleksa Sarai static void join_thread(pid_t pid)
7886469b66eSAleksa Sarai {
7896469b66eSAleksa Sarai 	int wstatus;
7906469b66eSAleksa Sarai 
7916469b66eSAleksa Sarai 	if (waitpid(pid, &wstatus, 0) < 0) {
7926469b66eSAleksa Sarai 		printf("newpid thread: waitpid() failed: %m\n");
7936469b66eSAleksa Sarai 		abort();
7946469b66eSAleksa Sarai 	}
7956469b66eSAleksa Sarai 
7966469b66eSAleksa Sarai 	if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0) {
7976469b66eSAleksa Sarai 		printf("newpid thread: exited with non-zero error code %d\n",
7986469b66eSAleksa Sarai 		       WEXITSTATUS(wstatus));
7996469b66eSAleksa Sarai 		abort();
8006469b66eSAleksa Sarai 	}
8016469b66eSAleksa Sarai 
8026469b66eSAleksa Sarai 	if (WIFSIGNALED(wstatus)) {
8036469b66eSAleksa Sarai 		printf("newpid thread: killed by signal %d\n",
8046469b66eSAleksa Sarai 		       WTERMSIG(wstatus));
8056469b66eSAleksa Sarai 		abort();
8066469b66eSAleksa Sarai 	}
8076469b66eSAleksa Sarai }
8086469b66eSAleksa Sarai 
spawn_idle_thread(unsigned int flags)8096469b66eSAleksa Sarai static pid_t spawn_idle_thread(unsigned int flags)
8106469b66eSAleksa Sarai {
8116469b66eSAleksa Sarai 	return spawn_thread(flags, idle_thread_fn, NULL);
8126469b66eSAleksa Sarai }
8136469b66eSAleksa Sarai 
join_idle_thread(pid_t pid)8144f5ce5e8SDavid Herrmann static void join_idle_thread(pid_t pid)
8154f5ce5e8SDavid Herrmann {
8164f5ce5e8SDavid Herrmann 	kill(pid, SIGTERM);
8174f5ce5e8SDavid Herrmann 	waitpid(pid, NULL, 0);
8184f5ce5e8SDavid Herrmann }
8194f5ce5e8SDavid Herrmann 
8204f5ce5e8SDavid Herrmann /*
8214f5ce5e8SDavid Herrmann  * Test memfd_create() syscall
8224f5ce5e8SDavid Herrmann  * Verify syscall-argument validation, including name checks, flag validation
8234f5ce5e8SDavid Herrmann  * and more.
8244f5ce5e8SDavid Herrmann  */
test_create(void)8254f5ce5e8SDavid Herrmann static void test_create(void)
8264f5ce5e8SDavid Herrmann {
8274f5ce5e8SDavid Herrmann 	char buf[2048];
8284f5ce5e8SDavid Herrmann 	int fd;
8294f5ce5e8SDavid Herrmann 
8303037aeb9SMarc-André Lureau 	printf("%s CREATE\n", memfd_str);
8311f522a48SMike Kravetz 
8324f5ce5e8SDavid Herrmann 	/* test NULL name */
8334f5ce5e8SDavid Herrmann 	mfd_fail_new(NULL, 0);
8344f5ce5e8SDavid Herrmann 
8354f5ce5e8SDavid Herrmann 	/* test over-long name (not zero-terminated) */
8364f5ce5e8SDavid Herrmann 	memset(buf, 0xff, sizeof(buf));
8374f5ce5e8SDavid Herrmann 	mfd_fail_new(buf, 0);
8384f5ce5e8SDavid Herrmann 
8394f5ce5e8SDavid Herrmann 	/* test over-long zero-terminated name */
8404f5ce5e8SDavid Herrmann 	memset(buf, 0xff, sizeof(buf));
8414f5ce5e8SDavid Herrmann 	buf[sizeof(buf) - 1] = 0;
8424f5ce5e8SDavid Herrmann 	mfd_fail_new(buf, 0);
8434f5ce5e8SDavid Herrmann 
8444f5ce5e8SDavid Herrmann 	/* verify "" is a valid name */
8454f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("", 0, 0);
8464f5ce5e8SDavid Herrmann 	close(fd);
8474f5ce5e8SDavid Herrmann 
8484f5ce5e8SDavid Herrmann 	/* verify invalid O_* open flags */
8494f5ce5e8SDavid Herrmann 	mfd_fail_new("", 0x0100);
8504f5ce5e8SDavid Herrmann 	mfd_fail_new("", ~MFD_CLOEXEC);
8514f5ce5e8SDavid Herrmann 	mfd_fail_new("", ~MFD_ALLOW_SEALING);
8524f5ce5e8SDavid Herrmann 	mfd_fail_new("", ~0);
8534f5ce5e8SDavid Herrmann 	mfd_fail_new("", 0x80000000U);
8544f5ce5e8SDavid Herrmann 
85511f75a01SJeff Xu 	/* verify EXEC and NOEXEC_SEAL can't both be set */
85611f75a01SJeff Xu 	mfd_fail_new("", MFD_EXEC | MFD_NOEXEC_SEAL);
85711f75a01SJeff Xu 
8584f5ce5e8SDavid Herrmann 	/* verify MFD_CLOEXEC is allowed */
8594f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("", 0, MFD_CLOEXEC);
8604f5ce5e8SDavid Herrmann 	close(fd);
8614f5ce5e8SDavid Herrmann 
8624f5ce5e8SDavid Herrmann 	/* verify MFD_ALLOW_SEALING is allowed */
8634f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
8644f5ce5e8SDavid Herrmann 	close(fd);
8654f5ce5e8SDavid Herrmann 
8664f5ce5e8SDavid Herrmann 	/* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
8674f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
8684f5ce5e8SDavid Herrmann 	close(fd);
8694f5ce5e8SDavid Herrmann }
8704f5ce5e8SDavid Herrmann 
8714f5ce5e8SDavid Herrmann /*
8724f5ce5e8SDavid Herrmann  * Test basic sealing
8734f5ce5e8SDavid Herrmann  * A very basic sealing test to see whether setting/retrieving seals works.
8744f5ce5e8SDavid Herrmann  */
test_basic(void)8754f5ce5e8SDavid Herrmann static void test_basic(void)
8764f5ce5e8SDavid Herrmann {
8774f5ce5e8SDavid Herrmann 	int fd;
8784f5ce5e8SDavid Herrmann 
8793037aeb9SMarc-André Lureau 	printf("%s BASIC\n", memfd_str);
8801f522a48SMike Kravetz 
8814f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_basic",
8821f522a48SMike Kravetz 			    mfd_def_size,
8834f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
8844f5ce5e8SDavid Herrmann 
8854f5ce5e8SDavid Herrmann 	/* add basic seals */
8864f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
8874f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SHRINK |
8884f5ce5e8SDavid Herrmann 				 F_SEAL_WRITE);
8894f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SHRINK |
8904f5ce5e8SDavid Herrmann 				 F_SEAL_WRITE);
8914f5ce5e8SDavid Herrmann 
8924f5ce5e8SDavid Herrmann 	/* add them again */
8934f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SHRINK |
8944f5ce5e8SDavid Herrmann 				 F_SEAL_WRITE);
8954f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SHRINK |
8964f5ce5e8SDavid Herrmann 				 F_SEAL_WRITE);
8974f5ce5e8SDavid Herrmann 
8984f5ce5e8SDavid Herrmann 	/* add more seals and seal against sealing */
8994f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
9004f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SHRINK |
9014f5ce5e8SDavid Herrmann 				 F_SEAL_GROW |
9024f5ce5e8SDavid Herrmann 				 F_SEAL_WRITE |
9034f5ce5e8SDavid Herrmann 				 F_SEAL_SEAL);
9044f5ce5e8SDavid Herrmann 
9054f5ce5e8SDavid Herrmann 	/* verify that sealing no longer works */
9064f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_GROW);
9074f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, 0);
9084f5ce5e8SDavid Herrmann 
9094f5ce5e8SDavid Herrmann 	close(fd);
9104f5ce5e8SDavid Herrmann 
9114f5ce5e8SDavid Herrmann 	/* verify sealing does not work without MFD_ALLOW_SEALING */
9124f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_basic",
9131f522a48SMike Kravetz 			    mfd_def_size,
9144f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC);
9154f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SEAL);
9164f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_SHRINK |
9174f5ce5e8SDavid Herrmann 			       F_SEAL_GROW |
9184f5ce5e8SDavid Herrmann 			       F_SEAL_WRITE);
9194f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SEAL);
9204f5ce5e8SDavid Herrmann 	close(fd);
9214f5ce5e8SDavid Herrmann }
9224f5ce5e8SDavid Herrmann 
9234f5ce5e8SDavid Herrmann /*
9244f5ce5e8SDavid Herrmann  * Test SEAL_WRITE
9254f5ce5e8SDavid Herrmann  * Test whether SEAL_WRITE actually prevents modifications.
9264f5ce5e8SDavid Herrmann  */
test_seal_write(void)9274f5ce5e8SDavid Herrmann static void test_seal_write(void)
9284f5ce5e8SDavid Herrmann {
9294f5ce5e8SDavid Herrmann 	int fd;
9304f5ce5e8SDavid Herrmann 
9313037aeb9SMarc-André Lureau 	printf("%s SEAL-WRITE\n", memfd_str);
9321f522a48SMike Kravetz 
9334f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_seal_write",
9341f522a48SMike Kravetz 			    mfd_def_size,
9354f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
9364f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
9374f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_WRITE);
9384f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE);
9394f5ce5e8SDavid Herrmann 
9404f5ce5e8SDavid Herrmann 	mfd_assert_read(fd);
9414f5ce5e8SDavid Herrmann 	mfd_fail_write(fd);
9424f5ce5e8SDavid Herrmann 	mfd_assert_shrink(fd);
9434f5ce5e8SDavid Herrmann 	mfd_assert_grow(fd);
9444f5ce5e8SDavid Herrmann 	mfd_fail_grow_write(fd);
9454f5ce5e8SDavid Herrmann 
9464f5ce5e8SDavid Herrmann 	close(fd);
9474f5ce5e8SDavid Herrmann }
9484f5ce5e8SDavid Herrmann 
9494f5ce5e8SDavid Herrmann /*
95054402986SJoel Fernandes (Google)  * Test SEAL_FUTURE_WRITE
95154402986SJoel Fernandes (Google)  * Test whether SEAL_FUTURE_WRITE actually prevents modifications.
95254402986SJoel Fernandes (Google)  */
test_seal_future_write(void)95354402986SJoel Fernandes (Google) static void test_seal_future_write(void)
95454402986SJoel Fernandes (Google) {
95554402986SJoel Fernandes (Google) 	int fd, fd2;
95654402986SJoel Fernandes (Google) 	void *p;
95754402986SJoel Fernandes (Google) 
95854402986SJoel Fernandes (Google) 	printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
95954402986SJoel Fernandes (Google) 
96054402986SJoel Fernandes (Google) 	fd = mfd_assert_new("kern_memfd_seal_future_write",
96154402986SJoel Fernandes (Google) 			    mfd_def_size,
96254402986SJoel Fernandes (Google) 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
96354402986SJoel Fernandes (Google) 
96454402986SJoel Fernandes (Google) 	p = mfd_assert_mmap_shared(fd);
96554402986SJoel Fernandes (Google) 
96654402986SJoel Fernandes (Google) 	mfd_assert_has_seals(fd, 0);
96754402986SJoel Fernandes (Google) 
96854402986SJoel Fernandes (Google) 	mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
96954402986SJoel Fernandes (Google) 	mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
97054402986SJoel Fernandes (Google) 
97154402986SJoel Fernandes (Google) 	/* read should pass, writes should fail */
97254402986SJoel Fernandes (Google) 	mfd_assert_read(fd);
97354402986SJoel Fernandes (Google) 	mfd_assert_read_shared(fd);
97454402986SJoel Fernandes (Google) 	mfd_fail_write(fd);
97554402986SJoel Fernandes (Google) 
97654402986SJoel Fernandes (Google) 	fd2 = mfd_assert_reopen_fd(fd);
97754402986SJoel Fernandes (Google) 	/* read should pass, writes should still fail */
97854402986SJoel Fernandes (Google) 	mfd_assert_read(fd2);
97954402986SJoel Fernandes (Google) 	mfd_assert_read_shared(fd2);
98054402986SJoel Fernandes (Google) 	mfd_fail_write(fd2);
98154402986SJoel Fernandes (Google) 
9822e53c4e1SJoel Fernandes (Google) 	mfd_assert_fork_private_write(fd);
9832e53c4e1SJoel Fernandes (Google) 
98454402986SJoel Fernandes (Google) 	munmap(p, mfd_def_size);
98554402986SJoel Fernandes (Google) 	close(fd2);
98654402986SJoel Fernandes (Google) 	close(fd);
98754402986SJoel Fernandes (Google) }
98854402986SJoel Fernandes (Google) 
98954402986SJoel Fernandes (Google) /*
9904f5ce5e8SDavid Herrmann  * Test SEAL_SHRINK
9914f5ce5e8SDavid Herrmann  * Test whether SEAL_SHRINK actually prevents shrinking
9924f5ce5e8SDavid Herrmann  */
test_seal_shrink(void)9934f5ce5e8SDavid Herrmann static void test_seal_shrink(void)
9944f5ce5e8SDavid Herrmann {
9954f5ce5e8SDavid Herrmann 	int fd;
9964f5ce5e8SDavid Herrmann 
9973037aeb9SMarc-André Lureau 	printf("%s SEAL-SHRINK\n", memfd_str);
9981f522a48SMike Kravetz 
9994f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_seal_shrink",
10001f522a48SMike Kravetz 			    mfd_def_size,
10014f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
10024f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
10034f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SHRINK);
10044f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SHRINK);
10054f5ce5e8SDavid Herrmann 
10064f5ce5e8SDavid Herrmann 	mfd_assert_read(fd);
10074f5ce5e8SDavid Herrmann 	mfd_assert_write(fd);
10084f5ce5e8SDavid Herrmann 	mfd_fail_shrink(fd);
10094f5ce5e8SDavid Herrmann 	mfd_assert_grow(fd);
10104f5ce5e8SDavid Herrmann 	mfd_assert_grow_write(fd);
10114f5ce5e8SDavid Herrmann 
10124f5ce5e8SDavid Herrmann 	close(fd);
10134f5ce5e8SDavid Herrmann }
10144f5ce5e8SDavid Herrmann 
10154f5ce5e8SDavid Herrmann /*
10164f5ce5e8SDavid Herrmann  * Test SEAL_GROW
10174f5ce5e8SDavid Herrmann  * Test whether SEAL_GROW actually prevents growing
10184f5ce5e8SDavid Herrmann  */
test_seal_grow(void)10194f5ce5e8SDavid Herrmann static void test_seal_grow(void)
10204f5ce5e8SDavid Herrmann {
10214f5ce5e8SDavid Herrmann 	int fd;
10224f5ce5e8SDavid Herrmann 
10233037aeb9SMarc-André Lureau 	printf("%s SEAL-GROW\n", memfd_str);
10241f522a48SMike Kravetz 
10254f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_seal_grow",
10261f522a48SMike Kravetz 			    mfd_def_size,
10274f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
10284f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
10294f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_GROW);
10304f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_GROW);
10314f5ce5e8SDavid Herrmann 
10324f5ce5e8SDavid Herrmann 	mfd_assert_read(fd);
10334f5ce5e8SDavid Herrmann 	mfd_assert_write(fd);
10344f5ce5e8SDavid Herrmann 	mfd_assert_shrink(fd);
10354f5ce5e8SDavid Herrmann 	mfd_fail_grow(fd);
10364f5ce5e8SDavid Herrmann 	mfd_fail_grow_write(fd);
10374f5ce5e8SDavid Herrmann 
10384f5ce5e8SDavid Herrmann 	close(fd);
10394f5ce5e8SDavid Herrmann }
10404f5ce5e8SDavid Herrmann 
10414f5ce5e8SDavid Herrmann /*
10424f5ce5e8SDavid Herrmann  * Test SEAL_SHRINK | SEAL_GROW
10434f5ce5e8SDavid Herrmann  * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
10444f5ce5e8SDavid Herrmann  */
test_seal_resize(void)10454f5ce5e8SDavid Herrmann static void test_seal_resize(void)
10464f5ce5e8SDavid Herrmann {
10474f5ce5e8SDavid Herrmann 	int fd;
10484f5ce5e8SDavid Herrmann 
10493037aeb9SMarc-André Lureau 	printf("%s SEAL-RESIZE\n", memfd_str);
10501f522a48SMike Kravetz 
10514f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_seal_resize",
10521f522a48SMike Kravetz 			    mfd_def_size,
10534f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
10544f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
10554f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
10564f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
10574f5ce5e8SDavid Herrmann 
10584f5ce5e8SDavid Herrmann 	mfd_assert_read(fd);
10594f5ce5e8SDavid Herrmann 	mfd_assert_write(fd);
10604f5ce5e8SDavid Herrmann 	mfd_fail_shrink(fd);
10614f5ce5e8SDavid Herrmann 	mfd_fail_grow(fd);
10624f5ce5e8SDavid Herrmann 	mfd_fail_grow_write(fd);
10634f5ce5e8SDavid Herrmann 
10644f5ce5e8SDavid Herrmann 	close(fd);
10654f5ce5e8SDavid Herrmann }
10664f5ce5e8SDavid Herrmann 
10674f5ce5e8SDavid Herrmann /*
106832d118adSDaniel Verkamp  * Test SEAL_EXEC
106911f75a01SJeff Xu  * Test fd is created with exec and allow sealing.
107011f75a01SJeff Xu  * chmod() cannot change x bits after sealing.
107132d118adSDaniel Verkamp  */
test_exec_seal(void)107211f75a01SJeff Xu static void test_exec_seal(void)
107332d118adSDaniel Verkamp {
107432d118adSDaniel Verkamp 	int fd;
107532d118adSDaniel Verkamp 
107632d118adSDaniel Verkamp 	printf("%s SEAL-EXEC\n", memfd_str);
107732d118adSDaniel Verkamp 
107811f75a01SJeff Xu 	printf("%s	Apply SEAL_EXEC\n", memfd_str);
107932d118adSDaniel Verkamp 	fd = mfd_assert_new("kern_memfd_seal_exec",
108032d118adSDaniel Verkamp 			    mfd_def_size,
108111f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_EXEC);
108232d118adSDaniel Verkamp 
108332d118adSDaniel Verkamp 	mfd_assert_mode(fd, 0777);
108432d118adSDaniel Verkamp 	mfd_assert_chmod(fd, 0644);
108532d118adSDaniel Verkamp 
108632d118adSDaniel Verkamp 	mfd_assert_has_seals(fd, 0);
108732d118adSDaniel Verkamp 	mfd_assert_add_seals(fd, F_SEAL_EXEC);
108832d118adSDaniel Verkamp 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
108932d118adSDaniel Verkamp 
109032d118adSDaniel Verkamp 	mfd_assert_chmod(fd, 0600);
109132d118adSDaniel Verkamp 	mfd_fail_chmod(fd, 0777);
109232d118adSDaniel Verkamp 	mfd_fail_chmod(fd, 0670);
109332d118adSDaniel Verkamp 	mfd_fail_chmod(fd, 0605);
109432d118adSDaniel Verkamp 	mfd_fail_chmod(fd, 0700);
109532d118adSDaniel Verkamp 	mfd_fail_chmod(fd, 0100);
109632d118adSDaniel Verkamp 	mfd_assert_chmod(fd, 0666);
109711f75a01SJeff Xu 	mfd_assert_write(fd);
109832d118adSDaniel Verkamp 	close(fd);
109911f75a01SJeff Xu 
110011f75a01SJeff Xu 	printf("%s	Apply ALL_SEALS\n", memfd_str);
110111f75a01SJeff Xu 	fd = mfd_assert_new("kern_memfd_seal_exec",
110211f75a01SJeff Xu 			    mfd_def_size,
110311f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_EXEC);
110411f75a01SJeff Xu 
110511f75a01SJeff Xu 	mfd_assert_mode(fd, 0777);
110611f75a01SJeff Xu 	mfd_assert_chmod(fd, 0700);
110711f75a01SJeff Xu 
110811f75a01SJeff Xu 	mfd_assert_has_seals(fd, 0);
110911f75a01SJeff Xu 	mfd_assert_add_seals(fd, F_SEAL_EXEC);
111011f75a01SJeff Xu 	mfd_assert_has_seals(fd, F_WX_SEALS);
111111f75a01SJeff Xu 
111211f75a01SJeff Xu 	mfd_fail_chmod(fd, 0711);
111311f75a01SJeff Xu 	mfd_fail_chmod(fd, 0600);
111411f75a01SJeff Xu 	mfd_fail_write(fd);
111511f75a01SJeff Xu 	close(fd);
111611f75a01SJeff Xu }
111711f75a01SJeff Xu 
111811f75a01SJeff Xu /*
111911f75a01SJeff Xu  * Test EXEC_NO_SEAL
112011f75a01SJeff Xu  * Test fd is created with exec and not allow sealing.
112111f75a01SJeff Xu  */
test_exec_no_seal(void)112211f75a01SJeff Xu static void test_exec_no_seal(void)
112311f75a01SJeff Xu {
112411f75a01SJeff Xu 	int fd;
112511f75a01SJeff Xu 
112611f75a01SJeff Xu 	printf("%s EXEC_NO_SEAL\n", memfd_str);
112711f75a01SJeff Xu 
112811f75a01SJeff Xu 	/* Create with EXEC but without ALLOW_SEALING */
112911f75a01SJeff Xu 	fd = mfd_assert_new("kern_memfd_exec_no_sealing",
113011f75a01SJeff Xu 			    mfd_def_size,
113111f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_EXEC);
113211f75a01SJeff Xu 	mfd_assert_mode(fd, 0777);
113311f75a01SJeff Xu 	mfd_assert_has_seals(fd, F_SEAL_SEAL);
113411f75a01SJeff Xu 	mfd_assert_chmod(fd, 0666);
113511f75a01SJeff Xu 	close(fd);
113611f75a01SJeff Xu }
113711f75a01SJeff Xu 
113811f75a01SJeff Xu /*
113911f75a01SJeff Xu  * Test memfd_create with MFD_NOEXEC flag
114011f75a01SJeff Xu  */
test_noexec_seal(void)114111f75a01SJeff Xu static void test_noexec_seal(void)
114211f75a01SJeff Xu {
114311f75a01SJeff Xu 	int fd;
114411f75a01SJeff Xu 
114511f75a01SJeff Xu 	printf("%s NOEXEC_SEAL\n", memfd_str);
114611f75a01SJeff Xu 
114711f75a01SJeff Xu 	/* Create with NOEXEC and ALLOW_SEALING */
114811f75a01SJeff Xu 	fd = mfd_assert_new("kern_memfd_noexec",
114911f75a01SJeff Xu 			    mfd_def_size,
115011f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL);
115111f75a01SJeff Xu 	mfd_assert_mode(fd, 0666);
115211f75a01SJeff Xu 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
115311f75a01SJeff Xu 	mfd_fail_chmod(fd, 0777);
115411f75a01SJeff Xu 	close(fd);
115511f75a01SJeff Xu 
115611f75a01SJeff Xu 	/* Create with NOEXEC but without ALLOW_SEALING */
115711f75a01SJeff Xu 	fd = mfd_assert_new("kern_memfd_noexec",
115811f75a01SJeff Xu 			    mfd_def_size,
115911f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_NOEXEC_SEAL);
116011f75a01SJeff Xu 	mfd_assert_mode(fd, 0666);
116111f75a01SJeff Xu 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
116211f75a01SJeff Xu 	mfd_fail_chmod(fd, 0777);
116311f75a01SJeff Xu 	close(fd);
116411f75a01SJeff Xu }
116511f75a01SJeff Xu 
test_sysctl_sysctl0(void)11666469b66eSAleksa Sarai static void test_sysctl_sysctl0(void)
116711f75a01SJeff Xu {
116811f75a01SJeff Xu 	int fd;
116911f75a01SJeff Xu 
11706469b66eSAleksa Sarai 	sysctl_assert_equal("0");
11716469b66eSAleksa Sarai 
11726469b66eSAleksa Sarai 	fd = mfd_assert_new("kern_memfd_sysctl_0_dfl",
117311f75a01SJeff Xu 			    mfd_def_size,
117411f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
11756469b66eSAleksa Sarai 	mfd_assert_mode(fd, 0777);
11766469b66eSAleksa Sarai 	mfd_assert_has_seals(fd, 0);
11776469b66eSAleksa Sarai 	mfd_assert_chmod(fd, 0644);
11786469b66eSAleksa Sarai 	close(fd);
11796469b66eSAleksa Sarai }
118011f75a01SJeff Xu 
test_sysctl_set_sysctl0(void)11816469b66eSAleksa Sarai static void test_sysctl_set_sysctl0(void)
11826469b66eSAleksa Sarai {
11836469b66eSAleksa Sarai 	sysctl_assert_write("0");
11846469b66eSAleksa Sarai 	test_sysctl_sysctl0();
11856469b66eSAleksa Sarai }
11866469b66eSAleksa Sarai 
test_sysctl_sysctl1(void)11876469b66eSAleksa Sarai static void test_sysctl_sysctl1(void)
11886469b66eSAleksa Sarai {
11896469b66eSAleksa Sarai 	int fd;
11906469b66eSAleksa Sarai 
11916469b66eSAleksa Sarai 	sysctl_assert_equal("1");
11926469b66eSAleksa Sarai 
11936469b66eSAleksa Sarai 	fd = mfd_assert_new("kern_memfd_sysctl_1_dfl",
11946469b66eSAleksa Sarai 			    mfd_def_size,
11956469b66eSAleksa Sarai 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
11966469b66eSAleksa Sarai 	mfd_assert_mode(fd, 0666);
11976469b66eSAleksa Sarai 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
11986469b66eSAleksa Sarai 	mfd_fail_chmod(fd, 0777);
11996469b66eSAleksa Sarai 	close(fd);
12006469b66eSAleksa Sarai 
12016469b66eSAleksa Sarai 	fd = mfd_assert_new("kern_memfd_sysctl_1_exec",
12026469b66eSAleksa Sarai 			    mfd_def_size,
12036469b66eSAleksa Sarai 			    MFD_CLOEXEC | MFD_EXEC | MFD_ALLOW_SEALING);
120411f75a01SJeff Xu 	mfd_assert_mode(fd, 0777);
120511f75a01SJeff Xu 	mfd_assert_has_seals(fd, 0);
120611f75a01SJeff Xu 	mfd_assert_chmod(fd, 0644);
120711f75a01SJeff Xu 	close(fd);
120811f75a01SJeff Xu 
12096469b66eSAleksa Sarai 	fd = mfd_assert_new("kern_memfd_sysctl_1_noexec",
121011f75a01SJeff Xu 			    mfd_def_size,
12116469b66eSAleksa Sarai 			    MFD_CLOEXEC | MFD_NOEXEC_SEAL | MFD_ALLOW_SEALING);
121211f75a01SJeff Xu 	mfd_assert_mode(fd, 0666);
121311f75a01SJeff Xu 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
121411f75a01SJeff Xu 	mfd_fail_chmod(fd, 0777);
121511f75a01SJeff Xu 	close(fd);
12166469b66eSAleksa Sarai }
121711f75a01SJeff Xu 
test_sysctl_set_sysctl1(void)12186469b66eSAleksa Sarai static void test_sysctl_set_sysctl1(void)
12196469b66eSAleksa Sarai {
12206469b66eSAleksa Sarai 	sysctl_assert_write("1");
12216469b66eSAleksa Sarai 	test_sysctl_sysctl1();
12226469b66eSAleksa Sarai }
12236469b66eSAleksa Sarai 
test_sysctl_sysctl2(void)12246469b66eSAleksa Sarai static void test_sysctl_sysctl2(void)
12256469b66eSAleksa Sarai {
12266469b66eSAleksa Sarai 	int fd;
12276469b66eSAleksa Sarai 
12286469b66eSAleksa Sarai 	sysctl_assert_equal("2");
1229202e1422SAleksa Sarai 
1230202e1422SAleksa Sarai 	fd = mfd_assert_new("kern_memfd_sysctl_2_dfl",
1231202e1422SAleksa Sarai 			    mfd_def_size,
123211f75a01SJeff Xu 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
1233202e1422SAleksa Sarai 	mfd_assert_mode(fd, 0666);
1234202e1422SAleksa Sarai 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
1235202e1422SAleksa Sarai 	mfd_fail_chmod(fd, 0777);
1236202e1422SAleksa Sarai 	close(fd);
1237202e1422SAleksa Sarai 
12386469b66eSAleksa Sarai 	mfd_fail_new("kern_memfd_sysctl_2_exec",
12396469b66eSAleksa Sarai 		     MFD_CLOEXEC | MFD_EXEC | MFD_ALLOW_SEALING);
12406469b66eSAleksa Sarai 
12416469b66eSAleksa Sarai 	fd = mfd_assert_new("kern_memfd_sysctl_2_noexec",
1242202e1422SAleksa Sarai 			    mfd_def_size,
12436469b66eSAleksa Sarai 			    MFD_CLOEXEC | MFD_NOEXEC_SEAL | MFD_ALLOW_SEALING);
1244202e1422SAleksa Sarai 	mfd_assert_mode(fd, 0666);
1245202e1422SAleksa Sarai 	mfd_assert_has_seals(fd, F_SEAL_EXEC);
1246202e1422SAleksa Sarai 	mfd_fail_chmod(fd, 0777);
1247badbbcd7SJeff Xu 	close(fd);
124811f75a01SJeff Xu }
124911f75a01SJeff Xu 
test_sysctl_set_sysctl2(void)12506469b66eSAleksa Sarai static void test_sysctl_set_sysctl2(void)
125111f75a01SJeff Xu {
12526469b66eSAleksa Sarai 	sysctl_assert_write("2");
12536469b66eSAleksa Sarai 	test_sysctl_sysctl2();
125411f75a01SJeff Xu }
125511f75a01SJeff Xu 
sysctl_simple_child(void * arg)12566469b66eSAleksa Sarai static int sysctl_simple_child(void *arg)
125711f75a01SJeff Xu {
125811f75a01SJeff Xu 	int fd;
12596469b66eSAleksa Sarai 	int pid;
126011f75a01SJeff Xu 
12616469b66eSAleksa Sarai 	printf("%s sysctl 0\n", memfd_str);
12626469b66eSAleksa Sarai 	test_sysctl_set_sysctl0();
126311f75a01SJeff Xu 
12646469b66eSAleksa Sarai 	printf("%s sysctl 1\n", memfd_str);
12656469b66eSAleksa Sarai 	test_sysctl_set_sysctl1();
126611f75a01SJeff Xu 
12676469b66eSAleksa Sarai 	printf("%s sysctl 0\n", memfd_str);
12686469b66eSAleksa Sarai 	test_sysctl_set_sysctl0();
12696469b66eSAleksa Sarai 
12706469b66eSAleksa Sarai 	printf("%s sysctl 2\n", memfd_str);
12716469b66eSAleksa Sarai 	test_sysctl_set_sysctl2();
12726469b66eSAleksa Sarai 
12736469b66eSAleksa Sarai 	printf("%s sysctl 1\n", memfd_str);
12746469b66eSAleksa Sarai 	test_sysctl_set_sysctl1();
12756469b66eSAleksa Sarai 
12766469b66eSAleksa Sarai 	printf("%s sysctl 0\n", memfd_str);
12776469b66eSAleksa Sarai 	test_sysctl_set_sysctl0();
12786469b66eSAleksa Sarai 
127911f75a01SJeff Xu 	return 0;
128011f75a01SJeff Xu }
128111f75a01SJeff Xu 
128211f75a01SJeff Xu /*
128311f75a01SJeff Xu  * Test sysctl
12846469b66eSAleksa Sarai  * A very basic test to make sure the core sysctl semantics work.
128511f75a01SJeff Xu  */
test_sysctl_simple(void)12866469b66eSAleksa Sarai static void test_sysctl_simple(void)
128711f75a01SJeff Xu {
12886469b66eSAleksa Sarai 	int pid = spawn_thread(CLONE_NEWPID, sysctl_simple_child, NULL);
128911f75a01SJeff Xu 
12906469b66eSAleksa Sarai 	join_thread(pid);
12916469b66eSAleksa Sarai }
12926469b66eSAleksa Sarai 
sysctl_nested(void * arg)12936469b66eSAleksa Sarai static int sysctl_nested(void *arg)
12946469b66eSAleksa Sarai {
12956469b66eSAleksa Sarai 	void (*fn)(void) = arg;
12966469b66eSAleksa Sarai 
12976469b66eSAleksa Sarai 	fn();
12986469b66eSAleksa Sarai 	return 0;
12996469b66eSAleksa Sarai }
13006469b66eSAleksa Sarai 
sysctl_nested_wait(void * arg)13016469b66eSAleksa Sarai static int sysctl_nested_wait(void *arg)
13026469b66eSAleksa Sarai {
13036469b66eSAleksa Sarai 	/* Wait for a SIGCONT. */
13046469b66eSAleksa Sarai 	kill(getpid(), SIGSTOP);
13056469b66eSAleksa Sarai 	return sysctl_nested(arg);
13066469b66eSAleksa Sarai }
13076469b66eSAleksa Sarai 
test_sysctl_sysctl1_failset(void)13086469b66eSAleksa Sarai static void test_sysctl_sysctl1_failset(void)
13096469b66eSAleksa Sarai {
13106469b66eSAleksa Sarai 	sysctl_fail_write("0");
13116469b66eSAleksa Sarai 	test_sysctl_sysctl1();
13126469b66eSAleksa Sarai }
13136469b66eSAleksa Sarai 
test_sysctl_sysctl2_failset(void)13146469b66eSAleksa Sarai static void test_sysctl_sysctl2_failset(void)
13156469b66eSAleksa Sarai {
13166469b66eSAleksa Sarai 	sysctl_fail_write("1");
13176469b66eSAleksa Sarai 	test_sysctl_sysctl2();
13186469b66eSAleksa Sarai 
13196469b66eSAleksa Sarai 	sysctl_fail_write("0");
13206469b66eSAleksa Sarai 	test_sysctl_sysctl2();
13216469b66eSAleksa Sarai }
13226469b66eSAleksa Sarai 
sysctl_nested_child(void * arg)13236469b66eSAleksa Sarai static int sysctl_nested_child(void *arg)
13246469b66eSAleksa Sarai {
13256469b66eSAleksa Sarai 	int fd;
13266469b66eSAleksa Sarai 	int pid;
13276469b66eSAleksa Sarai 
13286469b66eSAleksa Sarai 	printf("%s nested sysctl 0\n", memfd_str);
13296469b66eSAleksa Sarai 	sysctl_assert_write("0");
13306469b66eSAleksa Sarai 	/* A further nested pidns works the same. */
13316469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_simple_child, NULL);
13326469b66eSAleksa Sarai 	join_thread(pid);
13336469b66eSAleksa Sarai 
13346469b66eSAleksa Sarai 	printf("%s nested sysctl 1\n", memfd_str);
13356469b66eSAleksa Sarai 	sysctl_assert_write("1");
13366469b66eSAleksa Sarai 	/* Child inherits our setting. */
13376469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested, test_sysctl_sysctl1);
13386469b66eSAleksa Sarai 	join_thread(pid);
13396469b66eSAleksa Sarai 	/* Child cannot raise the setting. */
13406469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested,
13416469b66eSAleksa Sarai 			   test_sysctl_sysctl1_failset);
13426469b66eSAleksa Sarai 	join_thread(pid);
13436469b66eSAleksa Sarai 	/* Child can lower the setting. */
13446469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested,
13456469b66eSAleksa Sarai 			   test_sysctl_set_sysctl2);
13466469b66eSAleksa Sarai 	join_thread(pid);
13476469b66eSAleksa Sarai 	/* Child lowering the setting has no effect on our setting. */
13486469b66eSAleksa Sarai 	test_sysctl_sysctl1();
13496469b66eSAleksa Sarai 
13506469b66eSAleksa Sarai 	printf("%s nested sysctl 2\n", memfd_str);
13516469b66eSAleksa Sarai 	sysctl_assert_write("2");
13526469b66eSAleksa Sarai 	/* Child inherits our setting. */
13536469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested, test_sysctl_sysctl2);
13546469b66eSAleksa Sarai 	join_thread(pid);
13556469b66eSAleksa Sarai 	/* Child cannot raise the setting. */
13566469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested,
13576469b66eSAleksa Sarai 			   test_sysctl_sysctl2_failset);
13586469b66eSAleksa Sarai 	join_thread(pid);
13596469b66eSAleksa Sarai 
13606469b66eSAleksa Sarai 	/* Verify that the rules are actually inherited after fork. */
13616469b66eSAleksa Sarai 	printf("%s nested sysctl 0 -> 1 after fork\n", memfd_str);
13626469b66eSAleksa Sarai 	sysctl_assert_write("0");
13636469b66eSAleksa Sarai 
13646469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
13656469b66eSAleksa Sarai 			   test_sysctl_sysctl1_failset);
13666469b66eSAleksa Sarai 	sysctl_assert_write("1");
13676469b66eSAleksa Sarai 	kill(pid, SIGCONT);
13686469b66eSAleksa Sarai 	join_thread(pid);
13696469b66eSAleksa Sarai 
13706469b66eSAleksa Sarai 	printf("%s nested sysctl 0 -> 2 after fork\n", memfd_str);
13716469b66eSAleksa Sarai 	sysctl_assert_write("0");
13726469b66eSAleksa Sarai 
13736469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
13746469b66eSAleksa Sarai 			   test_sysctl_sysctl2_failset);
13756469b66eSAleksa Sarai 	sysctl_assert_write("2");
13766469b66eSAleksa Sarai 	kill(pid, SIGCONT);
13776469b66eSAleksa Sarai 	join_thread(pid);
13786469b66eSAleksa Sarai 
13796469b66eSAleksa Sarai 	/*
13806469b66eSAleksa Sarai 	 * Verify that the current effective setting is saved on fork, meaning
13816469b66eSAleksa Sarai 	 * that the parent lowering the sysctl doesn't affect already-forked
13826469b66eSAleksa Sarai 	 * children.
13836469b66eSAleksa Sarai 	 */
13846469b66eSAleksa Sarai 	printf("%s nested sysctl 2 -> 1 after fork\n", memfd_str);
13856469b66eSAleksa Sarai 	sysctl_assert_write("2");
13866469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
13876469b66eSAleksa Sarai 			   test_sysctl_sysctl2);
13886469b66eSAleksa Sarai 	sysctl_assert_write("1");
13896469b66eSAleksa Sarai 	kill(pid, SIGCONT);
13906469b66eSAleksa Sarai 	join_thread(pid);
13916469b66eSAleksa Sarai 
13926469b66eSAleksa Sarai 	printf("%s nested sysctl 2 -> 0 after fork\n", memfd_str);
13936469b66eSAleksa Sarai 	sysctl_assert_write("2");
13946469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
13956469b66eSAleksa Sarai 			   test_sysctl_sysctl2);
13966469b66eSAleksa Sarai 	sysctl_assert_write("0");
13976469b66eSAleksa Sarai 	kill(pid, SIGCONT);
13986469b66eSAleksa Sarai 	join_thread(pid);
13996469b66eSAleksa Sarai 
14006469b66eSAleksa Sarai 	printf("%s nested sysctl 1 -> 0 after fork\n", memfd_str);
14016469b66eSAleksa Sarai 	sysctl_assert_write("1");
14026469b66eSAleksa Sarai 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
14036469b66eSAleksa Sarai 			   test_sysctl_sysctl1);
14046469b66eSAleksa Sarai 	sysctl_assert_write("0");
14056469b66eSAleksa Sarai 	kill(pid, SIGCONT);
14066469b66eSAleksa Sarai 	join_thread(pid);
14076469b66eSAleksa Sarai 
14086469b66eSAleksa Sarai 	return 0;
14096469b66eSAleksa Sarai }
14106469b66eSAleksa Sarai 
14116469b66eSAleksa Sarai /*
14126469b66eSAleksa Sarai  * Test sysctl with nested pid namespaces
14136469b66eSAleksa Sarai  * Make sure that the sysctl nesting semantics work correctly.
14146469b66eSAleksa Sarai  */
test_sysctl_nested(void)14156469b66eSAleksa Sarai static void test_sysctl_nested(void)
14166469b66eSAleksa Sarai {
14176469b66eSAleksa Sarai 	int pid = spawn_thread(CLONE_NEWPID, sysctl_nested_child, NULL);
14186469b66eSAleksa Sarai 
14196469b66eSAleksa Sarai 	join_thread(pid);
142032d118adSDaniel Verkamp }
142132d118adSDaniel Verkamp 
142232d118adSDaniel Verkamp /*
14231f522a48SMike Kravetz  * Test sharing via dup()
14241f522a48SMike Kravetz  * Test that seals are shared between dupped FDs and they're all equal.
14251f522a48SMike Kravetz  */
test_share_dup(char * banner,char * b_suffix)14261f522a48SMike Kravetz static void test_share_dup(char *banner, char *b_suffix)
14271f522a48SMike Kravetz {
14281f522a48SMike Kravetz 	int fd, fd2;
14291f522a48SMike Kravetz 
14303037aeb9SMarc-André Lureau 	printf("%s %s %s\n", memfd_str, banner, b_suffix);
14311f522a48SMike Kravetz 
14321f522a48SMike Kravetz 	fd = mfd_assert_new("kern_memfd_share_dup",
14331f522a48SMike Kravetz 			    mfd_def_size,
14344f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
14354f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
14364f5ce5e8SDavid Herrmann 
14374f5ce5e8SDavid Herrmann 	fd2 = mfd_assert_dup(fd);
14384f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, 0);
14394f5ce5e8SDavid Herrmann 
14404f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_WRITE);
14414f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE);
14424f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE);
14434f5ce5e8SDavid Herrmann 
14444f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
14454f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
14464f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
14474f5ce5e8SDavid Herrmann 
14484f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SEAL);
14494f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
14504f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
14514f5ce5e8SDavid Herrmann 
14524f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_GROW);
14534f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd2, F_SEAL_GROW);
14544f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_SEAL);
14554f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd2, F_SEAL_SEAL);
14564f5ce5e8SDavid Herrmann 
14574f5ce5e8SDavid Herrmann 	close(fd2);
14584f5ce5e8SDavid Herrmann 
14594f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_GROW);
14604f5ce5e8SDavid Herrmann 	close(fd);
14614f5ce5e8SDavid Herrmann }
14624f5ce5e8SDavid Herrmann 
14634f5ce5e8SDavid Herrmann /*
14644f5ce5e8SDavid Herrmann  * Test sealing with active mmap()s
14654f5ce5e8SDavid Herrmann  * Modifying seals is only allowed if no other mmap() refs exist.
14664f5ce5e8SDavid Herrmann  */
test_share_mmap(char * banner,char * b_suffix)14671f522a48SMike Kravetz static void test_share_mmap(char *banner, char *b_suffix)
14684f5ce5e8SDavid Herrmann {
14694f5ce5e8SDavid Herrmann 	int fd;
14704f5ce5e8SDavid Herrmann 	void *p;
14714f5ce5e8SDavid Herrmann 
14723037aeb9SMarc-André Lureau 	printf("%s %s %s\n", memfd_str,  banner, b_suffix);
14731f522a48SMike Kravetz 
14744f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_share_mmap",
14751f522a48SMike Kravetz 			    mfd_def_size,
14764f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
14774f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
14784f5ce5e8SDavid Herrmann 
14794f5ce5e8SDavid Herrmann 	/* shared/writable ref prevents sealing WRITE, but allows others */
14804f5ce5e8SDavid Herrmann 	p = mfd_assert_mmap_shared(fd);
14814f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_WRITE);
14824f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
14834f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SHRINK);
14844f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SHRINK);
14851f522a48SMike Kravetz 	munmap(p, mfd_def_size);
14864f5ce5e8SDavid Herrmann 
14874f5ce5e8SDavid Herrmann 	/* readable ref allows sealing */
14884f5ce5e8SDavid Herrmann 	p = mfd_assert_mmap_private(fd);
14894f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_WRITE);
14904f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
14911f522a48SMike Kravetz 	munmap(p, mfd_def_size);
14924f5ce5e8SDavid Herrmann 
14934f5ce5e8SDavid Herrmann 	close(fd);
14944f5ce5e8SDavid Herrmann }
14954f5ce5e8SDavid Herrmann 
14964f5ce5e8SDavid Herrmann /*
14974f5ce5e8SDavid Herrmann  * Test sealing with open(/proc/self/fd/%d)
14984f5ce5e8SDavid Herrmann  * Via /proc we can get access to a separate file-context for the same memfd.
14994f5ce5e8SDavid Herrmann  * This is *not* like dup(), but like a real separate open(). Make sure the
15004f5ce5e8SDavid Herrmann  * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
15014f5ce5e8SDavid Herrmann  */
test_share_open(char * banner,char * b_suffix)15021f522a48SMike Kravetz static void test_share_open(char *banner, char *b_suffix)
15034f5ce5e8SDavid Herrmann {
15044f5ce5e8SDavid Herrmann 	int fd, fd2;
15054f5ce5e8SDavid Herrmann 
15063037aeb9SMarc-André Lureau 	printf("%s %s %s\n", memfd_str, banner, b_suffix);
15071f522a48SMike Kravetz 
15084f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_share_open",
15091f522a48SMike Kravetz 			    mfd_def_size,
15104f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
15114f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
15124f5ce5e8SDavid Herrmann 
15134f5ce5e8SDavid Herrmann 	fd2 = mfd_assert_open(fd, O_RDWR, 0);
15144f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_WRITE);
15154f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE);
15164f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE);
15174f5ce5e8SDavid Herrmann 
15184f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
15194f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
15204f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
15214f5ce5e8SDavid Herrmann 
15224f5ce5e8SDavid Herrmann 	close(fd);
15234f5ce5e8SDavid Herrmann 	fd = mfd_assert_open(fd2, O_RDONLY, 0);
15244f5ce5e8SDavid Herrmann 
15254f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_SEAL);
15264f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
15274f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
15284f5ce5e8SDavid Herrmann 
15294f5ce5e8SDavid Herrmann 	close(fd2);
15304f5ce5e8SDavid Herrmann 	fd2 = mfd_assert_open(fd, O_RDWR, 0);
15314f5ce5e8SDavid Herrmann 
15324f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd2, F_SEAL_SEAL);
15334f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
15344f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
15354f5ce5e8SDavid Herrmann 
15364f5ce5e8SDavid Herrmann 	close(fd2);
15374f5ce5e8SDavid Herrmann 	close(fd);
15384f5ce5e8SDavid Herrmann }
15394f5ce5e8SDavid Herrmann 
15404f5ce5e8SDavid Herrmann /*
15414f5ce5e8SDavid Herrmann  * Test sharing via fork()
15424f5ce5e8SDavid Herrmann  * Test whether seal-modifications work as expected with forked childs.
15434f5ce5e8SDavid Herrmann  */
test_share_fork(char * banner,char * b_suffix)15441f522a48SMike Kravetz static void test_share_fork(char *banner, char *b_suffix)
15454f5ce5e8SDavid Herrmann {
15464f5ce5e8SDavid Herrmann 	int fd;
15474f5ce5e8SDavid Herrmann 	pid_t pid;
15484f5ce5e8SDavid Herrmann 
15493037aeb9SMarc-André Lureau 	printf("%s %s %s\n", memfd_str, banner, b_suffix);
15501f522a48SMike Kravetz 
15514f5ce5e8SDavid Herrmann 	fd = mfd_assert_new("kern_memfd_share_fork",
15521f522a48SMike Kravetz 			    mfd_def_size,
15534f5ce5e8SDavid Herrmann 			    MFD_CLOEXEC | MFD_ALLOW_SEALING);
15544f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, 0);
15554f5ce5e8SDavid Herrmann 
15564f5ce5e8SDavid Herrmann 	pid = spawn_idle_thread(0);
15574f5ce5e8SDavid Herrmann 	mfd_assert_add_seals(fd, F_SEAL_SEAL);
15584f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SEAL);
15594f5ce5e8SDavid Herrmann 
15604f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_WRITE);
15614f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SEAL);
15624f5ce5e8SDavid Herrmann 
15634f5ce5e8SDavid Herrmann 	join_idle_thread(pid);
15644f5ce5e8SDavid Herrmann 
15654f5ce5e8SDavid Herrmann 	mfd_fail_add_seals(fd, F_SEAL_WRITE);
15664f5ce5e8SDavid Herrmann 	mfd_assert_has_seals(fd, F_SEAL_SEAL);
15674f5ce5e8SDavid Herrmann 
15684f5ce5e8SDavid Herrmann 	close(fd);
15694f5ce5e8SDavid Herrmann }
15704f5ce5e8SDavid Herrmann 
pid_ns_supported(void)1571*8b7dfdf3SIsaac J. Manjarres static bool pid_ns_supported(void)
1572*8b7dfdf3SIsaac J. Manjarres {
1573*8b7dfdf3SIsaac J. Manjarres 	return access("/proc/self/ns/pid", F_OK) == 0;
1574*8b7dfdf3SIsaac J. Manjarres }
1575*8b7dfdf3SIsaac J. Manjarres 
main(int argc,char ** argv)15764f5ce5e8SDavid Herrmann int main(int argc, char **argv)
15774f5ce5e8SDavid Herrmann {
15784f5ce5e8SDavid Herrmann 	pid_t pid;
15794f5ce5e8SDavid Herrmann 
15801f522a48SMike Kravetz 	if (argc == 2) {
15811f522a48SMike Kravetz 		if (!strcmp(argv[1], "hugetlbfs")) {
15821f522a48SMike Kravetz 			unsigned long hpage_size = default_huge_page_size();
15831f522a48SMike Kravetz 
15841f522a48SMike Kravetz 			if (!hpage_size) {
15851f522a48SMike Kravetz 				printf("Unable to determine huge page size\n");
15861f522a48SMike Kravetz 				abort();
15871f522a48SMike Kravetz 			}
15881f522a48SMike Kravetz 
15891f522a48SMike Kravetz 			hugetlbfs_test = 1;
15903037aeb9SMarc-André Lureau 			memfd_str = MEMFD_HUGE_STR;
15911f522a48SMike Kravetz 			mfd_def_size = hpage_size * 2;
15923037aeb9SMarc-André Lureau 		} else {
15933037aeb9SMarc-André Lureau 			printf("Unknown option: %s\n", argv[1]);
15943037aeb9SMarc-André Lureau 			abort();
15951f522a48SMike Kravetz 		}
15961f522a48SMike Kravetz 	}
15971f522a48SMike Kravetz 
15984f5ce5e8SDavid Herrmann 	test_create();
15994f5ce5e8SDavid Herrmann 	test_basic();
160011f75a01SJeff Xu 	test_exec_seal();
160111f75a01SJeff Xu 	test_exec_no_seal();
160211f75a01SJeff Xu 	test_noexec_seal();
16034f5ce5e8SDavid Herrmann 
16044f5ce5e8SDavid Herrmann 	test_seal_write();
160554402986SJoel Fernandes (Google) 	test_seal_future_write();
16064f5ce5e8SDavid Herrmann 	test_seal_shrink();
16074f5ce5e8SDavid Herrmann 	test_seal_grow();
16084f5ce5e8SDavid Herrmann 	test_seal_resize();
16094f5ce5e8SDavid Herrmann 
1610*8b7dfdf3SIsaac J. Manjarres 	if (pid_ns_supported()) {
16116469b66eSAleksa Sarai 		test_sysctl_simple();
16126469b66eSAleksa Sarai 		test_sysctl_nested();
1613*8b7dfdf3SIsaac J. Manjarres 	} else {
1614*8b7dfdf3SIsaac J. Manjarres 		printf("PID namespaces are not supported; skipping sysctl tests\n");
1615*8b7dfdf3SIsaac J. Manjarres 	}
16166469b66eSAleksa Sarai 
16171f522a48SMike Kravetz 	test_share_dup("SHARE-DUP", "");
16181f522a48SMike Kravetz 	test_share_mmap("SHARE-MMAP", "");
16191f522a48SMike Kravetz 	test_share_open("SHARE-OPEN", "");
16201f522a48SMike Kravetz 	test_share_fork("SHARE-FORK", "");
16214f5ce5e8SDavid Herrmann 
16224f5ce5e8SDavid Herrmann 	/* Run test-suite in a multi-threaded environment with a shared
16234f5ce5e8SDavid Herrmann 	 * file-table. */
16244f5ce5e8SDavid Herrmann 	pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
16251f522a48SMike Kravetz 	test_share_dup("SHARE-DUP", SHARED_FT_STR);
16261f522a48SMike Kravetz 	test_share_mmap("SHARE-MMAP", SHARED_FT_STR);
16271f522a48SMike Kravetz 	test_share_open("SHARE-OPEN", SHARED_FT_STR);
16281f522a48SMike Kravetz 	test_share_fork("SHARE-FORK", SHARED_FT_STR);
16294f5ce5e8SDavid Herrmann 	join_idle_thread(pid);
16304f5ce5e8SDavid Herrmann 
16314f5ce5e8SDavid Herrmann 	printf("memfd: DONE\n");
16324f5ce5e8SDavid Herrmann 
16334f5ce5e8SDavid Herrmann 	return 0;
16344f5ce5e8SDavid Herrmann }
1635