1 #include <darwintest.h>
2 #include <darwintest_utils.h>
3
4 #include <mach/mach.h>
5 #include <mach/mach_types.h>
6 #include <mach/mach_port.h>
7 #include <mach/message.h>
8 #include <mach/mach_error.h>
9 #include <mach/vm_map.h>
10
11
12 T_GLOBAL_META(
13 T_META_NAMESPACE("xnu.ipc"),
14 T_META_CHECK_LEAKS(false),
15 T_META_RUN_CONCURRENTLY(true),
16 T_META_RADAR_COMPONENT_NAME("xnu"),
17 T_META_RADAR_COMPONENT_VERSION("IPC"));
18
19 /*
20 * This file checks the basics of the MACH IPC basic transport mechanism
21 */
22
23 #pragma mark helpers
24
25 #define DEFAULT_CONTEXT ((mach_port_context_t)0x42424242)
26
27 static mach_port_name_t
t_port_construct_full(uint32_t mpo_flags,mach_port_msgcount_t qlimit)28 t_port_construct_full(
29 uint32_t mpo_flags,
30 mach_port_msgcount_t qlimit)
31 {
32 mach_port_options_t opts = {
33 .flags = mpo_flags | MPO_QLIMIT,
34 .mpl.mpl_qlimit = qlimit,
35 };
36 mach_port_name_t name;
37 kern_return_t kr;
38
39 kr = mach_port_construct(mach_task_self(), &opts, DEFAULT_CONTEXT, &name);
40 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct");
41
42 return name;
43 }
44 #define t_port_construct() t_port_construct_full(MPO_INSERT_SEND_RIGHT, 1)
45
46 static void
t_port_destruct_full(mach_port_name_t * name,uint16_t srights,mach_port_context_t ctx)47 t_port_destruct_full(
48 mach_port_name_t *name,
49 uint16_t srights,
50 mach_port_context_t ctx)
51 {
52 kern_return_t kr;
53
54 kr = mach_port_destruct(mach_task_self(), *name, -srights, ctx);
55 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct");
56
57 *name = MACH_PORT_NULL;
58 }
59 #define t_port_destruct(name) t_port_destruct_full(name, 1, 0)
60
61 static mach_port_name_t
t_make_sonce(mach_port_name_t port)62 t_make_sonce(
63 mach_port_name_t port)
64 {
65 mach_msg_type_name_t disp;
66 mach_port_name_t name;
67 kern_return_t kr;
68
69 kr = mach_port_extract_right(mach_task_self(), port,
70 MACH_MSG_TYPE_MAKE_SEND_ONCE, &name, &disp);
71 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "make-send-once");
72 T_QUIET; T_ASSERT_EQ(disp, MACH_MSG_TYPE_PORT_SEND_ONCE,
73 "check make-sonce");
74
75 return name;
76 }
77
78 static void
t_deallocate_sonce(mach_port_name_t port)79 t_deallocate_sonce(
80 mach_port_name_t port)
81 {
82 kern_return_t kr;
83
84 kr = mach_port_deallocate(mach_task_self(), port);
85 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "dealloc-send-once");
86 }
87
88 static void
t_vm_deallocate(void * addr,vm_size_t size)89 t_vm_deallocate(
90 void *addr,
91 vm_size_t size)
92 {
93 kern_return_t kr;
94
95 kr = vm_deallocate(mach_task_self(), (vm_address_t)addr, size);
96 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate");
97 }
98
99 static kern_return_t
t_receive(mach_port_name_t name,mach_msg_header_t * msg,mach_msg_size_t size,mach_msg_option64_t opts)100 t_receive(
101 mach_port_name_t name,
102 mach_msg_header_t *msg,
103 mach_msg_size_t size,
104 mach_msg_option64_t opts)
105 {
106 opts |= MACH64_RCV_GUARDED_DESC | MACH64_RCV_MSG;
107 return mach_msg2(msg, opts, *msg, 0, size, name, 0, 0);
108 }
109
110 __attribute__((overloadable))
111 static kern_return_t
t_send(mach_port_name_t dest,mach_msg_header_t * msg,void * upto,mach_msg_option64_t opts)112 t_send(
113 mach_port_name_t dest,
114 mach_msg_header_t *msg,
115 void *upto,
116 mach_msg_option64_t opts)
117 {
118 mach_msg_size_t size = (mach_msg_size_t)((char *)upto - (char *)msg);
119
120 opts |= MACH64_SEND_MSG | MACH64_SEND_MQ_CALL;
121
122 msg->msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, 0);
123 msg->msgh_size = size;
124 msg->msgh_remote_port = dest;
125 msg->msgh_local_port = MACH_PORT_NULL;
126 msg->msgh_voucher_port = MACH_PORT_NULL;
127 msg->msgh_id = 42;
128 return mach_msg2(msg, opts, *msg, size, 0, 0, 0, 0);
129 }
130
131 __attribute__((overloadable))
132 static kern_return_t
t_send(mach_port_name_t dest,mach_msg_base_t * base,void * upto,mach_msg_option64_t opts)133 t_send(
134 mach_port_name_t dest,
135 mach_msg_base_t *base,
136 void *upto,
137 mach_msg_option64_t opts)
138 {
139 mach_msg_header_t *msg = &base->header;
140 mach_msg_size_t size = (mach_msg_size_t)((char *)upto - (char *)msg);
141
142 opts |= MACH64_SEND_MSG | MACH64_SEND_MQ_CALL;
143
144 msg->msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0,
145 MACH_MSGH_BITS_COMPLEX);
146 msg->msgh_size = size;
147 msg->msgh_remote_port = dest;
148 msg->msgh_local_port = MACH_PORT_NULL;
149 msg->msgh_voucher_port = MACH_PORT_NULL;
150 msg->msgh_id = 42;
151 return mach_msg2(msg, opts, *msg, size, 0, 0, 0, 0);
152 }
153
154 static void
t_fill_port(mach_port_name_t dest,size_t n)155 t_fill_port(
156 mach_port_name_t dest,
157 size_t n)
158 {
159 for (size_t i = 0; i < n; i++) {
160 mach_msg_header_t hdr;
161 kern_return_t kr;
162
163 kr = t_send(dest, &hdr, &hdr + 1, MACH64_SEND_TIMEOUT);
164 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "send to fill");
165 }
166 }
167
168 static vm_size_t
t_check_0xff(const void * addr,vm_size_t size)169 t_check_0xff(
170 const void *addr,
171 vm_size_t size)
172 {
173 for (size_t i = 0; i < size; i++) {
174 if (((uint8_t *)addr)[i] != 0xff) {
175 return i;
176 }
177 }
178
179 return ~0ul;
180 }
181
182 #pragma mark trailer checks
183
184 T_DECL(mach_msg_trailer, "check trailer generation")
185 {
186 mach_port_name_t rcv_name;
187 security_token_t sec_token;
188 audit_token_t audit_token;
189 mach_msg_type_number_t count;
190 kern_return_t kr;
191
192 rcv_name = t_port_construct();
193
194 count = TASK_SECURITY_TOKEN_COUNT;
195 kr = task_info(mach_task_self(), TASK_SECURITY_TOKEN, (task_info_t)&sec_token, &count);
196 T_ASSERT_MACH_SUCCESS(kr, "task_info(TASK_SECURITY_TOKEN)");
197
198 count = TASK_AUDIT_TOKEN_COUNT;
199 kr = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)&audit_token, &count);
200 T_ASSERT_MACH_SUCCESS(kr, "task_info(TASK_AUDIT_TOKEN)");
201
202 for (int i = 0; i <= MACH_RCV_TRAILER_LABELS; i++) {
203 mach_msg_option64_t topts = (mach_msg_option64_t)MACH_RCV_TRAILER_ELEMENTS(i);
204 mach_msg_size_t tsize = REQUESTED_TRAILER_SIZE(topts);
205 struct {
206 mach_msg_header_t hdr;
207 mach_msg_max_trailer_t trailer;
208 uint32_t sentinel;
209 } buf;
210
211 switch (i) {
212 case MACH_RCV_TRAILER_NULL:
213 case MACH_RCV_TRAILER_SEQNO:
214 case MACH_RCV_TRAILER_SENDER:
215 case MACH_RCV_TRAILER_AUDIT:
216 case MACH_RCV_TRAILER_CTX:
217 case MACH_RCV_TRAILER_AV:
218 break;
219 default:
220 continue;
221 }
222
223 memset(&buf, 0xff, sizeof(buf));
224 kr = t_send(rcv_name, &buf.hdr, &buf.trailer, MACH64_MSG_OPTION_NONE);
225 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "sending message with trailer %d", i);
226
227 kr = t_receive(rcv_name, &buf.hdr, sizeof(buf), topts);
228 T_ASSERT_MACH_SUCCESS(kr, "receiving message with trailer %d", i);
229
230 T_EXPECT_EQ((unsigned long)buf.hdr.msgh_size, sizeof(buf.hdr), "msgh_size");
231 T_EXPECT_EQ(buf.trailer.msgh_trailer_type, MACH_MSG_TRAILER_FORMAT_0, "msgh_trailer_type");
232 T_EXPECT_EQ(buf.trailer.msgh_trailer_size, tsize, "msgh_trailer_size");
233 if (tsize > offsetof(mach_msg_max_trailer_t, msgh_sender)) {
234 T_EXPECT_EQ(memcmp(&buf.trailer.msgh_sender, &sec_token,
235 sizeof(sec_token)), 0, "msgh_sender");
236 }
237 if (tsize > offsetof(mach_msg_max_trailer_t, msgh_audit)) {
238 T_EXPECT_EQ(memcmp(&buf.trailer.msgh_audit, &audit_token,
239 sizeof(audit_token)), 0, "msgh_audit");
240 }
241 if (tsize > offsetof(mach_msg_max_trailer_t, msgh_context)) {
242 T_EXPECT_EQ(buf.trailer.msgh_context, DEFAULT_CONTEXT,
243 "msgh_context");
244 }
245 if (tsize > offsetof(mach_msg_max_trailer_t, msgh_ad)) {
246 T_EXPECT_EQ(buf.trailer.msgh_ad, 0, "msgh_ad");
247 }
248 if (tsize > offsetof(mach_msg_max_trailer_t, msgh_labels)) {
249 T_EXPECT_EQ(buf.trailer.msgh_labels.sender, 0, "msgh_labels");
250 }
251
252 T_QUIET; T_EXPECT_EQ(t_check_0xff((char *)&buf.trailer + tsize,
253 sizeof(buf.trailer) + sizeof(buf.sentinel) - tsize), ~0ul,
254 "should be unmodified");
255 }
256
257 t_port_destruct(&rcv_name);
258 }
259
260 #pragma mark descriptor checks
261
262 static const mach_msg_type_name_t port_dispositions[] = {
263 MACH_MSG_TYPE_MOVE_RECEIVE,
264 MACH_MSG_TYPE_MOVE_SEND,
265 MACH_MSG_TYPE_MOVE_SEND_ONCE,
266 MACH_MSG_TYPE_COPY_SEND,
267 MACH_MSG_TYPE_MAKE_SEND,
268 MACH_MSG_TYPE_MAKE_SEND_ONCE,
269 0,
270 };
271
272 struct msg_complex_port {
273 mach_msg_base_t base;
274 mach_msg_port_descriptor_t dsc;
275 mach_msg_max_trailer_t trailer;
276 };
277
278 struct msg_complex_guarded_port {
279 mach_msg_base_t base;
280 mach_msg_guarded_port_descriptor_t dsc;
281 mach_msg_max_trailer_t trailer;
282 };
283
284 struct msg_complex_port_array {
285 mach_msg_base_t base;
286 mach_msg_ool_ports_descriptor_t dsc;
287 mach_msg_max_trailer_t trailer;
288 mach_port_name_t array[2];
289 };
290
291 struct msg_complex_memory {
292 mach_msg_base_t base;
293 mach_msg_ool_descriptor_t dsc;
294 mach_msg_max_trailer_t trailer;
295 };
296
297 static void
t_fill_complex_port_msg(struct msg_complex_port * msg,mach_msg_type_name_t disp,mach_port_name_t name)298 t_fill_complex_port_msg(
299 struct msg_complex_port *msg,
300 mach_msg_type_name_t disp,
301 mach_port_name_t name)
302 {
303 *msg = (struct msg_complex_port){
304 .base.body.msgh_descriptor_count = 1,
305 .dsc = {
306 .type = MACH_MSG_PORT_DESCRIPTOR,
307 .disposition = disp,
308 .name = name,
309 },
310 };
311 }
312
313 static void
t_fill_complex_port_guarded_msg(struct msg_complex_guarded_port * msg,mach_msg_type_name_t disp,mach_port_name_t name,mach_msg_guard_flags_t flags)314 t_fill_complex_port_guarded_msg(
315 struct msg_complex_guarded_port *msg,
316 mach_msg_type_name_t disp,
317 mach_port_name_t name,
318 mach_msg_guard_flags_t flags)
319 {
320 *msg = (struct msg_complex_guarded_port){
321 .base.body.msgh_descriptor_count = 1,
322 .dsc = {
323 .type = MACH_MSG_GUARDED_PORT_DESCRIPTOR,
324 .disposition = disp,
325 .name = name,
326 .context = DEFAULT_CONTEXT,
327 .flags = flags,
328 },
329 };
330 if (flags & MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND) {
331 msg->dsc.context = 0;
332 }
333 }
334
335 static void
t_fill_complex_memory_msg(struct msg_complex_memory * msg,vm_address_t memory,mach_msg_size_t size,bool move)336 t_fill_complex_memory_msg(
337 struct msg_complex_memory *msg,
338 vm_address_t memory,
339 mach_msg_size_t size,
340 bool move)
341 {
342 *msg = (struct msg_complex_memory){
343 .base.body.msgh_descriptor_count = 1,
344 .dsc = {
345 .type = MACH_MSG_OOL_DESCRIPTOR,
346 .address = (void *)memory,
347 .size = size,
348 .deallocate = move,
349 },
350 };
351 }
352
353 static void
t_fill_complex_port_array_msg(struct msg_complex_port_array * msg,mach_msg_type_name_t disp,mach_port_name_t name1,mach_port_name_t name2)354 t_fill_complex_port_array_msg(
355 struct msg_complex_port_array *msg,
356 mach_msg_type_name_t disp,
357 mach_port_name_t name1,
358 mach_port_name_t name2)
359 {
360 *msg = (struct msg_complex_port_array){
361 .base.body.msgh_descriptor_count = 1,
362 .dsc = {
363 .type = MACH_MSG_OOL_PORTS_DESCRIPTOR,
364 .disposition = disp,
365 .address = &msg->array,
366 .count = 2,
367 .deallocate = false,
368 },
369 .array[0] = name1,
370 .array[1] = name2,
371 };
372 }
373
374 static void
t_mach_msg_descriptor_port(bool pseudo_receive)375 t_mach_msg_descriptor_port(bool pseudo_receive)
376 {
377 mach_port_name_t rcv_name, port;
378 kern_return_t kr;
379
380 rcv_name = t_port_construct();
381 port = t_port_construct();
382
383 if (pseudo_receive) {
384 t_fill_port(rcv_name, 1);
385 }
386
387 for (size_t i = 0; i < port_dispositions[i]; i++) {
388 mach_msg_type_name_t disp = port_dispositions[i];
389 mach_port_name_t name = port;
390 struct msg_complex_port msg;
391
392 if (disp == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
393 name = t_make_sonce(port);
394 }
395
396 t_fill_complex_port_msg(&msg, disp, name);
397
398 kr = t_send(rcv_name, &msg.base, &msg.trailer, MACH64_SEND_TIMEOUT);
399 if (pseudo_receive) {
400 T_ASSERT_MACH_ERROR(kr, MACH_SEND_TIMED_OUT,
401 "pseudo-rcv(disposition:%d)", disp);
402 } else {
403 T_ASSERT_MACH_SUCCESS(kr, "send(disposition:%d)", disp);
404
405 kr = t_receive(rcv_name, &msg.base.header, sizeof(msg),
406 MACH64_MSG_OPTION_NONE);
407 T_ASSERT_MACH_SUCCESS(kr, "recv(disposition:%d)", disp);
408 }
409
410 switch (disp) {
411 case MACH_MSG_TYPE_MOVE_RECEIVE:
412 disp = MACH_MSG_TYPE_PORT_RECEIVE;
413 break;
414 case MACH_MSG_TYPE_MOVE_SEND:
415 case MACH_MSG_TYPE_COPY_SEND:
416 case MACH_MSG_TYPE_MAKE_SEND:
417 disp = MACH_MSG_TYPE_PORT_SEND;
418 break;
419 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
420 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
421 disp = MACH_MSG_TYPE_PORT_SEND_ONCE;
422 break;
423 }
424
425 T_ASSERT_EQ(msg.base.header.msgh_bits & MACH_MSGH_BITS_COMPLEX,
426 MACH_MSGH_BITS_COMPLEX, "verify complex");
427 T_ASSERT_EQ(msg.base.body.msgh_descriptor_count, 1u, "verify dsc count");
428 T_ASSERT_EQ((mach_msg_descriptor_type_t)msg.dsc.type, MACH_MSG_PORT_DESCRIPTOR, "verify type");
429 T_ASSERT_EQ((mach_msg_type_name_t)msg.dsc.disposition, disp, "verify disposition");
430 if (disp == MACH_MSG_TYPE_PORT_RECEIVE ||
431 disp == MACH_PORT_TYPE_SEND) {
432 T_ASSERT_EQ(msg.dsc.name, name, "verify name");
433 }
434
435 if (disp == MACH_MSG_TYPE_PORT_SEND_ONCE) {
436 t_deallocate_sonce(msg.dsc.name);
437 }
438 }
439
440 t_port_destruct_full(&port, 3, 0); /* did a COPY_SEND and a MAKE_SEND */
441 t_port_destruct(&rcv_name);
442 }
443
444 T_DECL(mach_msg_descriptor_port, "check port descriptors")
445 {
446 T_LOG("regular receive");
447 t_mach_msg_descriptor_port(false);
448 T_LOG("pseudo receive");
449 t_mach_msg_descriptor_port(true);
450 }
451
452 static void
t_mach_msg_descriptor_guarded_port(bool pseudo_receive)453 t_mach_msg_descriptor_guarded_port(bool pseudo_receive)
454 {
455 mach_port_name_t rcv_name, port;
456 kern_return_t kr;
457
458 rcv_name = t_port_construct();
459
460 if (pseudo_receive) {
461 t_fill_port(rcv_name, 1);
462 }
463
464 static const mach_msg_guard_flags_t test_flags[] = {
465 MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE,
466 MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE | MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND,
467 0,
468 };
469
470 for (size_t i = 0; test_flags[i]; i++) {
471 struct msg_complex_guarded_port msg;
472 mach_port_context_t ctx;
473
474 if (test_flags[i] & MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND) {
475 port = t_port_construct();
476 } else {
477 port = t_port_construct_full(MPO_INSERT_SEND_RIGHT | MPO_CONTEXT_AS_GUARD, 1);
478 }
479
480 t_fill_complex_port_guarded_msg(&msg, MACH_MSG_TYPE_MOVE_RECEIVE,
481 port, test_flags[i]);
482
483 kr = t_send(rcv_name, &msg.base, &msg.trailer, MACH64_SEND_TIMEOUT);
484 if (pseudo_receive) {
485 T_ASSERT_MACH_ERROR(kr, MACH_SEND_TIMED_OUT, "pseudo-rcv");
486 } else {
487 T_ASSERT_MACH_SUCCESS(kr, "send");
488
489 kr = t_receive(rcv_name, &msg.base.header, sizeof(msg),
490 MACH64_MSG_OPTION_NONE);
491 T_ASSERT_MACH_SUCCESS(kr, "recv");
492 }
493
494 T_ASSERT_EQ(msg.base.header.msgh_bits & MACH_MSGH_BITS_COMPLEX,
495 MACH_MSGH_BITS_COMPLEX, "verify complex");
496 T_ASSERT_EQ(msg.base.body.msgh_descriptor_count, 1u, "verify dsc count");
497 T_ASSERT_EQ((mach_msg_descriptor_type_t)msg.dsc.type,
498 MACH_MSG_GUARDED_PORT_DESCRIPTOR, "verify type");
499 T_ASSERT_EQ((mach_msg_type_name_t)msg.dsc.disposition,
500 MACH_MSG_TYPE_PORT_RECEIVE, "verify disposition");
501 T_ASSERT_EQ(msg.dsc.name, port, "verify name");
502 ctx = (mach_port_context_t)&msg.base;
503 T_ASSERT_EQ(msg.dsc.context, ctx, "verify context");
504 t_port_destruct_full(&port, 1, ctx);
505 }
506
507 t_port_destruct(&rcv_name);
508 }
509
510 T_DECL(mach_msg_descriptor_guarded_port, "check guarded port descriptors")
511 {
512 T_LOG("regular receive");
513 t_mach_msg_descriptor_guarded_port(false);
514 T_LOG("pseudo receive");
515 t_mach_msg_descriptor_guarded_port(true);
516 }
517
518 static void
t_mach_msg_descriptor_port_array(bool pseudo_receive)519 t_mach_msg_descriptor_port_array(bool pseudo_receive)
520 {
521 mach_port_name_t rcv_name, port1, port2;
522 uint32_t mpo_flags;
523 kern_return_t kr;
524
525 /*
526 * Receive rights can receive OOL ports array only if
527 * the port is of a dedicated type that allows it.
528 *
529 * This type is created by using the MPO_CONNECTION_PORT_WITH_PORT_ARRAY
530 * flag, which also requires the task to have the relevant
531 * entitlement.
532 */
533 mpo_flags = MPO_INSERT_SEND_RIGHT | MPO_CONNECTION_PORT_WITH_PORT_ARRAY;
534 rcv_name = t_port_construct_full(mpo_flags, 1);
535 port1 = t_port_construct();
536 port2 = t_port_construct();
537
538 if (pseudo_receive) {
539 t_fill_port(rcv_name, 1);
540 }
541
542 /*
543 * We only allow MACH_MSG_TYPE_COPY_SEND disposition
544 * for OOL ports array descriptors.
545 */
546 mach_msg_type_name_t disp = MACH_MSG_TYPE_COPY_SEND;
547 mach_port_name_t name1 = port1;
548 mach_port_name_t name2 = port2;
549 struct msg_complex_port_array msg;
550 mach_port_name_t *array;
551
552 t_fill_complex_port_array_msg(&msg, disp, name1, name2);
553
554 kr = t_send(rcv_name, &msg.base, &msg.trailer, MACH64_SEND_TIMEOUT);
555 if (pseudo_receive) {
556 T_ASSERT_MACH_ERROR(kr, MACH_SEND_TIMED_OUT,
557 "pseudo-rcv(disposition:%d)", disp);
558 } else {
559 T_ASSERT_MACH_SUCCESS(kr, "send(disposition:%d)", disp);
560
561 kr = t_receive(rcv_name, &msg.base.header, sizeof(msg),
562 MACH64_MSG_OPTION_NONE);
563 T_ASSERT_MACH_SUCCESS(kr, "recv(disposition:%d)", disp);
564 }
565
566 disp = MACH_MSG_TYPE_PORT_SEND;
567 array = msg.dsc.address;
568
569 T_ASSERT_EQ(msg.base.header.msgh_bits & MACH_MSGH_BITS_COMPLEX,
570 MACH_MSGH_BITS_COMPLEX, "verify complex");
571 T_ASSERT_EQ(msg.base.body.msgh_descriptor_count, 1u, "verify dsc count");
572 T_ASSERT_EQ((mach_msg_descriptor_type_t)msg.dsc.type, MACH_MSG_OOL_PORTS_DESCRIPTOR, "verify type");
573 T_ASSERT_EQ((mach_msg_type_name_t)msg.dsc.disposition, disp, "verify disposition");
574 T_ASSERT_EQ(msg.dsc.count, 2u, "verify count");
575 T_ASSERT_EQ((bool)msg.dsc.deallocate, true, "verify deallocate");
576
577 T_ASSERT_EQ(array[0], name1, "verify name");
578 T_ASSERT_EQ(array[1], name2, "verify name");
579
580 t_vm_deallocate(array, sizeof(array[0]) * msg.dsc.count);
581
582 t_port_destruct_full(&port1, 2, 0); /* did a COPY_SEND */
583 t_port_destruct_full(&port2, 2, 0); /* did a COPY_SEND */
584 t_port_destruct(&rcv_name);
585 }
586
587 T_DECL(mach_msg_descriptor_port_array, "check port array descriptors")
588 {
589 T_LOG("regular receive");
590 t_mach_msg_descriptor_port_array(false);
591 T_LOG("pseudo receive");
592 t_mach_msg_descriptor_port_array(true);
593 }
594
595 static void
t_mach_msg_descriptor_memory(bool pseudo_receive)596 t_mach_msg_descriptor_memory(bool pseudo_receive)
597 {
598 mach_port_name_t rcv_name;
599 struct msg_complex_memory msg;
600 kern_return_t kr;
601 vm_address_t addr;
602 mach_msg_size_t size = 1u << 20;
603
604 rcv_name = t_port_construct();
605
606 if (pseudo_receive) {
607 t_fill_port(rcv_name, 1);
608 }
609
610 kr = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE);
611 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate(1M)");
612
613 memset((void *)addr, 0xff, size);
614
615 for (size_t n = 0; n < 2; n++) {
616 t_fill_complex_memory_msg(&msg, addr, size, n > 0);
617
618 kr = t_send(rcv_name, &msg.base, &msg.trailer, MACH64_SEND_TIMEOUT);
619 if (pseudo_receive) {
620 T_ASSERT_MACH_ERROR(kr, MACH_SEND_TIMED_OUT, "pseudo-rcv");
621 } else {
622 T_ASSERT_MACH_SUCCESS(kr, "send");
623
624 kr = t_receive(rcv_name, &msg.base.header, sizeof(msg),
625 MACH64_MSG_OPTION_NONE);
626 T_ASSERT_MACH_SUCCESS(kr, "recv");
627 }
628
629 T_ASSERT_EQ(msg.base.header.msgh_bits & MACH_MSGH_BITS_COMPLEX,
630 MACH_MSGH_BITS_COMPLEX, "verify complex");
631 T_ASSERT_EQ(msg.base.body.msgh_descriptor_count, 1u, "verify dsc count");
632 T_ASSERT_EQ((mach_msg_descriptor_type_t)msg.dsc.type,
633 MACH_MSG_OOL_DESCRIPTOR, "verify type");
634 T_ASSERT_EQ(msg.dsc.size, size, "verify dsc count");
635 T_ASSERT_EQ(t_check_0xff(msg.dsc.address, size), ~0ul,
636 "check content");
637
638 if (n == 0) {
639 t_vm_deallocate(msg.dsc.address, size);
640 } else {
641 addr = (vm_address_t)msg.dsc.address;
642 }
643 }
644
645 t_vm_deallocate((void *)addr, size);
646 t_port_destruct(&rcv_name);
647 }
648
649 T_DECL(mach_msg_descriptor_memory, "check memory descriptors")
650 {
651 T_LOG("regular receive");
652 t_mach_msg_descriptor_memory(false);
653 T_LOG("pseudo receive");
654 t_mach_msg_descriptor_memory(true);
655 }
656