16 return clock_gettime(CLOCK_MONOTONIC, &now) ? -1 : (int64_t)now.tv_sec * 1000000000 + now.tv_nsec;
18void mf_pause(
int milliseconds) {
19 struct timespec pause = {milliseconds / 1000, (milliseconds % 1000) * 1000000L};
20 while (nanosleep(&pause, &pause) && errno == EINTR) {
23int mf_wait(
volatile int* flag,
int milliseconds) {
24 const int64_t until = mf_now() + (int64_t)milliseconds * 1000000;
25 while (!__atomic_load_n(flag, __ATOMIC_ACQUIRE)) {
26 if (mf_now() >= until)
32int mf_reap(pid_t child,
int milliseconds) {
33 const int64_t until = mf_now() + (int64_t)milliseconds * 1000000;
34 while (mf_now() < until) {
36 pid_t result = waitpid(child, &status, WNOHANG);
37 if (result == child) {
38 int code = WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
40 fprintf(stderr,
"MEMFD-CONTRACT: child=%ld status=%d\n", (
long)child, code);
43 if (result < 0 && errno != EINTR)
47 fprintf(stderr,
"MEMFD-CONTRACT: child=%ld timeout\n", (
long)child);
49 while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
53int mf_byte(
int socket,
char expected) {
54 struct pollfd entry = {.fd = socket, .events = POLLIN};
57 result = poll(&entry, 1, 5000);
58 while (result < 0 && errno == EINTR);
60 return result > 0 && read(socket, &
byte, 1) == 1 &&
byte == expected ? 0 : -1;
62int mf_send_fd(
int socket,
int fd) {
64 struct iovec vector = {&byte, 1};
67 char bytes[CMSG_SPACE(
sizeof(
int))];
69 struct msghdr
message = {.msg_iov = &vector,
71 .msg_control = control.bytes,
72 .msg_controllen =
sizeof(control.bytes)};
73 struct cmsghdr* item = CMSG_FIRSTHDR(&
message);
74 item->cmsg_level = SOL_SOCKET;
75 item->cmsg_type = SCM_RIGHTS;
76 item->cmsg_len = CMSG_LEN(
sizeof(
int));
77 memcpy(CMSG_DATA(item), &fd,
sizeof(fd));
78 return sendmsg(socket, &
message, 0) == 1 ? 0 : -1;
80int mf_receive_fd(
int socket) {
82 struct iovec vector = {&byte, 1};
85 char bytes[CMSG_SPACE(
sizeof(
int))];
87 struct msghdr
message = {.msg_iov = &vector,
89 .msg_control = control.bytes,
90 .msg_controllen =
sizeof(control.bytes)};
91 if (recvmsg(socket, &
message, MSG_CMSG_CLOEXEC) != 1 || (
message.msg_flags & MSG_CTRUNC))
93 struct cmsghdr* item = CMSG_FIRSTHDR(&
message);
94 if (!item || item->cmsg_level != SOL_SOCKET || item->cmsg_type != SCM_RIGHTS ||
95 item->cmsg_len != CMSG_LEN(
sizeof(
int)))
98 memcpy(&fd, CMSG_DATA(item),
sizeof(fd));
101int mf_make(
size_t bytes) {
102 int fd = memfd_create(
"contract", MFD_ALLOW_SEALING);
103 if (fd >= 0 && ftruncate(fd, bytes)) {
109int mf_size(
int fd, off_t expected) {
111 return !fstat(fd, &st) && st.st_size == expected ? 0 : -1;
113int mf_contents(
int fd, off_t offset,
const void* expected,
size_t length) {
115 return length <=
sizeof(bytes) && pread(fd, bytes, length, offset) == (ssize_t)length &&
116 !memcmp(bytes, expected, length)
120static int run(
const char* name,
int (*test)(
void)) {
121 printf(
"MEMFD-CONTRACT: BEGIN %s\n", name);
123 pid_t child = fork();
131 _exit(result ? 1 : 0);
133 const int status = mf_reap(child, 45000);
134 printf(
"MEMFD-CONTRACT: %s %s status=%d\n", status ?
"FAIL" :
"PASS", name, status);
138int main(
int argc,
char** argv) {
139 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
141 if (argc > 1 && !strcmp(argv[1],
"memfd-exec"))
142 return memfd_exec(argc, argv);
146 } suites[] = {{
"creation", memfd_creation},
147 {
"seals", memfd_seals},
148 {
"mappings", memfd_mappings},
149 {
"lifetime", memfd_lifetime},
150 {
"races", memfd_races}};
152 for (
unsigned n = 0; n <
sizeof(suites) /
sizeof(suites[0]); ++n) {
153 if (argc > 1 && strcmp(argv[1], suites[n].name))
156 if (run(suites[n].name, suites[n].test))
161 puts(
"MEMFD-CONTRACT: END PASS");