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