16 return clock_gettime(CLOCK_MONOTONIC, &now) ? -1 : (int64_t)now.tv_sec * 1000000000 + now.tv_nsec;
18int pm_reap(pid_t pid,
int milliseconds) {
19 int64_t start = pm_now(), now, deadline = start + (int64_t)milliseconds * 1000000;
20 while (start >= 0 && (now = pm_now()) >= 0 && now < deadline) {
22 pid_t result = waitpid(pid, &status, WNOHANG);
24 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
25 if (result < 0 && errno != EINTR)
27 struct timespec pause = {0, 5000000};
28 nanosleep(&pause, NULL);
31 while (waitpid(pid, NULL, 0) < 0 && errno == EINTR) {
35int pm_read(
int fd,
void* buffer,
size_t length) {
36 unsigned char* bytes = buffer;
38 struct pollfd ready = {.fd = fd, .events = POLLIN};
41 result = poll(&ready, 1, 10000);
42 while (result < 0 && errno == EINTR);
45 ssize_t count = read(fd, bytes, length);
46 if (count < 0 && errno == EINTR)
55int pm_write(
int fd,
const void* buffer,
size_t length) {
56 const unsigned char* bytes = buffer;
58 ssize_t count = write(fd, bytes, length);
59 if (count < 0 && errno == EINTR)
68int pm_send(
int fd,
char command) {
69 return pm_write(fd, &command, 1);
71int pm_receive(
int fd,
char command) {
73 return pm_read(fd, &actual, 1) || actual != command ? -1 : 0;
75int pm_spawn(
struct pm_peer* peer,
int (*body)(
int,
int,
void*),
void* argument) {
76 int command[2], report[2];
89 int result = body(command[0], report[1], argument);
92 _exit(result ? 1 : 0);
102 peer->command = command[1];
103 peer->report = report[0];
106int pm_join(
struct pm_peer* peer) {
107 int result = pm_reap(peer->pid, 10000);
109 fprintf(stderr,
"cooperative child pid=%d status=%d\n", peer->pid, result);
111 if (peer->command >= 0)
112 close(peer->command);
113 if (peer->report >= 0)
115 peer->command = peer->report = -1;
118void pm_cleanup(
struct pm_peer* peer) {
120 kill(peer->pid, SIGKILL);
121 pm_reap(peer->pid, 1000);
123 if (peer->command >= 0)
124 close(peer->command);
125 if (peer->report >= 0)
127 peer->pid = peer->command = peer->report = -1;
129int pm_isolate(
int (*body)(
void)) {
136 _exit(result ? 1 : 0);
138 return pid > 0 ? pm_reap(pid, 32000) : -1;
140ssize_t pm_copy(pid_t pid,
void* local,
const void* remote,
size_t length,
int write_remote) {
141 struct iovec here = {local, length}, there = {(
void*)remote, length};
142 return write_remote ? process_vm_writev(pid, &here, 1, &there, 1, 0)
143 : process_vm_readv(pid, &here, 1, &there, 1, 0);
145int pm_dumpable(
int value) {
146 return prctl(PR_SET_DUMPABLE, (
unsigned long)value, 0UL, 0UL, 0UL);
148static int run(
const char* name,
int (*body)(
void)) {
149 printf(
"PROCESS-MEMORY-CONTRACT: BEGIN %s\n", name);
157 _exit(result ? 1 : 0);
159 int result = pid > 0 ? pm_reap(pid, 45000) : -1;
160 printf(
"PROCESS-MEMORY-CONTRACT: %s %s status=%d\n", result ?
"FAIL" :
"PASS", name, result);
164int main(
int argc,
char** argv) {
165 pm_page = (size_t)sysconf(_SC_PAGESIZE);
166 if (pm_page < 512 || pm_page > 65536 || (pm_page & (pm_page - 1)))
168 signal(SIGPIPE, SIG_IGN);
169 if (argc > 1 && !strcmp(argv[1],
"memory-exec"))
170 return pm_exec(argc, argv);
171 if (argc > 1 && !strcmp(argv[1],
"fs-exec"))
172 return pm_fs_exec(argc, argv);
175 static const struct {
178 } families[] = {{
"copies", pm_copies},
179 {
"mappings", pm_mappings},
180 {
"lifetime", pm_lifetime},
181 {
"credentials", pm_credentials},
182 {
"filesystem", pm_filesystem}};
184 for (
size_t n = 0; n <
sizeof(families) /
sizeof(families[0]); ++n) {
185 if (argc == 2 && strcmp(argv[1],
"all") && strcmp(argv[1], families[n].name))
188 if (run(families[n].name, families[n].body))
193 puts(
"PROCESS-MEMORY-CONTRACT: END PASS");