9typedef ssize_t (*copy_fn)(pid_t,
const struct iovec*,
unsigned long,
const struct iovec*,
10 unsigned long,
unsigned long);
12static int scatter_target(
int command,
int report,
void* argument) {
15 unsigned char bytes[64];
16 for (
size_t n = 0; n <
sizeof(bytes); ++n)
17 bytes[n] = (
unsigned char)(0x20 + n);
18 uintptr_t address = (uintptr_t)bytes;
19 CHECK(!pm_dumpable(1) && !pm_write(report, &address,
sizeof(address)));
20 CHECK(!pm_receive(command,
'q'));
21 for (
int n = 0; n < 5; ++n)
22 CHECK(bytes[3 + n] == (
unsigned char)(
'A' + n));
23 for (
int n = 0; n < 15; ++n)
24 CHECK(bytes[32 + n] == (
unsigned char)(
'F' + n));
25 CHECK(bytes[2] == 0x22 && bytes[8] == 0x28 && bytes[47] == 0x4f);
29static int scatter(
void) {
31 struct pm_peer peer = PM_PEER_INITIALIZER;
33 unsigned char bytes[32], payload[20];
34 CHECK(!pm_spawn(&peer, scatter_target, NULL));
35 CHECK(!pm_read(peer.report, &address,
sizeof(address)));
36 memset(bytes, 0,
sizeof(bytes));
37 struct iovec local[] = {{NULL, 0}, {bytes, 7}, {bytes + 7, 13}};
38 struct iovec remote[] = {{(
void*)(address + 3), 5}, {NULL, 0}, {(
void*)(address + 32), 15}};
39 CHECK(process_vm_readv(peer.pid, local, 3, remote, 3, 0) == 20);
40 for (
int n = 0; n < 5; ++n)
41 CHECK(bytes[n] == 0x23 + n);
42 for (
int n = 0; n < 15; ++n)
43 CHECK(bytes[5 + n] == 0x40 + n);
44 for (
int n = 0; n < 20; ++n)
45 payload[n] = (
unsigned char)(
'A' + n);
46 struct iovec input[] = {{payload, 8}, {NULL, 0}, {payload + 8, 12}};
47 CHECK(process_vm_writev(peer.pid, input, 3, remote, 3, 0) == 20);
48 CHECK(process_vm_readv(peer.pid, local, 3, remote, 3, 0) == 20 && !memcmp(bytes, payload, 20));
49 CHECK(!pm_send(peer.command,
'q') && !pm_join(&peer));
54static int admission(
void) {
56 unsigned char source[16] =
"cooperative", destination[16] = {0};
57 struct iovec local = {destination,
sizeof(source)}, remote = {source,
sizeof(source)};
58 struct iovec empty = {NULL, 0}, huge = {source, (size_t)SSIZE_MAX + 1};
59 void* bad = mmap(NULL, pm_page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
60 CHECK(bad != MAP_FAILED);
61 copy_fn functions[] = {process_vm_readv, process_vm_writev};
62 for (
size_t n = 0; n < 2; ++n) {
63 copy_fn copy = functions[n];
65 CHECK(copy(0, NULL, 0, NULL, 0, 1) == -1 && errno == EINVAL);
67 CHECK(copy(getpid(), &local, 1025, &remote, 1, 0) == -1 && errno == EINVAL);
69 CHECK(copy(getpid(), bad, 1, &remote, 1, 0) == -1 && errno == EFAULT);
71 CHECK(copy(getpid(), &huge, 1, &remote, 1, 0) == -1 && errno == EINVAL);
72 CHECK(copy(-1, NULL, 0, bad, ULONG_MAX, 0) == 0);
73 CHECK(copy(0, &empty, 1, bad, 1025, 0) == 0);
75 CHECK(copy(getpid(), &local, 1, &remote, 1025, 0) == -1 && errno == EINVAL);
77 CHECK(copy(0, &local, 1, bad, 1, 0) == -1 && errno == EFAULT);
79 CHECK(copy(getpid(), &local, 1, &huge, 1, 0) == -1 && errno == EINVAL);
80 CHECK(copy(-1, &local, 1, &empty, 1, 0) == 0);
82 CHECK(copy(0, &local, 1, &remote, 1, 0) == -1 && errno == ESRCH);
83 struct iovec inaccessible = {bad, 1};
85 CHECK(copy(0, &inaccessible, 1, &remote, 1, 0) == -1 && errno == ESRCH);
87 CHECK(process_vm_readv(getpid(), &local, 1, &remote, 1, 0) ==
sizeof(source));
88 CHECK(!memcmp(source, destination,
sizeof(source)));
89 memset(destination, 0x64,
sizeof(destination));
90 CHECK(process_vm_writev(getpid(), &local, 1, &remote, 1, 0) ==
sizeof(source));
91 CHECK(!memcmp(source, destination,
sizeof(source)));
93 if (bad != MAP_FAILED)
97static int partial_pages(
void) {
99 unsigned char *local = MAP_FAILED, *remote = MAP_FAILED;
100 local = mmap(NULL, 2 * pm_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
101 remote = mmap(NULL, 2 * pm_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
102 CHECK(local != MAP_FAILED && remote != MAP_FAILED);
103 memset(local, 0x35, 2 * pm_page);
104 memset(remote, 0x67, 2 * pm_page);
105 CHECK(!mprotect(remote + pm_page, pm_page, PROT_NONE));
106 CHECK(pm_copy(getpid(), local, remote, 2 * pm_page, 1) == (ssize_t)pm_page);
107 CHECK(remote[0] == 0x35 && remote[pm_page - 1] == 0x35);
108 memset(local, 0x89, 2 * pm_page);
109 CHECK(pm_copy(getpid(), local, remote, 2 * pm_page, 0) == (ssize_t)pm_page);
110 CHECK(local[0] == 0x35 && local[pm_page - 1] == 0x35 && local[pm_page] == 0x89);
111 CHECK(!mprotect(remote + pm_page, pm_page, PROT_READ | PROT_WRITE));
112 CHECK(remote[pm_page] == 0x67);
113 CHECK(!mprotect(local + pm_page, pm_page, PROT_NONE));
114 memset(remote, 0xab, pm_page);
115 CHECK(pm_copy(getpid(), local, remote, 2 * pm_page, 0) == (ssize_t)pm_page);
116 CHECK(local[0] == 0xab && local[pm_page - 1] == 0xab);
117 memset(local, 0xcd, pm_page);
118 CHECK(pm_copy(getpid(), local, remote, 2 * pm_page, 1) == (ssize_t)pm_page);
119 CHECK(remote[0] == 0xcd && remote[pm_page - 1] == 0xcd && remote[pm_page] == 0x67);
121 CHECK(pm_copy(getpid(), local + pm_page, remote, 1, 1) == -1 && errno == EFAULT);
123 if (remote != MAP_FAILED)
124 munmap(remote, 2 * pm_page);
125 if (local != MAP_FAILED)
126 munmap(local, 2 * pm_page);
130 return admission() || scatter() || partial_pages();