13#include <sys/resource.h>
17static int64_t now(
void) {
19 return clock_gettime(CLOCK_MONOTONIC, &time) ? -1
20 : (int64_t)time.tv_sec * 1000000000 + time.tv_nsec;
23int rp_reap(pid_t child,
int milliseconds) {
24 int64_t begin = now();
25 int64_t deadline = begin + (int64_t)milliseconds * 1000000;
26 while (begin >= 0 && (begin = now()) >= 0 && begin < deadline) {
28 pid_t result = waitpid(child, &status, WNOHANG);
30 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
31 if (result < 0 && errno != EINTR)
33 struct timespec pause = {0, 5000000};
34 nanosleep(&pause, NULL);
37 while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
42int rp_send(
int fd,
char byte) {
45 result = write(fd, &
byte, 1);
46 }
while (result < 0 && errno == EINTR);
47 return result == 1 ? 0 : -1;
50int rp_receive(
int fd,
char expected) {
51 int64_t begin = now(), deadline = begin + 5000000000;
52 while (begin >= 0 && (begin = now()) >= 0 && begin < deadline) {
53 struct pollfd watch = {.fd = fd, .events = POLLIN};
54 int result = poll(&watch, 1, 100);
55 if (result < 0 && errno == EINTR)
62 ssize_t amount = read(fd, &
byte, 1);
63 if (amount < 0 && errno == EINTR)
65 if (amount == 1 &&
byte == expected)
74static void expected_fault(
int signal) {
79int rp_fault(
void* address,
int expected_signal,
int write_access) {
85 struct sigaction action = {.sa_handler = expected_fault};
86 sigemptyset(&action.sa_mask);
87 if (sigaction(expected_signal, &action, NULL))
89 volatile unsigned char*
byte = address;
93 volatile unsigned char value = *byte;
98 int result = rp_reap(child, 4000);
100 fprintf(stderr,
"REMAP-FILE-PAGES-CONTRACT: expected signal=%d address=%p write=%d status=%d\n",
101 expected_signal, address, write_access, result);
105unsigned char rp_pattern(
size_t offset) {
106 return (
unsigned char)(0x31 + (offset / rp_page) * 23 + (offset % rp_page) * 37 +
107 ((offset % rp_page) >> 8) * 11);
110int rp_matches(
const volatile unsigned char* bytes,
size_t offset,
size_t length,
int zero) {
111 for (
size_t n = 0; n < length; ++n) {
112 unsigned char expected = zero ? 0 : rp_pattern(offset + n);
113 unsigned char actual = bytes[n];
114 if (actual != expected) {
115 fprintf(stderr,
"REMAP-FILE-PAGES-CONTRACT: offset=%zu got=%u expected=%u\n", offset + n,
116 (
unsigned)actual, (
unsigned)expected);
123int rp_contents(
int fd,
size_t offset,
size_t length,
int zero) {
124 unsigned char bytes[512];
126 size_t amount = length <
sizeof(bytes) ? length : sizeof(bytes);
127 if (pread(fd, bytes, amount, offset) != (ssize_t)amount ||
128 !rp_matches(bytes, offset, amount, zero))
136int rp_size(
int fd,
size_t size) {
137 struct stat metadata;
138 if (fstat(fd, &metadata))
140 if (metadata.st_size == (off_t)size)
142 fprintf(stderr,
"REMAP-FILE-PAGES-CONTRACT: size=%lld expected=%zu\n",
143 (
long long)metadata.st_size, size);
147int rp_resident(
void* address,
size_t pages,
unsigned bits,
const char* stage) {
148 unsigned char vector[8];
149 memset(vector, 0xa5,
sizeof(vector));
150 if (pages >
sizeof(vector) || mincore(address, pages * rp_page, vector)) {
151 fprintf(stderr,
"REMAP-FILE-PAGES-CONTRACT: %s mincore errno=%d\n", stage, errno);
154 for (
size_t n = 0; n < pages; ++n) {
155 if ((vector[n] & 1) != ((bits >> n) & 1)) {
156 fprintf(stderr,
"REMAP-FILE-PAGES-CONTRACT: %s page=%zu resident=%u expected=%u\n", stage, n,
157 vector[n], (bits >> n) & 1);
164int rp_create(
struct rp_file* file,
int backend) {
165 static unsigned sequence;
167 file->backend = backend;
169 if (backend == RP_MEMFD)
170 file->fd = memfd_create(
"remap-file-pages", MFD_CLOEXEC | MFD_ALLOW_SEALING);
172 snprintf(file->path,
sizeof(file->path),
"%s/remap-pages-%ld-%u",
173 backend == RP_RAMFS ?
"/tmp" :
"", (long)getpid(), ++sequence);
174 file->fd = open(file->path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);
176 fprintf(stderr,
"REMAP-FILE-PAGES-CONTRACT: create %s errno=%d\n", file->path, errno);
182 unsigned char* bytes = malloc(rp_page);
183 int error = !bytes || ftruncate(file->fd, 8 * rp_page);
184 for (
size_t offset = 0; !error && offset < 8 * rp_page; offset += rp_page) {
185 for (
size_t n = 0; n < rp_page; ++n)
186 bytes[n] = rp_pattern(offset + n);
187 error = pwrite(file->fd, bytes, rp_page, offset) != (ssize_t)rp_page;
199int rp_open_alias(
const struct rp_file* file) {
200 if (file->backend == RP_EXT2) {
202 snprintf(alias,
sizeof(alias),
"%s.alias", file->path);
203 if (link(file->path, alias))
205 int fd = open(alias, O_RDWR | O_CLOEXEC);
216 return file->path[0] ? open(file->path, O_RDWR | O_CLOEXEC) : dup(file->fd);
219void rp_close(
struct rp_file* file) {
228int rp_limit(
size_t bytes) {
230 if (getrlimit(RLIMIT_MEMLOCK, &limit))
232 limit.rlim_cur = bytes;
233 return setrlimit(RLIMIT_MEMLOCK, &limit);
236int rp_unprivileged(
void) {
237 if (!geteuid() && (setgroups(0, NULL) || setgid(65534) || setuid(65534)))