xref: /xnu-11215.41.3/tests/ipc/mach_msg_transport.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
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