11#include <sys/resource.h>
16static int64_t now(
void) {
18 return clock_gettime(CLOCK_MONOTONIC, &time) ? -1
19 : (int64_t)time.tv_sec * 1000000000 + time.tv_nsec;
22int ml_reap(pid_t child,
int milliseconds) {
23 int64_t deadline = now() + (int64_t)milliseconds * 1000000;
24 while (now() < deadline) {
26 pid_t result = waitpid(child, &status, WNOHANG);
28 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
29 if (result < 0 && errno != EINTR)
31 struct timespec pause = {0, 5000000};
32 nanosleep(&pause, NULL);
35 while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
40int ml_send(
int fd,
char byte) {
43 result = write(fd, &
byte, 1);
44 }
while (result < 0 && errno == EINTR);
45 return result == 1 ? 0 : -1;
48int ml_receive(
int fd,
char expected) {
49 int64_t deadline = now() + 5000000000;
50 while (now() < deadline) {
51 struct pollfd watch = {.fd = fd, .events = POLLIN};
52 int result = poll(&watch, 1, 100);
53 if (result < 0 && errno == EINTR)
60 ssize_t amount = read(fd, &
byte, 1);
61 if (amount < 0 && errno == EINTR)
63 if (amount == 1 &&
byte == expected)
72int ml_limit(
size_t bytes) {
74 if (getrlimit(RLIMIT_MEMLOCK, &limit))
76 limit.rlim_cur = bytes;
77 return setrlimit(RLIMIT_MEMLOCK, &limit);
80int ml_unprivileged(
void) {
81 if (!geteuid() && (setgroups(0, NULL) || setgid(65534) || setuid(65534)))
89int ml_resident(
void* address,
size_t pages,
unsigned bits,
const char* stage) {
90 unsigned char vector[8];
91 memset(vector, 0xa5,
sizeof(vector));
92 if (pages >
sizeof(vector) || mincore(address, pages * ml_page, vector)) {
93 fprintf(stderr,
"MEMORY-LOCK-CONTRACT: %s mincore failed errno=%d\n", stage, errno);
96 for (
size_t n = 0; n < pages; ++n) {
97 if ((vector[n] & 1) != ((bits >> n) & 1)) {
98 fprintf(stderr,
"MEMORY-LOCK-CONTRACT: %s page=%zu resident=%u expected=%u\n", stage, n,
99 vector[n], (bits >> n) & 1);
106static int run(
const char* name,
int (*function)(
void)) {
107 printf(
"MEMORY-LOCK-CONTRACT: BEGIN %s\n", name);
109 pid_t child = fork();
114 int result = function();
117 _exit(result ? 1 : 0);
119 int result = ml_reap(child, 45000);
120 printf(
"MEMORY-LOCK-CONTRACT: %s %s status=%d\n", result ?
"FAIL" :
"PASS", name, result);
125int main(
int argc,
char** argv) {
126 ml_page = (size_t)sysconf(_SC_PAGESIZE);
127 if (ml_page < 512 || ml_page > 65536 || (ml_page & (ml_page - 1)))
129 if (argc > 1 && !strcmp(argv[1],
"memory-lock-exec"))
130 return ml_exec(argc, argv);
131 signal(SIGPIPE, SIG_IGN);
132 static const struct {
134 int (*function)(void);
135 } suites[] = {{
"limits", ml_limits},
136 {
"ranges", ml_ranges},
137 {
"managed", ml_managed},
139 {
"lifetime", ml_lifetime}};
141 for (
size_t n = 0; n <
sizeof(suites) /
sizeof(suites[0]); ++n) {
142 if (argc > 1 && strcmp(argv[1], suites[n].name))
145 if (run(suites[n].name, suites[n].function))
150 puts(
"MEMORY-LOCK-CONTRACT: END PASS");