1 // SPDX-License-Identifier: GPL-2.0
3 #define __EXPORTED_HEADERS__
8 #include <linux/falloc.h>
10 #include <linux/memfd.h>
18 #include <sys/syscall.h>
24 #define MEMFD_STR "memfd:"
25 #define MEMFD_HUGE_STR "memfd-hugetlb:"
26 #define SHARED_FT_STR "(shared file-table)"
28 #define MFD_DEF_SIZE 8192
29 #define STACK_SIZE 65536
31 #define F_SEAL_EXEC 0x0020
33 #define F_WX_SEALS (F_SEAL_SHRINK | \
36 F_SEAL_FUTURE_WRITE | \
39 #define MFD_NOEXEC_SEAL 0x0008U
42 * Default is not to test hugetlbfs
44 static size_t mfd_def_size = MFD_DEF_SIZE;
45 static const char *memfd_str = MEMFD_STR;
46 static pid_t spawn_newpid_thread(unsigned int flags, int (*fn)(void *));
47 static int newpid_thread_fn2(void *arg);
48 static void join_newpid_thread(pid_t pid);
50 static ssize_t fd2name(int fd, char *buf, size_t bufsize)
56 size = snprintf(buf1, PATH_MAX, "/proc/self/fd/%d", fd);
58 printf("snprintf(%d) failed on %m\n", fd);
63 * reserver one byte for string termination.
65 nbytes = readlink(buf1, buf, bufsize-1);
67 printf("readlink(%s) failed %m\n", buf1);
74 static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
78 fd = sys_memfd_create(name, flags);
80 printf("memfd_create(\"%s\", %u) failed: %m\n",
85 r = ftruncate(fd, sz);
87 printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
94 static void sysctl_assert_write(const char *val)
96 int fd = open("/proc/sys/vm/memfd_noexec", O_WRONLY | O_CLOEXEC);
99 printf("open sysctl failed\n");
103 if (write(fd, val, strlen(val)) < 0) {
104 printf("write sysctl failed\n");
109 static void sysctl_fail_write(const char *val)
111 int fd = open("/proc/sys/vm/memfd_noexec", O_WRONLY | O_CLOEXEC);
114 printf("open sysctl failed\n");
118 if (write(fd, val, strlen(val)) >= 0) {
119 printf("write sysctl %s succeeded, but failure expected\n",
125 static int mfd_assert_reopen_fd(int fd_in)
130 sprintf(path, "/proc/self/fd/%d", fd_in);
132 fd = open(path, O_RDWR);
134 printf("re-open of existing fd %d failed\n", fd_in);
141 static void mfd_fail_new(const char *name, unsigned int flags)
145 r = sys_memfd_create(name, flags);
147 printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
154 static unsigned int mfd_assert_get_seals(int fd)
158 r = fcntl(fd, F_GET_SEALS);
160 printf("GET_SEALS(%d) failed: %m\n", fd);
164 return (unsigned int)r;
167 static void mfd_assert_has_seals(int fd, unsigned int seals)
172 fd2name(fd, buf, PATH_MAX);
174 s = mfd_assert_get_seals(fd);
176 printf("%u != %u = GET_SEALS(%s)\n", seals, s, buf);
181 static void mfd_assert_add_seals(int fd, unsigned int seals)
186 s = mfd_assert_get_seals(fd);
187 r = fcntl(fd, F_ADD_SEALS, seals);
189 printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
194 static void mfd_fail_add_seals(int fd, unsigned int seals)
199 r = fcntl(fd, F_GET_SEALS);
205 r = fcntl(fd, F_ADD_SEALS, seals);
207 printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
213 static void mfd_assert_size(int fd, size_t size)
220 printf("fstat(%d) failed: %m\n", fd);
222 } else if (st.st_size != size) {
223 printf("wrong file size %lld, but expected %lld\n",
224 (long long)st.st_size, (long long)size);
229 static int mfd_assert_dup(int fd)
235 printf("dup(%d) failed: %m\n", fd);
242 static void *mfd_assert_mmap_shared(int fd)
248 PROT_READ | PROT_WRITE,
252 if (p == MAP_FAILED) {
253 printf("mmap() failed: %m\n");
260 static void *mfd_assert_mmap_private(int fd)
270 if (p == MAP_FAILED) {
271 printf("mmap() failed: %m\n");
278 static int mfd_assert_open(int fd, int flags, mode_t mode)
283 sprintf(buf, "/proc/self/fd/%d", fd);
284 r = open(buf, flags, mode);
286 printf("open(%s) failed: %m\n", buf);
293 static void mfd_fail_open(int fd, int flags, mode_t mode)
298 sprintf(buf, "/proc/self/fd/%d", fd);
299 r = open(buf, flags, mode);
301 printf("open(%s) didn't fail as expected\n", buf);
306 static void mfd_assert_read(int fd)
312 l = read(fd, buf, sizeof(buf));
313 if (l != sizeof(buf)) {
314 printf("read() failed: %m\n");
318 /* verify PROT_READ *is* allowed */
325 if (p == MAP_FAILED) {
326 printf("mmap() failed: %m\n");
329 munmap(p, mfd_def_size);
331 /* verify MAP_PRIVATE is *always* allowed (even writable) */
334 PROT_READ | PROT_WRITE,
338 if (p == MAP_FAILED) {
339 printf("mmap() failed: %m\n");
342 munmap(p, mfd_def_size);
345 /* Test that PROT_READ + MAP_SHARED mappings work. */
346 static void mfd_assert_read_shared(int fd)
350 /* verify PROT_READ and MAP_SHARED *is* allowed */
357 if (p == MAP_FAILED) {
358 printf("mmap() failed: %m\n");
361 munmap(p, mfd_def_size);
364 static void mfd_assert_fork_private_write(int fd)
371 PROT_READ | PROT_WRITE,
375 if (p == MAP_FAILED) {
376 printf("mmap() failed: %m\n");
387 waitpid(pid, NULL, 0);
390 printf("MAP_PRIVATE copy-on-write failed: %m\n");
395 munmap(p, mfd_def_size);
398 static void mfd_assert_write(int fd)
405 * huegtlbfs does not support write, but we want to
406 * verify everything else here.
408 if (!hugetlbfs_test) {
409 /* verify write() succeeds */
410 l = write(fd, "\0\0\0\0", 4);
412 printf("write() failed: %m\n");
417 /* verify PROT_READ | PROT_WRITE is allowed */
420 PROT_READ | PROT_WRITE,
424 if (p == MAP_FAILED) {
425 printf("mmap() failed: %m\n");
429 munmap(p, mfd_def_size);
431 /* verify PROT_WRITE is allowed */
438 if (p == MAP_FAILED) {
439 printf("mmap() failed: %m\n");
443 munmap(p, mfd_def_size);
445 /* verify PROT_READ with MAP_SHARED is allowed and a following
446 * mprotect(PROT_WRITE) allows writing */
453 if (p == MAP_FAILED) {
454 printf("mmap() failed: %m\n");
458 r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
460 printf("mprotect() failed: %m\n");
465 munmap(p, mfd_def_size);
467 /* verify PUNCH_HOLE works */
469 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
473 printf("fallocate(PUNCH_HOLE) failed: %m\n");
478 static void mfd_fail_write(int fd)
484 /* verify write() fails */
485 l = write(fd, "data", 4);
487 printf("expected EPERM on write(), but got %d: %m\n", (int)l);
491 /* verify PROT_READ | PROT_WRITE is not allowed */
494 PROT_READ | PROT_WRITE,
498 if (p != MAP_FAILED) {
499 printf("mmap() didn't fail as expected\n");
503 /* verify PROT_WRITE is not allowed */
510 if (p != MAP_FAILED) {
511 printf("mmap() didn't fail as expected\n");
515 /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
516 * allowed. Note that for r/w the kernel already prevents the mmap. */
523 if (p != MAP_FAILED) {
524 r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
526 printf("mmap()+mprotect() didn't fail as expected\n");
529 munmap(p, mfd_def_size);
532 /* verify PUNCH_HOLE fails */
534 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
538 printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
543 static void mfd_assert_shrink(int fd)
547 r = ftruncate(fd, mfd_def_size / 2);
549 printf("ftruncate(SHRINK) failed: %m\n");
553 mfd_assert_size(fd, mfd_def_size / 2);
555 fd2 = mfd_assert_open(fd,
556 O_RDWR | O_CREAT | O_TRUNC,
560 mfd_assert_size(fd, 0);
563 static void mfd_fail_shrink(int fd)
567 r = ftruncate(fd, mfd_def_size / 2);
569 printf("ftruncate(SHRINK) didn't fail as expected\n");
574 O_RDWR | O_CREAT | O_TRUNC,
578 static void mfd_assert_grow(int fd)
582 r = ftruncate(fd, mfd_def_size * 2);
584 printf("ftruncate(GROW) failed: %m\n");
588 mfd_assert_size(fd, mfd_def_size * 2);
595 printf("fallocate(ALLOC) failed: %m\n");
599 mfd_assert_size(fd, mfd_def_size * 4);
602 static void mfd_fail_grow(int fd)
606 r = ftruncate(fd, mfd_def_size * 2);
608 printf("ftruncate(GROW) didn't fail as expected\n");
617 printf("fallocate(ALLOC) didn't fail as expected\n");
622 static void mfd_assert_grow_write(int fd)
627 /* hugetlbfs does not support write */
631 buf = malloc(mfd_def_size * 8);
633 printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
637 l = pwrite(fd, buf, mfd_def_size * 8, 0);
638 if (l != (mfd_def_size * 8)) {
639 printf("pwrite() failed: %m\n");
643 mfd_assert_size(fd, mfd_def_size * 8);
646 static void mfd_fail_grow_write(int fd)
651 /* hugetlbfs does not support write */
655 buf = malloc(mfd_def_size * 8);
657 printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
661 l = pwrite(fd, buf, mfd_def_size * 8, 0);
662 if (l == (mfd_def_size * 8)) {
663 printf("pwrite() didn't fail as expected\n");
668 static void mfd_assert_mode(int fd, int mode)
674 fd2name(fd, buf, PATH_MAX);
676 if (fstat(fd, &st) < 0) {
677 printf("fstat(%s) failed: %m\n", buf);
681 if ((st.st_mode & 07777) != mode) {
682 printf("fstat(%s) wrong file mode 0%04o, but expected 0%04o\n",
683 buf, (int)st.st_mode & 07777, mode);
688 static void mfd_assert_chmod(int fd, int mode)
693 fd2name(fd, buf, PATH_MAX);
695 if (fchmod(fd, mode) < 0) {
696 printf("fchmod(%s, 0%04o) failed: %m\n", buf, mode);
700 mfd_assert_mode(fd, mode);
703 static void mfd_fail_chmod(int fd, int mode)
709 fd2name(fd, buf, PATH_MAX);
711 if (fstat(fd, &st) < 0) {
712 printf("fstat(%s) failed: %m\n", buf);
716 if (fchmod(fd, mode) == 0) {
717 printf("fchmod(%s, 0%04o) didn't fail as expected\n",
722 /* verify that file mode bits did not change */
723 mfd_assert_mode(fd, st.st_mode & 07777);
726 static int idle_thread_fn(void *arg)
731 /* dummy waiter; SIGTERM terminates us anyway */
733 sigaddset(&set, SIGTERM);
739 static pid_t spawn_idle_thread(unsigned int flags)
744 stack = malloc(STACK_SIZE);
746 printf("malloc(STACK_SIZE) failed: %m\n");
750 pid = clone(idle_thread_fn,
755 printf("clone() failed: %m\n");
762 static void join_idle_thread(pid_t pid)
765 waitpid(pid, NULL, 0);
769 * Test memfd_create() syscall
770 * Verify syscall-argument validation, including name checks, flag validation
773 static void test_create(void)
778 printf("%s CREATE\n", memfd_str);
781 mfd_fail_new(NULL, 0);
783 /* test over-long name (not zero-terminated) */
784 memset(buf, 0xff, sizeof(buf));
785 mfd_fail_new(buf, 0);
787 /* test over-long zero-terminated name */
788 memset(buf, 0xff, sizeof(buf));
789 buf[sizeof(buf) - 1] = 0;
790 mfd_fail_new(buf, 0);
792 /* verify "" is a valid name */
793 fd = mfd_assert_new("", 0, 0);
796 /* verify invalid O_* open flags */
797 mfd_fail_new("", 0x0100);
798 mfd_fail_new("", ~MFD_CLOEXEC);
799 mfd_fail_new("", ~MFD_ALLOW_SEALING);
800 mfd_fail_new("", ~0);
801 mfd_fail_new("", 0x80000000U);
803 /* verify EXEC and NOEXEC_SEAL can't both be set */
804 mfd_fail_new("", MFD_EXEC | MFD_NOEXEC_SEAL);
806 /* verify MFD_CLOEXEC is allowed */
807 fd = mfd_assert_new("", 0, MFD_CLOEXEC);
810 /* verify MFD_ALLOW_SEALING is allowed */
811 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
814 /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
815 fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
821 * A very basic sealing test to see whether setting/retrieving seals works.
823 static void test_basic(void)
827 printf("%s BASIC\n", memfd_str);
829 fd = mfd_assert_new("kern_memfd_basic",
831 MFD_CLOEXEC | MFD_ALLOW_SEALING);
833 /* add basic seals */
834 mfd_assert_has_seals(fd, 0);
835 mfd_assert_add_seals(fd, F_SEAL_SHRINK |
837 mfd_assert_has_seals(fd, F_SEAL_SHRINK |
841 mfd_assert_add_seals(fd, F_SEAL_SHRINK |
843 mfd_assert_has_seals(fd, F_SEAL_SHRINK |
846 /* add more seals and seal against sealing */
847 mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
848 mfd_assert_has_seals(fd, F_SEAL_SHRINK |
853 /* verify that sealing no longer works */
854 mfd_fail_add_seals(fd, F_SEAL_GROW);
855 mfd_fail_add_seals(fd, 0);
859 /* verify sealing does not work without MFD_ALLOW_SEALING */
860 fd = mfd_assert_new("kern_memfd_basic",
863 mfd_assert_has_seals(fd, F_SEAL_SEAL);
864 mfd_fail_add_seals(fd, F_SEAL_SHRINK |
867 mfd_assert_has_seals(fd, F_SEAL_SEAL);
873 * Test whether SEAL_WRITE actually prevents modifications.
875 static void test_seal_write(void)
879 printf("%s SEAL-WRITE\n", memfd_str);
881 fd = mfd_assert_new("kern_memfd_seal_write",
883 MFD_CLOEXEC | MFD_ALLOW_SEALING);
884 mfd_assert_has_seals(fd, 0);
885 mfd_assert_add_seals(fd, F_SEAL_WRITE);
886 mfd_assert_has_seals(fd, F_SEAL_WRITE);
890 mfd_assert_shrink(fd);
892 mfd_fail_grow_write(fd);
898 * Test SEAL_FUTURE_WRITE
899 * Test whether SEAL_FUTURE_WRITE actually prevents modifications.
901 static void test_seal_future_write(void)
906 printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
908 fd = mfd_assert_new("kern_memfd_seal_future_write",
910 MFD_CLOEXEC | MFD_ALLOW_SEALING);
912 p = mfd_assert_mmap_shared(fd);
914 mfd_assert_has_seals(fd, 0);
916 mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
917 mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
919 /* read should pass, writes should fail */
921 mfd_assert_read_shared(fd);
924 fd2 = mfd_assert_reopen_fd(fd);
925 /* read should pass, writes should still fail */
926 mfd_assert_read(fd2);
927 mfd_assert_read_shared(fd2);
930 mfd_assert_fork_private_write(fd);
932 munmap(p, mfd_def_size);
939 * Test whether SEAL_SHRINK actually prevents shrinking
941 static void test_seal_shrink(void)
945 printf("%s SEAL-SHRINK\n", memfd_str);
947 fd = mfd_assert_new("kern_memfd_seal_shrink",
949 MFD_CLOEXEC | MFD_ALLOW_SEALING);
950 mfd_assert_has_seals(fd, 0);
951 mfd_assert_add_seals(fd, F_SEAL_SHRINK);
952 mfd_assert_has_seals(fd, F_SEAL_SHRINK);
955 mfd_assert_write(fd);
958 mfd_assert_grow_write(fd);
965 * Test whether SEAL_GROW actually prevents growing
967 static void test_seal_grow(void)
971 printf("%s SEAL-GROW\n", memfd_str);
973 fd = mfd_assert_new("kern_memfd_seal_grow",
975 MFD_CLOEXEC | MFD_ALLOW_SEALING);
976 mfd_assert_has_seals(fd, 0);
977 mfd_assert_add_seals(fd, F_SEAL_GROW);
978 mfd_assert_has_seals(fd, F_SEAL_GROW);
981 mfd_assert_write(fd);
982 mfd_assert_shrink(fd);
984 mfd_fail_grow_write(fd);
990 * Test SEAL_SHRINK | SEAL_GROW
991 * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
993 static void test_seal_resize(void)
997 printf("%s SEAL-RESIZE\n", memfd_str);
999 fd = mfd_assert_new("kern_memfd_seal_resize",
1001 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1002 mfd_assert_has_seals(fd, 0);
1003 mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
1004 mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
1006 mfd_assert_read(fd);
1007 mfd_assert_write(fd);
1008 mfd_fail_shrink(fd);
1010 mfd_fail_grow_write(fd);
1017 * Test fd is created with exec and allow sealing.
1018 * chmod() cannot change x bits after sealing.
1020 static void test_exec_seal(void)
1024 printf("%s SEAL-EXEC\n", memfd_str);
1026 printf("%s Apply SEAL_EXEC\n", memfd_str);
1027 fd = mfd_assert_new("kern_memfd_seal_exec",
1029 MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_EXEC);
1031 mfd_assert_mode(fd, 0777);
1032 mfd_assert_chmod(fd, 0644);
1034 mfd_assert_has_seals(fd, 0);
1035 mfd_assert_add_seals(fd, F_SEAL_EXEC);
1036 mfd_assert_has_seals(fd, F_SEAL_EXEC);
1038 mfd_assert_chmod(fd, 0600);
1039 mfd_fail_chmod(fd, 0777);
1040 mfd_fail_chmod(fd, 0670);
1041 mfd_fail_chmod(fd, 0605);
1042 mfd_fail_chmod(fd, 0700);
1043 mfd_fail_chmod(fd, 0100);
1044 mfd_assert_chmod(fd, 0666);
1045 mfd_assert_write(fd);
1048 printf("%s Apply ALL_SEALS\n", memfd_str);
1049 fd = mfd_assert_new("kern_memfd_seal_exec",
1051 MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_EXEC);
1053 mfd_assert_mode(fd, 0777);
1054 mfd_assert_chmod(fd, 0700);
1056 mfd_assert_has_seals(fd, 0);
1057 mfd_assert_add_seals(fd, F_SEAL_EXEC);
1058 mfd_assert_has_seals(fd, F_WX_SEALS);
1060 mfd_fail_chmod(fd, 0711);
1061 mfd_fail_chmod(fd, 0600);
1068 * Test fd is created with exec and not allow sealing.
1070 static void test_exec_no_seal(void)
1074 printf("%s EXEC_NO_SEAL\n", memfd_str);
1076 /* Create with EXEC but without ALLOW_SEALING */
1077 fd = mfd_assert_new("kern_memfd_exec_no_sealing",
1079 MFD_CLOEXEC | MFD_EXEC);
1080 mfd_assert_mode(fd, 0777);
1081 mfd_assert_has_seals(fd, F_SEAL_SEAL);
1082 mfd_assert_chmod(fd, 0666);
1087 * Test memfd_create with MFD_NOEXEC flag
1089 static void test_noexec_seal(void)
1093 printf("%s NOEXEC_SEAL\n", memfd_str);
1095 /* Create with NOEXEC and ALLOW_SEALING */
1096 fd = mfd_assert_new("kern_memfd_noexec",
1098 MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL);
1099 mfd_assert_mode(fd, 0666);
1100 mfd_assert_has_seals(fd, F_SEAL_EXEC);
1101 mfd_fail_chmod(fd, 0777);
1104 /* Create with NOEXEC but without ALLOW_SEALING */
1105 fd = mfd_assert_new("kern_memfd_noexec",
1107 MFD_CLOEXEC | MFD_NOEXEC_SEAL);
1108 mfd_assert_mode(fd, 0666);
1109 mfd_assert_has_seals(fd, F_SEAL_EXEC);
1110 mfd_fail_chmod(fd, 0777);
1114 static void test_sysctl_child(void)
1119 printf("%s sysctl 0\n", memfd_str);
1120 sysctl_assert_write("0");
1121 fd = mfd_assert_new("kern_memfd_sysctl_0",
1123 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1125 mfd_assert_mode(fd, 0777);
1126 mfd_assert_has_seals(fd, 0);
1127 mfd_assert_chmod(fd, 0644);
1130 printf("%s sysctl 1\n", memfd_str);
1131 sysctl_assert_write("1");
1132 fd = mfd_assert_new("kern_memfd_sysctl_1",
1134 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1136 printf("%s child ns\n", memfd_str);
1137 pid = spawn_newpid_thread(CLONE_NEWPID, newpid_thread_fn2);
1138 join_newpid_thread(pid);
1140 mfd_assert_mode(fd, 0666);
1141 mfd_assert_has_seals(fd, F_SEAL_EXEC);
1142 mfd_fail_chmod(fd, 0777);
1143 sysctl_fail_write("0");
1146 printf("%s sysctl 2\n", memfd_str);
1147 sysctl_assert_write("2");
1148 mfd_fail_new("kern_memfd_sysctl_2",
1149 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1150 sysctl_fail_write("0");
1151 sysctl_fail_write("1");
1154 static int newpid_thread_fn(void *arg)
1156 test_sysctl_child();
1160 static void test_sysctl_child2(void)
1164 sysctl_fail_write("0");
1165 fd = mfd_assert_new("kern_memfd_sysctl_1",
1167 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1169 mfd_assert_mode(fd, 0666);
1170 mfd_assert_has_seals(fd, F_SEAL_EXEC);
1171 mfd_fail_chmod(fd, 0777);
1175 static int newpid_thread_fn2(void *arg)
1177 test_sysctl_child2();
1180 static pid_t spawn_newpid_thread(unsigned int flags, int (*fn)(void *))
1185 stack = malloc(STACK_SIZE);
1187 printf("malloc(STACK_SIZE) failed: %m\n");
1196 printf("clone() failed: %m\n");
1203 static void join_newpid_thread(pid_t pid)
1205 waitpid(pid, NULL, 0);
1210 * A very basic sealing test to see whether setting/retrieving seals works.
1212 static void test_sysctl(void)
1214 int pid = spawn_newpid_thread(CLONE_NEWPID, newpid_thread_fn);
1216 join_newpid_thread(pid);
1220 * Test sharing via dup()
1221 * Test that seals are shared between dupped FDs and they're all equal.
1223 static void test_share_dup(char *banner, char *b_suffix)
1227 printf("%s %s %s\n", memfd_str, banner, b_suffix);
1229 fd = mfd_assert_new("kern_memfd_share_dup",
1231 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1232 mfd_assert_has_seals(fd, 0);
1234 fd2 = mfd_assert_dup(fd);
1235 mfd_assert_has_seals(fd2, 0);
1237 mfd_assert_add_seals(fd, F_SEAL_WRITE);
1238 mfd_assert_has_seals(fd, F_SEAL_WRITE);
1239 mfd_assert_has_seals(fd2, F_SEAL_WRITE);
1241 mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
1242 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
1243 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
1245 mfd_assert_add_seals(fd, F_SEAL_SEAL);
1246 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
1247 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
1249 mfd_fail_add_seals(fd, F_SEAL_GROW);
1250 mfd_fail_add_seals(fd2, F_SEAL_GROW);
1251 mfd_fail_add_seals(fd, F_SEAL_SEAL);
1252 mfd_fail_add_seals(fd2, F_SEAL_SEAL);
1256 mfd_fail_add_seals(fd, F_SEAL_GROW);
1261 * Test sealing with active mmap()s
1262 * Modifying seals is only allowed if no other mmap() refs exist.
1264 static void test_share_mmap(char *banner, char *b_suffix)
1269 printf("%s %s %s\n", memfd_str, banner, b_suffix);
1271 fd = mfd_assert_new("kern_memfd_share_mmap",
1273 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1274 mfd_assert_has_seals(fd, 0);
1276 /* shared/writable ref prevents sealing WRITE, but allows others */
1277 p = mfd_assert_mmap_shared(fd);
1278 mfd_fail_add_seals(fd, F_SEAL_WRITE);
1279 mfd_assert_has_seals(fd, 0);
1280 mfd_assert_add_seals(fd, F_SEAL_SHRINK);
1281 mfd_assert_has_seals(fd, F_SEAL_SHRINK);
1282 munmap(p, mfd_def_size);
1284 /* readable ref allows sealing */
1285 p = mfd_assert_mmap_private(fd);
1286 mfd_assert_add_seals(fd, F_SEAL_WRITE);
1287 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
1288 munmap(p, mfd_def_size);
1294 * Test sealing with open(/proc/self/fd/%d)
1295 * Via /proc we can get access to a separate file-context for the same memfd.
1296 * This is *not* like dup(), but like a real separate open(). Make sure the
1297 * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
1299 static void test_share_open(char *banner, char *b_suffix)
1303 printf("%s %s %s\n", memfd_str, banner, b_suffix);
1305 fd = mfd_assert_new("kern_memfd_share_open",
1307 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1308 mfd_assert_has_seals(fd, 0);
1310 fd2 = mfd_assert_open(fd, O_RDWR, 0);
1311 mfd_assert_add_seals(fd, F_SEAL_WRITE);
1312 mfd_assert_has_seals(fd, F_SEAL_WRITE);
1313 mfd_assert_has_seals(fd2, F_SEAL_WRITE);
1315 mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
1316 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
1317 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
1320 fd = mfd_assert_open(fd2, O_RDONLY, 0);
1322 mfd_fail_add_seals(fd, F_SEAL_SEAL);
1323 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
1324 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
1327 fd2 = mfd_assert_open(fd, O_RDWR, 0);
1329 mfd_assert_add_seals(fd2, F_SEAL_SEAL);
1330 mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
1331 mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
1338 * Test sharing via fork()
1339 * Test whether seal-modifications work as expected with forked childs.
1341 static void test_share_fork(char *banner, char *b_suffix)
1346 printf("%s %s %s\n", memfd_str, banner, b_suffix);
1348 fd = mfd_assert_new("kern_memfd_share_fork",
1350 MFD_CLOEXEC | MFD_ALLOW_SEALING);
1351 mfd_assert_has_seals(fd, 0);
1353 pid = spawn_idle_thread(0);
1354 mfd_assert_add_seals(fd, F_SEAL_SEAL);
1355 mfd_assert_has_seals(fd, F_SEAL_SEAL);
1357 mfd_fail_add_seals(fd, F_SEAL_WRITE);
1358 mfd_assert_has_seals(fd, F_SEAL_SEAL);
1360 join_idle_thread(pid);
1362 mfd_fail_add_seals(fd, F_SEAL_WRITE);
1363 mfd_assert_has_seals(fd, F_SEAL_SEAL);
1368 int main(int argc, char **argv)
1373 if (!strcmp(argv[1], "hugetlbfs")) {
1374 unsigned long hpage_size = default_huge_page_size();
1377 printf("Unable to determine huge page size\n");
1382 memfd_str = MEMFD_HUGE_STR;
1383 mfd_def_size = hpage_size * 2;
1385 printf("Unknown option: %s\n", argv[1]);
1393 test_exec_no_seal();
1397 test_seal_future_write();
1402 test_share_dup("SHARE-DUP", "");
1403 test_share_mmap("SHARE-MMAP", "");
1404 test_share_open("SHARE-OPEN", "");
1405 test_share_fork("SHARE-FORK", "");
1407 /* Run test-suite in a multi-threaded environment with a shared
1409 pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
1410 test_share_dup("SHARE-DUP", SHARED_FT_STR);
1411 test_share_mmap("SHARE-MMAP", SHARED_FT_STR);
1412 test_share_open("SHARE-OPEN", SHARED_FT_STR);
1413 test_share_fork("SHARE-FORK", SHARED_FT_STR);
1414 join_idle_thread(pid);
1418 printf("memfd: DONE\n");