11static int fork_seals(
void) {
12 int failed = 0, fd = -1, alias = -1, pair[2] = {-1, -1};
14 CHECK((fd = mf_make(32)) >= 0 && (alias = dup(fd)) >= 0);
15 CHECK(pwrite(fd,
"a", 1, 0) == 1);
16 CHECK(!socketpair(AF_UNIX, SOCK_STREAM, 0, pair));
17 CHECK((child = fork()) >= 0);
22 if (write(pair[1],
"r", 1) != 1 || mf_byte(pair[1],
'g'))
24 if (fcntl(alias, F_GET_SEALS) != F_SEAL_GROW || fcntl(alias, F_ADD_SEALS, F_SEAL_SHRINK) ||
25 pwrite(alias,
"b", 1, 0) != 1)
27 _exit(write(pair[1],
"s", 1) == 1 ? 0 : 12);
31 CHECK(!mf_byte(pair[0],
'r'));
32 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_GROW));
33 CHECK(write(pair[0],
"g", 1) == 1 && !mf_byte(pair[0],
's'));
34 CHECK(fcntl(fd, F_GET_SEALS) == (F_SEAL_GROW | F_SEAL_SHRINK));
35 CHECK(fcntl(alias, F_GET_SEALS) == (F_SEAL_GROW | F_SEAL_SHRINK));
36 CHECK(!mf_contents(fd, 0,
"b", 1));
37 const int status = mf_reap(child, 5000);
55static int queued_rights(
void) {
56 int failed = 0, fd = -1, received = -1, pair[2] = {-1, -1}, gate[2] = {-1, -1};
58 CHECK((fd = mf_make(32)) >= 0 && pwrite(fd,
"queue", 5, 0) == 5);
59 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_GROW));
60 CHECK(!socketpair(AF_UNIX, SOCK_STREAM, 0, pair) && !socketpair(AF_UNIX, SOCK_STREAM, 0, gate));
61 CHECK((child = fork()) >= 0);
67 if (write(gate[1],
"r", 1) != 1 || mf_byte(gate[1],
'g'))
69 int transferred = mf_receive_fd(pair[1]);
70 if (transferred < 0 || fcntl(transferred, F_GETFD) != FD_CLOEXEC ||
71 fcntl(transferred, F_GET_SEALS) != F_SEAL_GROW || mf_contents(transferred, 0,
"queue", 5) ||
72 fcntl(transferred, F_ADD_SEALS, F_SEAL_SHRINK) || mf_send_fd(pair[1], transferred))
75 _exit(write(gate[1],
"s", 1) == 1 ? 0 : 22);
81 CHECK(!mf_byte(gate[0],
'r') && !mf_send_fd(pair[0], fd));
85 CHECK(write(gate[0],
"g", 1) == 1 && !mf_byte(gate[0],
's'));
86 CHECK((received = mf_receive_fd(pair[0])) >= 0);
87 CHECK(fcntl(received, F_GET_SEALS) == (F_SEAL_GROW | F_SEAL_SHRINK));
88 CHECK(!mf_contents(received, 0,
"queue", 5));
89 CHECK(ftruncate(received, 31) == -1 && errno == EPERM);
90 const int status = mf_reap(child, 5000);
98 for (
int n = 0; n < 2; ++n) {
110static int child_capability(
int explicit_unmap) {
111 int failed = 0, fd = -1, pair[2] = {-1, -1};
112 const size_t page = sysconf(_SC_PAGESIZE);
113 char* mapping = MAP_FAILED;
115 CHECK((fd = mf_make(page)) >= 0);
116 mapping = mmap(NULL, page, PROT_READ, MAP_SHARED, fd, 0);
117 CHECK(mapping != MAP_FAILED && !socketpair(AF_UNIX, SOCK_STREAM, 0, pair));
118 CHECK((child = fork()) >= 0);
123 if (write(pair[1],
"r", 1) != 1 || mf_byte(pair[1],
'g') ||
124 mprotect(mapping, page, PROT_READ | PROT_WRITE))
127 if (write(pair[1],
"w", 1) != 1 || mf_byte(pair[1],
'u'))
129 if (explicit_unmap &&
130 (munmap(mapping, page) || write(pair[1],
"u", 1) != 1 || mf_byte(pair[1],
'q')))
136 CHECK(!mf_byte(pair[0],
'r'));
137 CHECK(!munmap(mapping, page));
138 mapping = MAP_FAILED;
139 CHECK(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_SHRINK) == -1 && errno == EBUSY);
140 CHECK(fcntl(fd, F_GET_SEALS) == 0 && !fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE));
141 CHECK(write(pair[0],
"g", 1) == 1 && !mf_byte(pair[0],
'w'));
142 CHECK(!mf_contents(fd, 0,
"c", 1));
143 CHECK(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1 && errno == EBUSY);
144 CHECK(write(pair[0],
"u", 1) == 1);
145 if (explicit_unmap) {
146 CHECK(!mf_byte(pair[0],
'u'));
147 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE));
148 CHECK(write(pair[0],
"q", 1) == 1);
150 const int status = mf_reap(child, 5000);
153 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE));
154 CHECK(fcntl(fd, F_GET_SEALS) == (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE));
157 kill(child, SIGKILL);
158 mf_reap(child, 1000);
164 if (mapping != MAP_FAILED)
165 munmap(mapping, page);
170static int mapped_last_close(
void) {
171 int failed = 0, fd = -1;
172 const size_t page = sysconf(_SC_PAGESIZE);
173 char *mapping = MAP_FAILED, *alias = MAP_FAILED, *target = MAP_FAILED, *
private = MAP_FAILED;
174 size_t length = 2 * page;
176 CHECK((fd = mf_make(3 * page)) >= 0 && pwrite(fd,
"last", 4, 0) == 4);
177 mapping = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
178 alias = mmap(NULL, page, PROT_READ, MAP_SHARED, fd, 0);
179 CHECK(mapping != MAP_FAILED && alias != MAP_FAILED);
180 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE));
181 private = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
182 CHECK(
private != MAP_FAILED);
186 CHECK(!memcmp(alias,
"last", 4));
187 target = mmap(NULL, 3 * page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
188 CHECK(target != MAP_FAILED);
189 char* moved = mremap(mapping, length, 3 * page, MREMAP_MAYMOVE | MREMAP_FIXED, target);
190 CHECK(moved == target);
194 CHECK(!madvise(mapping, length, MADV_DONTNEED) && !memcmp(mapping,
"last", 4));
196 mapping[2 * page] =
'g';
197 CHECK(alias[0] ==
'L');
198 CHECK(!madvise(mapping, length, MADV_DONTNEED));
199 CHECK(mapping[0] ==
'L' && mapping[2 * page] ==
'g');
200 CHECK((child = fork()) >= 0);
203 if (
private[0] !=
'p' || mapping[0] !=
'L' || mapping[2 * page] !=
'g')
207 _exit(
private[0] ==
'c' && alias[0] ==
'F' ? 0 : 36);
209 const int status = mf_reap(child, 5000);
211 CHECK(!status &&
private[0] ==
'p' && alias[0] ==
'F' && mapping[0] ==
'F');
214 kill(child, SIGKILL);
215 mf_reap(child, 1000);
217 if (
private != MAP_FAILED)
218 munmap(
private, page);
219 if (target != MAP_FAILED)
220 munmap(target, 3 * page);
221 if (alias != MAP_FAILED)
223 if (mapping != MAP_FAILED)
224 munmap(mapping, length);
229int memfd_exec(
int argc,
char** argv) {
232 const int closed = atoi(argv[2]), retained = atoi(argv[3]);
233 if (fcntl(closed, F_GETFD) != -1 || errno != EBADF || fcntl(retained, F_GETFD) != 0 ||
234 fcntl(retained, F_GET_SEALS) != (F_SEAL_GROW | F_SEAL_SHRINK) ||
235 mf_contents(retained, 0,
"exec", 4))
237 if (fcntl(retained, F_ADD_SEALS, F_SEAL_WRITE))
239 return close(retained) ? 43 : 0;
241static int exec_lifetime(
void) {
242 int failed = 0, fd = -1, alias = -1;
244 char closed[24], retained[24];
245 CHECK((fd = memfd_create(
"exec", MFD_ALLOW_SEALING | MFD_CLOEXEC)) >= 0);
246 CHECK(write(fd,
"exec", 4) == 4 && (alias = dup(fd)) >= 0);
247 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK));
248 snprintf(closed,
sizeof(closed),
"%d", fd);
249 snprintf(retained,
sizeof(retained),
"%d", alias);
250 CHECK((child = fork()) >= 0);
253 execl(MEMFD_APP, MEMFD_APP,
"memfd-exec", closed, retained, (
char*)NULL);
256 const int status = mf_reap(child, 6000);
259 CHECK(fcntl(fd, F_GET_SEALS) == (F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_WRITE));
262 kill(child, SIGKILL);
263 mf_reap(child, 1000);
271int memfd_lifetime(
void) {
272 return fork_seals() || queued_rights() || child_capability(1) || child_capability(0) ||
273 mapped_last_close() || exec_lifetime();