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