9#include <sys/syscall.h>
16 uintptr_t anonymous, shared,
private, cow, stack, heap;
18static unsigned char pattern(
size_t n) {
19 return (
unsigned char)(n % 251 + 1);
22static int mapping_target(
int command,
int report,
void* argument) {
25 unsigned char *anonymous = MAP_FAILED, *shared = MAP_FAILED, *
private = MAP_FAILED;
26 volatile unsigned char stack[32] = {0x27};
27 anonymous = mmap(NULL, 3 * pm_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
28 shared = mmap(NULL, 3 * pm_page, PROT_READ | PROT_WRITE, MAP_SHARED, args->fd, 0);
29 private = mmap(NULL, 3 * pm_page, PROT_READ | PROT_WRITE, MAP_PRIVATE, args->fd, 0);
30 CHECK(anonymous != MAP_FAILED && shared != MAP_FAILED &&
private != MAP_FAILED);
31 uintptr_t original = (uintptr_t)syscall(SYS_brk, 0);
32 CHECK(original && original != UINTPTR_MAX && original < UINTPTR_MAX - 2 * pm_page);
33 uintptr_t heap = (original + pm_page - 1) & ~(uintptr_t)(pm_page - 1);
34 CHECK((uintptr_t)syscall(SYS_brk, heap + pm_page) == heap + pm_page);
35 *(
volatile unsigned char*)heap = 0x38;
36 struct map_addresses addresses = {(uintptr_t)anonymous, (uintptr_t)shared, (uintptr_t)
private,
37 (uintptr_t)args->cow, (uintptr_t)stack, heap};
38 CHECK(!pm_dumpable(1) && !pm_write(report, &addresses,
sizeof(addresses)));
39 CHECK(!pm_receive(command,
'w'));
40 CHECK(anonymous[0] == 0x31 && stack[0] == 0x42 && *(
volatile unsigned char*)heap == 0x53);
41 CHECK(args->cow[0] == 0x64 &&
private[7] == 0x75 && shared[11] == 0x86);
42 CHECK(
private[11] == pattern(11) && shared[7] == pattern(7));
43 CHECK(!msync(shared, 3 * pm_page, MS_SYNC) && !fsync(args->fd));
44 CHECK(!pm_send(report,
's'));
45 CHECK(!pm_receive(command,
'p'));
46 CHECK(!mprotect(anonymous + pm_page, pm_page, PROT_NONE));
47 CHECK(!mprotect(
private, 3 * pm_page, PROT_READ));
48 CHECK(!pm_send(report,
'p'));
49 CHECK(!pm_receive(command,
'e'));
50 CHECK(!ftruncate(args->fd, pm_page + 137));
51 CHECK(!pm_send(report,
'e') && !pm_receive(command,
'q'));
53 if (
private != MAP_FAILED)
54 munmap(
private, 3 * pm_page);
55 if (shared != MAP_FAILED)
56 munmap(shared, 3 * pm_page);
57 if (anonymous != MAP_FAILED)
58 munmap(anonymous, 3 * pm_page);
62static int backend(
int disk) {
63 int failed = 0, fd = -1;
65 struct pm_peer peer = PM_PEER_INITIALIZER;
67 unsigned char *buffer = MAP_FAILED, *cow = MAP_FAILED;
68 buffer = mmap(NULL, 3 * pm_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
69 cow = mmap(NULL, pm_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
70 CHECK(buffer != MAP_FAILED && cow != MAP_FAILED);
71 memset(cow, 0x19, pm_page);
73 snprintf(path,
sizeof(path),
"/process-memory-%d", getpid());
74 fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);
76 fd = memfd_create(
"process-memory", MFD_CLOEXEC);
78 for (
size_t n = 0; n < 3 * pm_page; ++n)
79 buffer[n] = pattern(n);
80 CHECK(!pm_write(fd, buffer, 3 * pm_page));
82 CHECK(!pm_spawn(&peer, mapping_target, &arguments));
83 CHECK(!pm_read(peer.report, &addresses,
sizeof(addresses)));
84 memset(buffer, 0xff, 3 * pm_page);
85 CHECK(pm_copy(peer.pid, buffer, (
void*)addresses.anonymous, 3 * pm_page, 0) ==
86 (ssize_t)(3 * pm_page));
87 for (
size_t n = 0; n < 3 * pm_page; ++n)
88 CHECK(buffer[n] == 0);
89 CHECK(pm_copy(peer.pid, buffer, (
void*)addresses.private, pm_page, 0) == (ssize_t)pm_page);
90 for (
size_t n = 0; n < pm_page; ++n)
91 CHECK(buffer[n] == pattern(n));
92 unsigned char byte = 0;
93 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.stack, 1, 0) == 1 &&
byte == 0x27);
94 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.heap, 1, 0) == 1 &&
byte == 0x38);
95 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.cow, 1, 0) == 1 &&
byte == 0x19);
97 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.anonymous, 1, 1) == 1);
99 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.stack, 1, 1) == 1);
101 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.heap, 1, 1) == 1);
103 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.cow, 1, 1) == 1);
105 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.private + 7), 1, 1) == 1);
107 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.shared + 11), 1, 1) == 1);
108 CHECK(cow[0] == 0x19 && cow[pm_page - 1] == 0x19);
109 CHECK(!pm_send(peer.command,
'w') && !pm_receive(peer.report,
's'));
110 CHECK(pread(fd, &
byte, 1, 7) == 1 &&
byte == pattern(7));
111 CHECK(pread(fd, &
byte, 1, 11) == 1 &&
byte == 0x86);
112 CHECK(!pm_send(peer.command,
'p') && !pm_receive(peer.report,
'p'));
114 CHECK(pm_copy(peer.pid, &
byte, (
void*)addresses.private, 1, 1) == -1 && errno == EFAULT);
115 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.private + 7), 1, 0) == 1 &&
byte == 0x75);
116 memset(buffer, 0x91, 3 * pm_page);
117 CHECK(pm_copy(peer.pid, buffer, (
void*)addresses.anonymous, 3 * pm_page, 0) == (ssize_t)pm_page);
118 CHECK(buffer[0] == 0x31 && buffer[pm_page] == 0x91 && buffer[2 * pm_page] == 0x91);
119 memset(buffer, 0xa2, 3 * pm_page);
120 CHECK(pm_copy(peer.pid, buffer, (
void*)addresses.anonymous, 3 * pm_page, 1) == (ssize_t)pm_page);
121 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.anonymous + 2 * pm_page), 1, 0) == 1 &&
123 CHECK(!pm_send(peer.command,
'e') && !pm_receive(peer.report,
'e'));
124 memset(buffer, 0xb3, 3 * pm_page);
125 CHECK(pm_copy(peer.pid, buffer, (
void*)addresses.shared, 3 * pm_page, 0) ==
126 (ssize_t)(2 * pm_page));
127 CHECK(buffer[11] == 0x86 && buffer[pm_page + 136] == pattern(pm_page + 136));
128 for (
size_t n = pm_page + 137; n < 2 * pm_page; ++n)
129 CHECK(buffer[n] == 0);
130 CHECK(buffer[2 * pm_page] == 0xb3);
132 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.shared + pm_page + 200), 1, 1) == 1);
133 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.shared + pm_page + 200), 1, 0) == 1 &&
136 CHECK(pm_copy(peer.pid, &
byte, (
void*)(addresses.shared + 2 * pm_page), 1, 1) == -1 &&
139 CHECK(!fstat(fd, &st) && st.st_size == (off_t)(pm_page + 137));
140 CHECK(!pm_send(peer.command,
'q') && !pm_join(&peer));
147 if (cow != MAP_FAILED)
148 munmap(cow, pm_page);
149 if (buffer != MAP_FAILED)
150 munmap(buffer, 3 * pm_page);
153int pm_mappings(
void) {
154 return backend(0) || backend(1);