]>
Commit | Line | Data |
---|---|---|
f427ee49 A |
1 | // |
2 | // vmremaptest.c | |
3 | // | |
4 | // Created by Lionel Desai on 9/16/19. | |
5 | // Copyright © 2019 Apple. All rights reserved. | |
6 | // | |
7 | ||
8 | #include "mach_vm_tests.h" | |
9 | #include <sys/sysctl.h> | |
10 | ||
11 | ||
12 | #define TESTSZ (140 * 1024 * 1024ULL) | |
13 | ||
14 | void | |
15 | mach_vm_client(mach_port_t port) | |
16 | { | |
17 | mach_port_t memport = MACH_PORT_NULL; | |
18 | mach_vm_address_t src = 0, dest = 0, tmp = 0; | |
19 | mach_vm_size_t size = 0; | |
20 | vm_prot_t cur_prot, max_prot; | |
21 | mach_port_name_t lport = 0; | |
22 | kern_return_t ret = 0; | |
23 | boolean_t copy = FALSE; | |
24 | mach_vm_offset_t misoffset = 0; | |
25 | ||
26 | mach_msg_type_number_t countp; | |
27 | mach_msg_size_t messageSize = 0; | |
28 | ipc_message_t *message = NULL; | |
29 | ||
30 | char buffer[PATH_MAX]; | |
31 | ret = proc_pidpath(getpid(), buffer, sizeof(buffer)); | |
32 | assert(ret != -1); | |
33 | ||
34 | messageSize = sizeof(ipc_message_t) + sizeof(mach_msg_trailer_t) + 64; | |
35 | message = (ipc_message_t *)calloc(1, messageSize); | |
36 | ||
37 | message->header.msgh_bits = MACH_MSGH_BITS_ZERO; | |
38 | message->header.msgh_size = messageSize; | |
39 | message->header.msgh_remote_port = MACH_PORT_NULL; | |
40 | message->header.msgh_local_port = port; | |
41 | ||
42 | while (1) { | |
43 | /* Awaiting the pid/src. addr/size from the server so we know what to remap from where */ | |
44 | ret = mach_msg(&message->header, MACH_RCV_MSG | MACH_RCV_LARGE, 0, messageSize, port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
45 | if (ret == KERN_SUCCESS) { | |
46 | if (debug) { | |
47 | T_LOG("CLIENT: received info from server... 0x%llx, %lld, 0x%llx, %d - %d\n", message->address, message->size, message->misoffset, message->vm_op, message->copy); | |
48 | } | |
49 | ||
50 | switch (message->vm_op) { | |
51 | case VM_OP_REMAP: | |
52 | ret = task_for_pid(mach_task_self(), (pid_t) message->pid, &lport); | |
53 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "task_for_pid"); | |
54 | ||
55 | copy = message->copy; | |
56 | size = message->size; | |
57 | src = message->address; | |
58 | misoffset = 0; | |
59 | ||
60 | ret = mach_vm_allocate(mach_task_self(), &tmp, size + 16384, VM_FLAGS_ANYWHERE); | |
61 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "mach_vm_allocate"); | |
62 | mach_vm_deallocate(mach_task_self(), tmp, size + 16384); | |
63 | ||
64 | dest = tmp + 4096; | |
65 | ||
66 | ret = mach_vm_remap(mach_task_self(), &dest, size, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, | |
67 | lport, src, copy, | |
68 | &cur_prot, | |
69 | &max_prot, | |
70 | VM_INHERIT_NONE); | |
71 | ||
72 | if (ret) { | |
73 | char dstval[64]; | |
74 | memcpy(dstval, (void*) dest, 64); | |
75 | T_LOG("CLIENT: mach_vm_remap FAILED: %s -- src 0x%llx, dest 0x%llx (%s)\n", mach_error_string(ret), src, dest, dstval); | |
76 | T_FAIL("CLIENT: mach_vm_remap FAILED"); | |
77 | } | |
78 | ||
79 | memcpy(message->value, (void*)dest, 64); | |
80 | break; | |
81 | ||
82 | case VM_OP_READ_OVERWRITE: | |
83 | ret = task_for_pid(mach_task_self(), (pid_t) message->pid, &lport); | |
84 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "task_for_pid"); | |
85 | ||
86 | size = message->size; | |
87 | src = message->address; | |
88 | misoffset = 0; | |
89 | ||
90 | mach_vm_size_t dest_size = 0; | |
91 | ret = mach_vm_allocate(mach_task_self(), &tmp, size + 16384, VM_FLAGS_ANYWHERE); | |
92 | assert(KERN_SUCCESS == ret); | |
93 | ||
94 | dest = tmp + 4096; | |
95 | ||
96 | ret = mach_vm_read_overwrite(lport, src, size, dest, &dest_size); | |
97 | ||
98 | if (ret) { | |
99 | char dstval[64]; | |
100 | memcpy(dstval, (void*) dest, 64); | |
101 | T_LOG("CLIENT: mach_vm_read_overwrite FAILED: %s -- src 0x%llx, dest 0x%llx (%s)\n", mach_error_string(ret), src, dest, dstval); | |
102 | T_FAIL("CLIENT: mach_vm_read_overwrite FAILED"); | |
103 | } | |
104 | ||
105 | memcpy(message->value, (void*)dest, 64); | |
106 | break; | |
107 | ||
108 | case VM_OP_READ: | |
109 | ret = task_for_pid(mach_task_self(), (pid_t) message->pid, &lport); | |
110 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "task_for_pid"); | |
111 | ||
112 | size = message->size; | |
113 | src = message->address; | |
114 | misoffset = 0; | |
115 | ||
116 | ret = mach_vm_read(lport, src, size, (vm_offset_t*)&dest, &countp); | |
117 | if (ret) { | |
118 | char dstval[64]; | |
119 | memcpy(dstval, (void*) dest, 64); | |
120 | T_LOG("CLIENT: mach_vm_read FAILED: %s -- src 0x%llx, dest 0x%llx (%s)\n", mach_error_string(ret), src, dest, dstval); | |
121 | T_FAIL("CLIENT: mach_vm_read FAILED"); | |
122 | exit(1); | |
123 | } | |
124 | ||
125 | memcpy(message->value, (void*)dest, 64); | |
126 | break; | |
127 | ||
128 | #if 0 | |
129 | case VM_OP_WRITE: | |
130 | ret = task_for_pid(mach_task_self(), (pid_t) message->pid, &lport); | |
131 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "task_for_pid"); | |
132 | ||
133 | size = message->size; | |
134 | src = message->address; | |
135 | misoffset = 0; | |
136 | ||
137 | ret = mach_vm_write(lport, src, dest, countp); | |
138 | if (ret) { | |
139 | char dstval[64]; | |
140 | memcpy(dstval, (void*) dest, 64); | |
141 | T_LOG("CLIENT: mach_vm_write FAILED: %s -- src 0x%llx, dest 0x%llx (%s)\n", mach_error_string(ret), src, dest, dstval); | |
142 | T_FAIL("CLIENT: mach_vm_write FAILED"); | |
143 | } | |
144 | ||
145 | memcpy(message->value, (void*)dest, 64); | |
146 | break; | |
147 | #endif | |
148 | case VM_OP_MEMENTRY: | |
149 | assert(message->body.msgh_descriptor_count == 1); | |
150 | dest = 0; | |
151 | size = message->size; | |
152 | memport = message->port_descriptor.name; | |
153 | copy = message->copy; | |
154 | if (copy) { | |
155 | misoffset = 0; | |
156 | } else { | |
157 | misoffset = message->misoffset; | |
158 | } | |
159 | ||
160 | cur_prot = max_prot = VM_PROT_READ; | |
161 | #if 0 | |
162 | /* This + VM_FLAGS_FIXED in mach_vm_map() will return KERN_INVALID_ARG expectedly */ | |
163 | ret = mach_vm_allocate(mach_task_self(), &tmp, size + 16384, VM_FLAGS_ANYWHERE); | |
164 | dest = tmp + 4095; | |
165 | mach_vm_deallocate(mach_task_self(), tmp, size + 16384); | |
166 | #endif | |
167 | ret = mach_vm_map(mach_task_self(), &dest, size, 0 /*mask*/, | |
168 | VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, | |
169 | memport, 0 /*offset*/, copy, cur_prot, max_prot, VM_INHERIT_NONE); | |
170 | ||
171 | if (ret) { | |
172 | T_LOG("CLIENT: mach_vm_map FAILED: %s -- port 0x%x\n", mach_error_string(ret), memport); | |
173 | T_FAIL("CLIENT: mach_vm_map FAILED"); | |
174 | } | |
175 | ||
176 | memcpy(message->value, (void*)(dest + misoffset), 64); | |
177 | break; | |
178 | ||
179 | case VM_OP_UNMAP: | |
180 | assert(dest); | |
181 | ret = mach_vm_deallocate(mach_task_self(), dest, size); | |
182 | if (ret) { | |
183 | T_LOG("CLIENT: mach_vm_deallocate FAILED: %s -- dest 0x%llx, size 0x%llx\n", mach_error_string(ret), dest, size); | |
184 | T_FAIL("CLIENT: mach_vm_deallocate FAILED"); | |
185 | } | |
186 | /* No message to send here */ | |
187 | continue; | |
188 | ||
189 | case VM_OP_NONE: | |
190 | memcpy(message->value, (void*) (dest + misoffset), 64); | |
191 | break; | |
192 | ||
193 | case VM_OP_EXIT: | |
194 | if (debug) { | |
195 | T_LOG("CLIENT EXITING ****** \n"); | |
196 | } | |
197 | return; | |
198 | ||
199 | case VM_OP_EXIT_ERROR: | |
200 | if (debug) { | |
201 | T_LOG("CLIENT EXITING WITH ERROR****** \n"); | |
202 | T_FAIL("Revieved VM_OP_EXIT_ERROR"); | |
203 | } | |
204 | return; | |
205 | default: | |
206 | break; | |
207 | } | |
208 | ||
209 | char dstval[64]; | |
210 | memcpy(dstval, (void*) message->value, 64); | |
211 | dstval[63] = '\0'; | |
212 | ||
213 | if (debug) { | |
214 | T_LOG("CLIENT: dest 0x%llx -> 0x%llx (0x%llx), *dest %s\n", dest, dest + misoffset, misoffset, dstval); | |
215 | /*memcpy(dstval, (void*) (dest + misoffset), 64); | |
216 | * dstval[63]='\0'; | |
217 | * T_LOG("*dest %s\n", dstval);*/ | |
218 | } | |
219 | ||
220 | message->header.msgh_local_port = MACH_PORT_NULL; | |
221 | ||
222 | ret = mach_msg(&message->header, MACH_SEND_MSG, message->header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
223 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "CLIENT: mach_msg_send FAILED"); | |
224 | } else { | |
225 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "CLIENT: mach_msg_rcv FAILED"); | |
226 | } | |
227 | } | |
228 | } | |
229 | ||
230 | void | |
231 | mach_server_make_memory_entry(mach_port_t replyPort) | |
232 | { | |
233 | mach_vm_address_t src = 0, lsrc = 0; | |
234 | mach_vm_size_t size = TESTSZ; | |
235 | memory_object_size_t memsz = 0; | |
236 | kern_return_t kr; | |
237 | boolean_t modified_in_server = FALSE, perm_changed = FALSE; | |
238 | ipc_message_t message; | |
239 | ipc_message_t *reply = NULL; | |
240 | char src_val[64], dst_val[64]; | |
241 | mach_msg_size_t replySize = 0; | |
242 | void *buffer = NULL; | |
243 | int flags = 0; | |
244 | mach_port_t memport = 0; | |
245 | int mementry_pass_idx = 0; | |
246 | mach_vm_offset_t misoffset = 0; | |
247 | ||
248 | if (debug) { | |
249 | T_LOG("\n*************** make_memory_entry_test START ***************\n"); | |
250 | } | |
251 | ||
252 | if (mach_server_data_setup(&buffer) != 0) { | |
253 | server_error_out(replyPort); | |
254 | } | |
255 | ||
256 | if (buffer == NULL) { | |
257 | mach_server_data_cleanup(NULL, 0, 0); | |
258 | exit(0); | |
259 | } | |
260 | ||
261 | replySize = sizeof(ipc_message_t) + sizeof(mach_msg_trailer_t) + 64; | |
262 | reply = calloc(1, replySize); | |
263 | ||
264 | test_different_mementry_mode: | |
265 | /* create message to send over rights/address/pid/size */ | |
266 | mach_server_construct_header(&message, replyPort); | |
267 | ||
268 | /* allocation that we plan to remap in the client */ | |
269 | mach_server_create_allocation(&src, size, buffer); | |
270 | ||
271 | memsz = 8191; | |
272 | lsrc = src + 94095; | |
273 | int pgmask = (getpagesize() - 1); | |
274 | misoffset = 94095 - (94095 & ~pgmask); | |
275 | ||
276 | if (mementry_pass_idx < 2) { | |
277 | if (mementry_pass_idx == 0) { | |
278 | flags = VM_PROT_DEFAULT | MAP_MEM_VM_COPY | MAP_MEM_USE_DATA_ADDR; | |
279 | T_LOG("mach_make_memory_entry VM_COPY | USE_DATA_ADDR test..."); | |
280 | } else { | |
281 | flags = VM_PROT_READ | MAP_MEM_VM_SHARE; | |
282 | T_LOG("mach_make_memory_entry VM_SHARE test..."); | |
283 | } | |
284 | kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) lsrc, (mach_vm_size_t)getpagesize(), FALSE, VM_PROT_READ); | |
285 | assert(kr == KERN_SUCCESS); | |
286 | perm_changed = TRUE; | |
287 | } else { | |
288 | flags = VM_PROT_DEFAULT; | |
289 | perm_changed = FALSE; | |
290 | T_LOG("mach_make_memory_entry DEFAULT test..."); | |
291 | } | |
292 | ||
293 | kr = mach_make_memory_entry_64(mach_task_self(), &memsz, lsrc, flags, &memport, MACH_PORT_NULL); | |
294 | if (kr != KERN_SUCCESS) { | |
295 | T_LOG("ERROR: mach_make_memory_entry_64 try (%d) failed in Client: (%d) %s\n", | |
296 | mementry_pass_idx + 1, kr, mach_error_string(kr)); | |
297 | server_error_out(replyPort); | |
298 | } | |
299 | ||
300 | mach_server_contruct_payload(&message, lsrc, memport, memsz, misoffset, ((flags & MAP_MEM_VM_COPY) == MAP_MEM_VM_COPY) /*copy*/, VM_OP_MEMENTRY); | |
301 | ||
302 | memcpy(src_val, (void*) lsrc, 64); | |
303 | src_val[63] = '\0'; | |
304 | ||
305 | check_again: | |
306 | /* Sending over pid/src address/size */ | |
307 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
308 | ||
309 | if (kr != KERN_SUCCESS) { | |
310 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
311 | server_error_out(replyPort); | |
312 | } | |
313 | ||
314 | /* Ack from client that it worked */ | |
315 | ||
316 | bzero(reply, replySize); | |
317 | ||
318 | kr = mach_msg(&reply->header, MACH_RCV_MSG, 0, replySize, replyPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
319 | if (kr != KERN_SUCCESS) { | |
320 | T_LOG("ERROR: Failed to get reply from client: (%d) %s\n", kr, mach_error_string(kr)); | |
321 | server_error_out(replyPort); | |
322 | } | |
323 | ||
324 | memcpy(dst_val, &reply->value, 64); | |
325 | dst_val[63] = '\0'; | |
326 | ||
327 | if (modified_in_server == FALSE) { | |
328 | if (strncmp(src_val, dst_val, 64)) { | |
329 | T_LOG("FAILED\n"); | |
330 | T_LOG("(%d) Pre modification mach_make_memory_entry() FAILED: copy(%d) src_val: %s dest_val: %s\n", mementry_pass_idx + 1, message.copy, src_val, dst_val); | |
331 | server_error_out(replyPort); | |
332 | } | |
333 | } else { | |
334 | if (message.copy == TRUE) { | |
335 | if (strncmp(src_val, dst_val, 64) == 0) { | |
336 | T_LOG("FAILED\n"); | |
337 | T_LOG("(%d) Data mismatch with Copy: %d src_val: %s dest_val: %s\n", | |
338 | mementry_pass_idx + 1, message.copy, src_val, dst_val); | |
339 | server_error_out(replyPort); | |
340 | } | |
341 | } else { | |
342 | if (strncmp(src_val, dst_val, 64)) { | |
343 | T_LOG("FAILED\n"); | |
344 | T_LOG("(%d) Data mismatch with Copy: %d src_val: %s dest_val: %s\n", | |
345 | mementry_pass_idx + 1, message.copy, src_val, dst_val); | |
346 | server_error_out(replyPort); | |
347 | } | |
348 | } | |
349 | } | |
350 | ||
351 | if (modified_in_server == FALSE) { | |
352 | /* Now we change our data that has been mapped elsewhere */ | |
353 | if (perm_changed) { | |
354 | kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) lsrc, (mach_vm_size_t)getpagesize(), FALSE, VM_PROT_READ | VM_PROT_WRITE); | |
355 | assert(kr == KERN_SUCCESS); | |
356 | } | |
357 | ||
358 | memcpy((void*) lsrc, "THIS IS DIFFERENT -- BUT WE DON'T know if that's expecTED", 64); | |
359 | ||
360 | if (perm_changed) { | |
361 | kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) lsrc, (mach_vm_size_t)getpagesize(), FALSE, VM_PROT_READ); | |
362 | assert(kr == KERN_SUCCESS); | |
363 | } | |
364 | ||
365 | memcpy(src_val, (void*) lsrc, 64); | |
366 | src_val[63] = '\0'; | |
367 | modified_in_server = TRUE; | |
368 | message.vm_op = VM_OP_NONE; | |
369 | ||
370 | /* Check to see if the data in the other process is as expected */ | |
371 | goto check_again; | |
372 | } | |
373 | ||
374 | if (mementry_pass_idx < 2) { | |
375 | /* Next remap mode...so ask the other process to unmap the older mapping. */ | |
376 | message.vm_op = VM_OP_UNMAP; | |
377 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
378 | if (kr != KERN_SUCCESS) { | |
379 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
380 | server_error_out(replyPort); | |
381 | } | |
382 | ||
383 | mach_port_deallocate(mach_task_self(), memport); | |
384 | memport = MACH_PORT_NULL; | |
385 | mach_vm_deallocate(mach_task_self(), src, size); | |
386 | ||
387 | T_LOG("PASSED\n"); | |
388 | ||
389 | mementry_pass_idx++; | |
390 | modified_in_server = FALSE; | |
391 | ||
392 | goto test_different_mementry_mode; | |
393 | } | |
394 | ||
395 | T_LOG("PASSED\n"); | |
396 | ||
397 | /* Unmap old mapping in the other process. */ | |
398 | message.vm_op = VM_OP_UNMAP; | |
399 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
400 | if (kr != KERN_SUCCESS) { | |
401 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
402 | server_error_out(replyPort); | |
403 | } | |
404 | ||
405 | free(reply); | |
406 | reply = NULL; | |
407 | ||
408 | mach_port_deallocate(mach_task_self(), memport); | |
409 | memport = MACH_PORT_NULL; | |
410 | ||
411 | mach_server_data_cleanup(buffer, src, size); | |
412 | buffer = NULL; | |
413 | ||
414 | if (debug) { | |
415 | T_LOG("*************** mach_make_memory_entry_test END ***************\n"); | |
416 | } | |
417 | } | |
418 | ||
419 | void | |
420 | mach_server_read(mach_port_t replyPort, int op) | |
421 | { | |
422 | mach_vm_address_t src; | |
423 | mach_vm_size_t size = TESTSZ; | |
424 | kern_return_t kr; | |
425 | boolean_t modified_in_server = FALSE; | |
426 | ipc_message_t message; | |
427 | char src_val[64], dst_val[64]; | |
428 | mach_msg_size_t replySize = 0; | |
429 | ipc_message_t *reply = NULL; | |
430 | void *buffer = NULL; | |
431 | ||
432 | if (debug) { | |
433 | T_LOG("\n*************** vm_read / write / overwrite_test START ***************\n"); | |
434 | } | |
435 | ||
436 | { | |
437 | char opname[16]; | |
438 | if (op == VM_OP_READ) { | |
439 | strlcpy(opname, "read", 5); | |
440 | } | |
441 | if (op == VM_OP_WRITE) { | |
442 | strlcpy(opname, "write", 6); | |
443 | } | |
444 | if (op == VM_OP_READ_OVERWRITE) { | |
445 | strlcpy(opname, "read_overwrite", 15); | |
446 | } | |
447 | ||
448 | T_LOG("vm_%s test...", opname); | |
449 | } | |
450 | ||
451 | if (mach_server_data_setup(&buffer) != 0) { | |
452 | server_error_out(replyPort); | |
453 | } | |
454 | ||
455 | if (buffer == NULL) { | |
456 | mach_server_data_cleanup(NULL, 0, 0); | |
457 | exit(0); | |
458 | } | |
459 | ||
460 | replySize = sizeof(ipc_message_t) + sizeof(mach_msg_trailer_t) + 64; | |
461 | reply = calloc(1, replySize); | |
462 | ||
463 | /* create message to send over rights/address/pid/size */ | |
464 | mach_server_construct_header(&message, replyPort); | |
465 | ||
466 | /* allocation that we plan to remap in the client */ | |
467 | mach_server_create_allocation(&src, size, buffer); | |
468 | ||
469 | mach_server_contruct_payload(&message, src, MACH_PORT_NULL /* port */, size, 0, TRUE /*copy*/, op); | |
470 | if (debug) { | |
471 | T_LOG("server COPY: Sending 0x%llx, %d, 0x%llx\n", message.address, getpid(), message.size); | |
472 | } | |
473 | memcpy(src_val, (void*)message.address, 64); | |
474 | ||
475 | check_again: | |
476 | /* Sending over pid/src address/size */ | |
477 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
478 | if (kr != KERN_SUCCESS) { | |
479 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
480 | server_error_out(replyPort); | |
481 | } | |
482 | ||
483 | /* Ack from client that it worked */ | |
484 | ||
485 | bzero(reply, replySize); | |
486 | ||
487 | kr = mach_msg(&reply->header, MACH_RCV_MSG, 0, replySize, replyPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
488 | if (kr != KERN_SUCCESS) { | |
489 | T_LOG("ERROR: Failed to get reply from client: (%d) %s\n", kr, mach_error_string(kr)); | |
490 | server_error_out(replyPort); | |
491 | } | |
492 | ||
493 | memcpy(dst_val, &reply->value, 64); | |
494 | ||
495 | if (modified_in_server == FALSE) { | |
496 | if (strncmp(src_val, dst_val, 64)) { | |
497 | T_LOG("Pre modification (op: %d) FAILED: src_val: %s dest_val: %s\n", op, src_val, dst_val); | |
498 | server_error_out(replyPort); | |
499 | } | |
500 | } else { | |
501 | if (strncmp(src_val, dst_val, 64) == 0) { | |
502 | T_LOG("Data mismatch (op:%d) with Copy: %d src_val: %s dest_val: %s\n", op, message.copy, src_val, dst_val); | |
503 | server_error_out(replyPort); | |
504 | } | |
505 | } | |
506 | ||
507 | if (modified_in_server == FALSE) { | |
508 | /* Now we change our data that has been mapped elsewhere */ | |
509 | memcpy((void*)message.address, "THIS IS DIFFERENT -- BUT WE DON'T know if that's expecTED", 64); | |
510 | memcpy(src_val, (void*)message.address, 64); | |
511 | modified_in_server = TRUE; | |
512 | message.vm_op = VM_OP_NONE; | |
513 | ||
514 | /* Check to see if the data in the other process is as expected */ | |
515 | goto check_again; | |
516 | } | |
517 | ||
518 | /* Unmap old mapping in the other process. */ | |
519 | message.vm_op = VM_OP_UNMAP; | |
520 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
521 | if (kr != KERN_SUCCESS) { | |
522 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
523 | server_error_out(replyPort); | |
524 | } | |
525 | ||
526 | free(reply); | |
527 | reply = NULL; | |
528 | ||
529 | mach_server_data_cleanup(buffer, src, size); | |
530 | buffer = NULL; | |
531 | ||
532 | if (debug) { | |
533 | T_LOG("*************** vm_read_test END ***************\n"); | |
534 | } | |
535 | ||
536 | T_LOG("PASSED\n"); | |
537 | } | |
538 | ||
539 | void | |
540 | mach_server_remap(mach_port_t replyPort) | |
541 | { | |
542 | mach_vm_address_t src = 0, lsrc = 0; | |
543 | mach_vm_size_t size = TESTSZ; | |
544 | kern_return_t kr; | |
545 | int remap_copy_pass_idx = 0; | |
546 | boolean_t modified_in_server = FALSE; | |
547 | void *buffer; | |
548 | ipc_message_t message; | |
549 | char src_val[64], dst_val[64]; | |
550 | mach_msg_size_t replySize = 0; | |
551 | ipc_message_t *reply = NULL; | |
552 | ||
553 | if (debug) { | |
554 | T_LOG("\n*************** vm_remap_test START ***************\n"); | |
555 | } | |
556 | ||
557 | if (mach_server_data_setup(&buffer) != 0) { | |
558 | server_error_out(replyPort); | |
559 | } | |
560 | ||
561 | if (buffer == NULL) { | |
562 | mach_server_data_cleanup(NULL, 0, 0); | |
563 | exit(0); | |
564 | } | |
565 | ||
566 | replySize = sizeof(ipc_message_t) + sizeof(mach_msg_trailer_t) + 64; | |
567 | reply = calloc(1, replySize); | |
568 | ||
569 | remap_again: | |
570 | ||
571 | T_LOG("vm_remap (copy = %s) test...", ((remap_copy_pass_idx == 0) ? "FALSE" : "TRUE")); | |
572 | ||
573 | /* create message to send over rights/address/pid/size */ | |
574 | mach_server_construct_header(&message, replyPort); | |
575 | ||
576 | /* server allocation that we plan to remap in the client */ | |
577 | mach_server_create_allocation(&src, size, buffer); | |
578 | ||
579 | lsrc = src + 8193; | |
580 | ||
581 | mach_server_contruct_payload(&message, lsrc, MACH_PORT_NULL /* port */, size - 9000, 0, remap_copy_pass_idx /*copy*/, VM_OP_REMAP); | |
582 | if (debug) { | |
583 | T_LOG("server COPY: Sending 0x%llx, %d, 0x%llx\n", message.address, getpid(), message.size); | |
584 | } | |
585 | ||
586 | memcpy(src_val, (void*)lsrc, 64); | |
587 | src_val[63] = '\0'; | |
588 | ||
589 | check_again: | |
590 | /* Sending over pid/src address/size */ | |
591 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
592 | if (kr != KERN_SUCCESS) { | |
593 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
594 | server_error_out(replyPort); | |
595 | } | |
596 | ||
597 | /* Ack from client that it worked */ | |
598 | ||
599 | bzero(reply, replySize); | |
600 | ||
601 | kr = mach_msg(&reply->header, MACH_RCV_MSG, 0, replySize, replyPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
602 | if (kr != KERN_SUCCESS) { | |
603 | T_LOG("ERROR: Failed to get reply from client: (%d) %s\n", kr, mach_error_string(kr)); | |
604 | server_error_out(replyPort); | |
605 | } | |
606 | ||
607 | memcpy(dst_val, &reply->value, 64); | |
608 | dst_val[63] = '\0'; | |
609 | ||
610 | ||
611 | if (modified_in_server == FALSE) { | |
612 | if (strncmp(src_val, dst_val, 64)) { | |
613 | T_LOG("Pre modification remap() FAILED: copy(%d) src_val: %s dest_val: %s\n", | |
614 | message.copy, src_val, dst_val); | |
615 | server_error_out(replyPort); | |
616 | } | |
617 | } else { | |
618 | if (message.copy == TRUE) { | |
619 | if (strcmp(src_val, dst_val) == 0) { | |
620 | T_LOG("Data mismatch with Copy: %d src_val: %s dest_val: %s\n", | |
621 | message.copy, src_val, dst_val); | |
622 | server_error_out(replyPort); | |
623 | } | |
624 | } else { | |
625 | if (strcmp(src_val, dst_val)) { | |
626 | T_LOG("Data mismatch with Copy: %d src_val: %s dest_val: %s\n", | |
627 | message.copy, src_val, dst_val); | |
628 | server_error_out(replyPort); | |
629 | } | |
630 | } | |
631 | } | |
632 | ||
633 | if (modified_in_server == FALSE) { | |
634 | /* Now we change our data that has been mapped elsewhere */ | |
635 | memcpy((void*)message.address, "THIS IS DIFFERENT -- BUT WE DON'T know if that's expecTED", 64); | |
636 | memcpy(src_val, (void*)message.address, 64); | |
637 | src_val[63] = '\0'; | |
638 | ||
639 | modified_in_server = TRUE; | |
640 | message.vm_op = VM_OP_NONE; | |
641 | ||
642 | /* Check to see if the data in the other process is as expected */ | |
643 | goto check_again; | |
644 | } | |
645 | ||
646 | if (remap_copy_pass_idx == 0) { | |
647 | /* Next remap mode...so ask the other process to unmap the older mapping. */ | |
648 | message.vm_op = VM_OP_UNMAP; | |
649 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
650 | if (kr != KERN_SUCCESS) { | |
651 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
652 | server_error_out(replyPort); | |
653 | } | |
654 | ||
655 | mach_vm_deallocate(mach_task_self(), src, size); | |
656 | ||
657 | T_LOG("PASSED\n"); | |
658 | ||
659 | remap_copy_pass_idx++; | |
660 | modified_in_server = FALSE; | |
661 | ||
662 | /* Next remap pass to test (copy == TRUE). Send data out again to the other process to remap. */ | |
663 | goto remap_again; | |
664 | } | |
665 | ||
666 | T_LOG("PASSED\n"); | |
667 | ||
668 | /* Unmap old mapping in the other process. */ | |
669 | message.vm_op = VM_OP_UNMAP; | |
670 | kr = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
671 | if (kr != KERN_SUCCESS) { | |
672 | T_LOG("ERROR: Failed to send message to client: (%d) %s\n", kr, mach_error_string(kr)); | |
673 | server_error_out(replyPort); | |
674 | } | |
675 | ||
676 | free(reply); | |
677 | reply = NULL; | |
678 | ||
679 | mach_server_data_cleanup(buffer, src, size); | |
680 | buffer = NULL; | |
681 | ||
682 | if (debug) { | |
683 | T_LOG("*************** vm_remap_test END ***************\n"); | |
684 | } | |
685 | } |