xref: /xnu-8792.61.2/osfmk/ipc/ipc_mqueue.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_FREE_COPYRIGHT@
30  */
31 /*
32  * Mach Operating System
33  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34  * All Rights Reserved.
35  *
36  * Permission to use, copy, modify and distribute this software and its
37  * documentation is hereby granted, provided that both the copyright
38  * notice and this permission notice appear in all copies of the
39  * software, derivative works or modified versions, and any portions
40  * thereof, and that both notices appear in supporting documentation.
41  *
42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45  *
46  * Carnegie Mellon requests users of this software to return to
47  *
48  *  Software Distribution Coordinator  or  [email protected]
49  *  School of Computer Science
50  *  Carnegie Mellon University
51  *  Pittsburgh PA 15213-3890
52  *
53  * any improvements or extensions that they make and grant Carnegie Mellon
54  * the rights to redistribute these changes.
55  */
56 /*
57  */
58 /*
59  *	File:	ipc/ipc_mqueue.c
60  *	Author:	Rich Draves
61  *	Date:	1989
62  *
63  *	Functions to manipulate IPC message queues.
64  */
65 /*
66  * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
67  * support for mandatory and extensible security protections.  This notice
68  * is included in support of clause 2.2 (b) of the Apple Public License,
69  * Version 2.0.
70  */
71 
72 
73 #include <mach/port.h>
74 #include <mach/message.h>
75 #include <mach/sync_policy.h>
76 
77 #include <kern/assert.h>
78 #include <kern/counter.h>
79 #include <kern/sched_prim.h>
80 #include <kern/ipc_kobject.h>
81 #include <kern/ipc_mig.h>       /* XXX - for mach_msg_receive_continue */
82 #include <kern/misc_protos.h>
83 #include <kern/task.h>
84 #include <kern/thread.h>
85 #include <kern/waitq.h>
86 
87 #include <ipc/port.h>
88 #include <ipc/ipc_mqueue.h>
89 #include <ipc/ipc_kmsg.h>
90 #include <ipc/ipc_right.h>
91 #include <ipc/ipc_port.h>
92 #include <ipc/ipc_pset.h>
93 #include <ipc/ipc_space.h>
94 
95 #if MACH_FLIPC
96 #include <ipc/flipc.h>
97 #endif
98 
99 #ifdef __LP64__
100 #include <vm/vm_map.h>
101 #endif
102 
103 #include <sys/event.h>
104 
105 extern char     *proc_name_address(void *p);
106 
107 int ipc_mqueue_full;            /* address is event for queue space */
108 int ipc_mqueue_rcv;             /* address is event for message arrival */
109 
110 /* forward declarations */
111 static void ipc_mqueue_receive_results(wait_result_t result);
112 static void ipc_mqueue_peek_on_thread_locked(
113 	ipc_mqueue_t        port_mq,
114 	mach_msg_option64_t option,
115 	thread_t            thread);
116 
117 /* Deliver message to message queue or waiting receiver */
118 static void ipc_mqueue_post(
119 	ipc_mqueue_t            mqueue,
120 	ipc_kmsg_t              kmsg,
121 	mach_msg_option_t       option);
122 
123 /*
124  *	Routine:	ipc_mqueue_init
125  *	Purpose:
126  *		Initialize a newly-allocated message queue.
127  */
128 void
ipc_mqueue_init(ipc_mqueue_t mqueue)129 ipc_mqueue_init(
130 	ipc_mqueue_t            mqueue)
131 {
132 	ipc_kmsg_queue_init(&mqueue->imq_messages);
133 	mqueue->imq_qlimit = MACH_PORT_QLIMIT_DEFAULT;
134 	klist_init(&mqueue->imq_klist);
135 }
136 
137 /*
138  *	Routine:	ipc_mqueue_add_locked.
139  *	Purpose:
140  *		Associate the portset's mqueue with the port's mqueue.
141  *		This has to be done so that posting the port will wakeup
142  *		a portset waiter.  If there are waiters on the portset
143  *		mqueue and messages on the port mqueue, try to match them
144  *		up now.
145  *	Conditions:
146  *		Port and Pset both locked.
147  */
148 kern_return_t
ipc_mqueue_add_locked(ipc_mqueue_t port_mqueue,ipc_pset_t pset,waitq_link_t * linkp)149 ipc_mqueue_add_locked(
150 	ipc_mqueue_t    port_mqueue,
151 	ipc_pset_t      pset,
152 	waitq_link_t   *linkp)
153 {
154 	ipc_port_t       port = ip_from_mq(port_mqueue);
155 	struct waitq_set *wqset = &pset->ips_wqset;
156 	circle_queue_t   kmsgq = &port_mqueue->imq_messages;
157 	kern_return_t    kr = KERN_SUCCESS;
158 	ipc_kmsg_t       kmsg;
159 
160 	kr = waitq_link_locked(&port->ip_waitq, wqset, linkp);
161 	if (kr != KERN_SUCCESS) {
162 		return kr;
163 	}
164 
165 	/*
166 	 * Now that the set has been added to the port, there may be
167 	 * messages queued on the port and threads waiting on the set
168 	 * waitq.  Lets get them together.
169 	 *
170 	 * Only consider this set however, as the other ones have been
171 	 * posted to already.
172 	 */
173 	while ((kmsg = ipc_kmsg_queue_first(kmsgq)) != IKM_NULL) {
174 		thread_t th;
175 		mach_msg_size_t msize, asize;
176 		spl_t th_spl;
177 
178 		th = waitq_wakeup64_identify_locked(wqset, IPC_MQUEUE_RECEIVE,
179 		    THREAD_AWAKENED, WAITQ_KEEP_LOCKED, &th_spl);
180 		/* port and pset still locked, thread locked */
181 
182 		if (th == THREAD_NULL) {
183 			/*
184 			 * Didn't find a thread to wake up but messages
185 			 * are enqueued, prepost the set instead,
186 			 * as calling waitq_wakeup64_identify_locked()
187 			 * on the set directly will not take care of it.
188 			 */
189 			waitq_link_prepost_locked(&port->ip_waitq, wqset);
190 			break;
191 		}
192 
193 		/*
194 		 * If the receiver waited with a facility not directly
195 		 * related to Mach messaging, then it isn't prepared to get
196 		 * handed the message directly.  Just set it running, and
197 		 * go look for another thread that can.
198 		 */
199 		if (th->ith_state != MACH_RCV_IN_PROGRESS) {
200 			if (th->ith_state == MACH_PEEK_IN_PROGRESS) {
201 				/*
202 				 * wakeup the peeking thread, but
203 				 * continue to loop over the threads
204 				 * waiting on the port's mqueue to see
205 				 * if there are any actual receivers
206 				 */
207 				ipc_mqueue_peek_on_thread_locked(port_mqueue,
208 				    th->ith_option,
209 				    th);
210 			}
211 			thread_unlock(th);
212 			splx(th_spl);
213 			continue;
214 		}
215 
216 		/*
217 		 * Found a receiver. see if they can handle the message
218 		 * correctly (the message is not too large for them, or
219 		 * they didn't care to be informed that the message was
220 		 * too large).  If they can't handle it, take them off
221 		 * the list and let them go back and figure it out and
222 		 * just move onto the next.
223 		 */
224 		msize = ipc_kmsg_copyout_size(kmsg, th->map);
225 		asize = ipc_kmsg_aux_data_size(kmsg);
226 
227 		if (ipc_kmsg_too_large(msize, asize, th->ith_option,
228 		    th->ith_max_msize, th->ith_max_asize, th)) {
229 			th->ith_state = MACH_RCV_TOO_LARGE;
230 			th->ith_msize = msize;
231 			th->ith_asize = asize;
232 			if (th->ith_option & MACH_RCV_LARGE) {
233 				/*
234 				 * let him go without message
235 				 */
236 				th->ith_receiver_name = port_mqueue->imq_receiver_name;
237 				th->ith_kmsg = IKM_NULL;
238 				th->ith_seqno = 0;
239 				thread_unlock(th);
240 				splx(th_spl);
241 				continue; /* find another thread */
242 			}
243 		} else {
244 			th->ith_state = MACH_MSG_SUCCESS;
245 		}
246 
247 		/*
248 		 * This thread is going to take this message,
249 		 * so give it to him.
250 		 */
251 		ipc_kmsg_rmqueue(kmsgq, kmsg);
252 #if MACH_FLIPC
253 		mach_node_t  node = kmsg->ikm_node;
254 #endif
255 		ipc_mqueue_release_msgcount(port_mqueue);
256 
257 		th->ith_kmsg = kmsg;
258 		th->ith_seqno = port_mqueue->imq_seqno++;
259 		thread_unlock(th);
260 		splx(th_spl);
261 #if MACH_FLIPC
262 		if (MACH_NODE_VALID(node) && FPORT_VALID(port_mqueue->imq_fport)) {
263 			flipc_msg_ack(node, port_mqueue, TRUE);
264 		}
265 #endif
266 	}
267 
268 	return KERN_SUCCESS;
269 }
270 
271 
272 /*
273  *	Routine:	ipc_port_has_klist
274  *	Purpose:
275  *		Returns whether the given port imq_klist field can be used as a klist.
276  */
277 bool
ipc_port_has_klist(ipc_port_t port)278 ipc_port_has_klist(ipc_port_t port)
279 {
280 	return !port->ip_specialreply &&
281 	       port->ip_sync_link_state == PORT_SYNC_LINK_ANY;
282 }
283 
284 static inline struct klist *
ipc_object_klist(ipc_object_t object)285 ipc_object_klist(ipc_object_t object)
286 {
287 	if (io_otype(object) == IOT_PORT) {
288 		ipc_port_t port = ip_object_to_port(object);
289 
290 		return ipc_port_has_klist(port) ? &port->ip_klist : NULL;
291 	}
292 	return &ips_object_to_pset(object)->ips_klist;
293 }
294 
295 /*
296  *	Routine:	ipc_mqueue_changed
297  *	Purpose:
298  *		Wake up receivers waiting in a message queue.
299  *	Conditions:
300  *		The object containing the message queue is locked.
301  */
302 void
ipc_mqueue_changed(ipc_space_t space,struct waitq * waitq)303 ipc_mqueue_changed(
304 	ipc_space_t         space,
305 	struct waitq       *waitq)
306 {
307 	ipc_object_t object = io_from_waitq(waitq);
308 	struct klist *klist = ipc_object_klist(object);
309 
310 	if (klist && SLIST_FIRST(klist)) {
311 		/*
312 		 * Indicate that this message queue is vanishing
313 		 *
314 		 * When this is called, the associated receive right may be in flight
315 		 * between two tasks: the one it used to live in, and the one that armed
316 		 * a port destroyed notification for it.
317 		 *
318 		 * The new process may want to register the port it gets back with an
319 		 * EVFILT_MACHPORT filter again, and may have pending sync IPC on this
320 		 * port pending already, in which case we want the imq_klist field to be
321 		 * reusable for nefarious purposes.
322 		 *
323 		 * Fortunately, we really don't need this linkage anymore after this
324 		 * point as EV_VANISHED / EV_EOF will be the last thing delivered ever.
325 		 *
326 		 * Note: we don't have the space lock here, however, this covers the
327 		 *       case of when a task is terminating the space, triggering
328 		 *       several knote_vanish() calls.
329 		 *
330 		 *       We don't need the lock to observe that the space is inactive as
331 		 *       we just deactivated it on the same thread.
332 		 *
333 		 *       We still need to call knote_vanish() so that the knote is
334 		 *       marked with EV_VANISHED or EV_EOF so that the detach step
335 		 *       in filt_machportdetach is skipped correctly.
336 		 */
337 		assert(space);
338 		knote_vanish(klist, is_active(space));
339 	}
340 
341 	if (io_otype(object) == IOT_PORT) {
342 		ipc_port_adjust_sync_link_state_locked(ip_object_to_port(object),
343 		    PORT_SYNC_LINK_ANY, NULL);
344 	} else {
345 		klist_init(klist);
346 	}
347 
348 	/*
349 	 * do not pass WAITQ_UPDATE_INHERITOR, ipc_port_destroy()
350 	 * needs to handle this manually, and the port lock
351 	 * is the waitq lock, so there's really no inefficiency there.
352 	 */
353 	waitq_wakeup64_all_locked(waitq, IPC_MQUEUE_RECEIVE,
354 	    THREAD_RESTART, WAITQ_KEEP_LOCKED);
355 }
356 
357 
358 
359 
360 /*
361  *	Routine:	ipc_mqueue_send
362  *	Purpose:
363  *		Send a message to a message queue.  The message holds a reference
364  *		for the destination port for this message queue in the
365  *		msgh_remote_port field.
366  *
367  *		If unsuccessful, the caller still has possession of
368  *		the message and must do something with it.  If successful,
369  *		the message is queued, given to a receiver, or destroyed.
370  *	Conditions:
371  *		port is locked.
372  *	Returns:
373  *		MACH_MSG_SUCCESS	The message was accepted.
374  *		MACH_SEND_TIMED_OUT	Caller still has message.
375  *		MACH_SEND_INTERRUPTED	Caller still has message.
376  */
377 mach_msg_return_t
ipc_mqueue_send_locked(ipc_mqueue_t mqueue,ipc_kmsg_t kmsg,mach_msg_option_t option,mach_msg_timeout_t send_timeout)378 ipc_mqueue_send_locked(
379 	ipc_mqueue_t            mqueue,
380 	ipc_kmsg_t              kmsg,
381 	mach_msg_option_t       option,
382 	mach_msg_timeout_t  send_timeout)
383 {
384 	ipc_port_t port = ip_from_mq(mqueue);
385 	int wresult;
386 
387 	/*
388 	 *  Don't block if:
389 	 *	1) We're under the queue limit.
390 	 *	2) Caller used the MACH_SEND_ALWAYS internal option.
391 	 *	3) Message is sent to a send-once right.
392 	 */
393 	if (!imq_full(mqueue) ||
394 	    (!imq_full_kernel(mqueue) &&
395 	    ((option & MACH_SEND_ALWAYS) ||
396 	    (MACH_MSGH_BITS_REMOTE(ikm_header(kmsg)->msgh_bits) ==
397 	    MACH_MSG_TYPE_PORT_SEND_ONCE)))) {
398 		mqueue->imq_msgcount++;
399 		assert(mqueue->imq_msgcount > 0);
400 		ip_mq_unlock(port);
401 	} else {
402 		thread_t cur_thread = current_thread();
403 		struct turnstile *send_turnstile = TURNSTILE_NULL;
404 		uint64_t deadline;
405 
406 		/*
407 		 * We have to wait for space to be granted to us.
408 		 */
409 		if ((option & MACH_SEND_TIMEOUT) && (send_timeout == 0)) {
410 			ip_mq_unlock(port);
411 			return MACH_SEND_TIMED_OUT;
412 		}
413 		if (imq_full_kernel(mqueue)) {
414 			ip_mq_unlock(port);
415 			return MACH_SEND_NO_BUFFER;
416 		}
417 		port->ip_fullwaiters = true;
418 
419 		if (option & MACH_SEND_TIMEOUT) {
420 			clock_interval_to_deadline(send_timeout, 1000 * NSEC_PER_USEC, &deadline);
421 		} else {
422 			deadline = 0;
423 		}
424 
425 		thread_set_pending_block_hint(cur_thread, kThreadWaitPortSend);
426 
427 		send_turnstile = turnstile_prepare((uintptr_t)port,
428 		    port_send_turnstile_address(port),
429 		    TURNSTILE_NULL, TURNSTILE_SYNC_IPC);
430 
431 		ipc_port_send_update_inheritor(port, send_turnstile,
432 		    TURNSTILE_DELAYED_UPDATE);
433 
434 		wresult = waitq_assert_wait64_leeway(
435 			&send_turnstile->ts_waitq,
436 			IPC_MQUEUE_FULL,
437 			THREAD_ABORTSAFE,
438 			TIMEOUT_URGENCY_USER_NORMAL,
439 			deadline,
440 			TIMEOUT_NO_LEEWAY);
441 
442 		ip_mq_unlock(port);
443 		turnstile_update_inheritor_complete(send_turnstile,
444 		    TURNSTILE_INTERLOCK_NOT_HELD);
445 
446 		if (wresult == THREAD_WAITING) {
447 			wresult = thread_block(THREAD_CONTINUE_NULL);
448 		}
449 
450 		/* Call turnstile complete with interlock held */
451 		ip_mq_lock(port);
452 		turnstile_complete((uintptr_t)port, port_send_turnstile_address(port), NULL, TURNSTILE_SYNC_IPC);
453 		ip_mq_unlock(port);
454 
455 		/* Call cleanup after dropping the interlock */
456 		turnstile_cleanup();
457 
458 		switch (wresult) {
459 		case THREAD_AWAKENED:
460 			/*
461 			 * we can proceed - inherited msgcount from waker
462 			 * or the message queue has been destroyed and the msgcount
463 			 * has been reset to zero (will detect in ipc_mqueue_post()).
464 			 */
465 			break;
466 
467 		case THREAD_TIMED_OUT:
468 			assert(option & MACH_SEND_TIMEOUT);
469 			return MACH_SEND_TIMED_OUT;
470 
471 		case THREAD_INTERRUPTED:
472 			return MACH_SEND_INTERRUPTED;
473 
474 		case THREAD_RESTART:
475 			/* mqueue is being destroyed */
476 			return MACH_SEND_INVALID_DEST;
477 		default:
478 			panic("ipc_mqueue_send");
479 		}
480 	}
481 
482 	ipc_mqueue_post(mqueue, kmsg, option);
483 	return MACH_MSG_SUCCESS;
484 }
485 
486 /*
487  *	Routine:	ipc_mqueue_override_send_locked
488  *	Purpose:
489  *		Set an override qos on the first message in the queue
490  *		(if the queue is full). This is a send-possible override
491  *		that will go away as soon as we drain a message from the
492  *		queue.
493  *
494  *	Conditions:
495  *		The port corresponding to mqueue is locked.
496  *		The caller holds a reference on the message queue.
497  */
498 void
ipc_mqueue_override_send_locked(ipc_mqueue_t mqueue,mach_msg_qos_t qos_ovr)499 ipc_mqueue_override_send_locked(
500 	ipc_mqueue_t        mqueue,
501 	mach_msg_qos_t      qos_ovr)
502 {
503 	ipc_port_t port = ip_from_mq(mqueue);
504 
505 	assert(waitq_is_valid(&port->ip_waitq));
506 
507 	if (imq_full(mqueue)) {
508 		ipc_kmsg_t first = ipc_kmsg_queue_first(&mqueue->imq_messages);
509 
510 		if (first && ipc_kmsg_override_qos(&mqueue->imq_messages, first, qos_ovr)) {
511 			if (ip_in_a_space(port) &&
512 			    is_active(ip_get_receiver(port)) &&
513 			    ipc_port_has_klist(port)) {
514 				KNOTE(&port->ip_klist, 0);
515 			}
516 		}
517 	}
518 }
519 
520 /*
521  *	Routine:	ipc_mqueue_release_msgcount
522  *	Purpose:
523  *		Release a message queue reference in the case where we
524  *		found a waiter.
525  *
526  *	Conditions:
527  *		The port corresponding to message queue is locked.
528  *		The message corresponding to this reference is off the queue.
529  *		There is no need to pass reserved preposts because this will
530  *		never prepost to anyone
531  */
532 void
ipc_mqueue_release_msgcount(ipc_mqueue_t port_mq)533 ipc_mqueue_release_msgcount(ipc_mqueue_t port_mq)
534 {
535 	ipc_port_t port = ip_from_mq(port_mq);
536 	struct turnstile *send_turnstile = port_send_turnstile(port);
537 
538 	ip_mq_lock_held(port);
539 	assert(port_mq->imq_msgcount > 1 || ipc_kmsg_queue_empty(&port_mq->imq_messages));
540 
541 	port_mq->imq_msgcount--;
542 
543 	if (!imq_full(port_mq) && port->ip_fullwaiters &&
544 	    send_turnstile != TURNSTILE_NULL) {
545 		/*
546 		 * boost the priority of the awoken thread
547 		 * (WAITQ_PROMOTE_PRIORITY) to ensure it uses
548 		 * the message queue slot we've just reserved.
549 		 *
550 		 * NOTE: this will never prepost
551 		 *
552 		 * The wakeup happens on a turnstile waitq
553 		 * which will wakeup the highest priority waiter.
554 		 * A potential downside of this would be starving low
555 		 * priority senders if there is a constant churn of
556 		 * high priority threads trying to send to this port.
557 		 */
558 		if (waitq_wakeup64_one(&send_turnstile->ts_waitq,
559 		    IPC_MQUEUE_FULL,
560 		    THREAD_AWAKENED,
561 		    WAITQ_PROMOTE_PRIORITY) != KERN_SUCCESS) {
562 			port->ip_fullwaiters = false;
563 		} else {
564 			/* gave away our slot - add reference back */
565 			port_mq->imq_msgcount++;
566 		}
567 	}
568 
569 	if (ipc_kmsg_queue_empty(&port_mq->imq_messages)) {
570 		waitq_clear_prepost_locked(&port->ip_waitq);
571 	}
572 }
573 
574 /*
575  *	Routine:	ipc_mqueue_post
576  *	Purpose:
577  *		Post a message to a waiting receiver or enqueue it.  If a
578  *		receiver is waiting, we can release our reserved space in
579  *		the message queue.
580  *
581  *	Conditions:
582  *		port is unlocked
583  *		If we need to queue, our space in the message queue is reserved.
584  */
585 static void
ipc_mqueue_post(ipc_mqueue_t mqueue,ipc_kmsg_t kmsg,mach_msg_option_t __unused option)586 ipc_mqueue_post(
587 	ipc_mqueue_t               mqueue,
588 	ipc_kmsg_t                 kmsg,
589 	mach_msg_option_t __unused option)
590 {
591 	ipc_port_t port = ip_from_mq(mqueue);
592 	struct waitq *waitq = &port->ip_waitq;
593 	boolean_t destroy_msg = FALSE;
594 
595 	ipc_kmsg_trace_send(kmsg, option);
596 
597 	/*
598 	 *	While the msg queue is locked, we have control of the
599 	 *	kmsg, so the ref in it for the port is still good.
600 	 *
601 	 *	Check for a receiver for the message.
602 	 */
603 	ip_mq_lock(port);
604 
605 	/* we may have raced with port destruction! */
606 	if (!waitq_is_valid(&port->ip_waitq)) {
607 		destroy_msg = TRUE;
608 		goto out_unlock;
609 	}
610 
611 	for (;;) {
612 		spl_t th_spl;
613 		thread_t receiver;
614 		mach_msg_size_t msize, asize;
615 
616 		receiver = waitq_wakeup64_identify_locked(waitq,
617 		    IPC_MQUEUE_RECEIVE, THREAD_AWAKENED,
618 		    WAITQ_KEEP_LOCKED, &th_spl);
619 		/* waitq still locked, thread locked */
620 
621 		if (receiver == THREAD_NULL) {
622 			/*
623 			 * no receivers; queue kmsg if space still reserved
624 			 * Reservations are cancelled when the port goes inactive.
625 			 * note that this will enqueue the message for any
626 			 * "peeking" receivers.
627 			 *
628 			 * Also, post the knote to wake up any threads waiting
629 			 * on that style of interface if this insertion is of
630 			 * note (first insertion, or adjusted override qos all
631 			 * the way to the head of the queue).
632 			 *
633 			 * This is just for ports. port-sets knotes are being
634 			 * posted to by the waitq_wakeup64_identify_locked()
635 			 * above already.
636 			 */
637 			if (mqueue->imq_msgcount == 0) {
638 				/*
639 				 * The message queue must belong
640 				 * to an inactive port, so just destroy
641 				 * the message and pretend it was posted.
642 				 */
643 				destroy_msg = TRUE;
644 			} else if (!ipc_kmsg_enqueue_qos(&mqueue->imq_messages, kmsg)) {
645 				/*
646 				 * queue was not empty and qos
647 				 * didn't change, nothing to do.
648 				 */
649 			} else if (ip_in_a_space(port) &&
650 			    is_active(ip_get_receiver(port)) &&
651 			    ipc_port_has_klist(port)) {
652 				/*
653 				 * queue was empty or qos changed
654 				 * we need to tell kqueue, unless
655 				 * the space is getting torn down
656 				 */
657 				KNOTE(&port->ip_klist, 0);
658 			}
659 			break;
660 		}
661 
662 		/*
663 		 * If a thread is attempting a "peek" into the message queue
664 		 * (MACH_PEEK_IN_PROGRESS), then we enqueue the message and set the
665 		 * thread running.  A successful peek is essentially the same as
666 		 * message delivery since the peeking thread takes responsibility
667 		 * for delivering the message and (eventually) removing it from
668 		 * the mqueue.  Only one thread can successfully use the peek
669 		 * facility on any given port, so we exit the waitq loop after
670 		 * encountering such a thread.
671 		 */
672 		if (receiver->ith_state == MACH_PEEK_IN_PROGRESS && mqueue->imq_msgcount > 0) {
673 			ipc_kmsg_enqueue_qos(&mqueue->imq_messages, kmsg);
674 			ipc_mqueue_peek_on_thread_locked(mqueue, receiver->ith_option, receiver);
675 			thread_unlock(receiver);
676 			splx(th_spl);
677 			break; /* Message was posted, so break out of loop */
678 		}
679 
680 		/*
681 		 * If the receiver waited with a facility not directly related
682 		 * to Mach messaging, then it isn't prepared to get handed the
683 		 * message directly. Just set it running, and go look for
684 		 * another thread that can.
685 		 */
686 		if (receiver->ith_state != MACH_RCV_IN_PROGRESS) {
687 			thread_unlock(receiver);
688 			splx(th_spl);
689 			continue;
690 		}
691 
692 
693 		/*
694 		 * We found a waiting thread.
695 		 * If the message is too large or the scatter list is too small
696 		 * the thread we wake up will get that as its status.
697 		 */
698 		msize = ipc_kmsg_copyout_size(kmsg, receiver->map);
699 		asize = ipc_kmsg_aux_data_size(kmsg);
700 
701 		if (ipc_kmsg_too_large(msize, asize, receiver->ith_option,
702 		    receiver->ith_max_msize, receiver->ith_max_asize, receiver)) {
703 			receiver->ith_msize = msize;
704 			receiver->ith_asize = asize;
705 			receiver->ith_state = MACH_RCV_TOO_LARGE;
706 		} else {
707 			receiver->ith_state = MACH_MSG_SUCCESS;
708 		}
709 
710 		/*
711 		 * If there is no problem with the upcoming receive, or the
712 		 * receiver thread didn't specifically ask for special too
713 		 * large error condition, go ahead and select it anyway.
714 		 */
715 		if ((receiver->ith_state == MACH_MSG_SUCCESS) ||
716 		    !(receiver->ith_option & MACH_RCV_LARGE)) {
717 			receiver->ith_kmsg = kmsg;
718 			receiver->ith_seqno = mqueue->imq_seqno++;
719 #if MACH_FLIPC
720 			mach_node_t node = kmsg->ikm_node;
721 #endif
722 			thread_unlock(receiver);
723 			splx(th_spl);
724 
725 			/* we didn't need our reserved spot in the queue */
726 			ipc_mqueue_release_msgcount(mqueue);
727 
728 #if MACH_FLIPC
729 			if (MACH_NODE_VALID(node) && FPORT_VALID(mqueue->imq_fport)) {
730 				flipc_msg_ack(node, mqueue, TRUE);
731 			}
732 #endif
733 			break;
734 		}
735 
736 		/*
737 		 * Otherwise, this thread needs to be released to run
738 		 * and handle its error without getting the message.  We
739 		 * need to go back and pick another one.
740 		 */
741 		receiver->ith_receiver_name = mqueue->imq_receiver_name;
742 		receiver->ith_kmsg = IKM_NULL;
743 		receiver->ith_seqno = 0;
744 		thread_unlock(receiver);
745 		splx(th_spl);
746 	}
747 
748 out_unlock:
749 	/* clear the waitq boost we may have been given */
750 	waitq_clear_promotion_locked(waitq, current_thread());
751 	waitq_unlock(waitq);
752 
753 	if (destroy_msg) {
754 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
755 	}
756 
757 	counter_inc(&current_task()->messages_sent);
758 	return;
759 }
760 
761 
762 static void
ipc_mqueue_receive_results(wait_result_t saved_wait_result)763 ipc_mqueue_receive_results(wait_result_t saved_wait_result)
764 {
765 	thread_t                self = current_thread();
766 	mach_msg_option64_t     option64 = self->ith_option;
767 
768 	/*
769 	 * why did we wake up?
770 	 */
771 	switch (saved_wait_result) {
772 	case THREAD_TIMED_OUT:
773 		self->ith_state = MACH_RCV_TIMED_OUT;
774 		return;
775 
776 	case THREAD_INTERRUPTED:
777 		self->ith_state = MACH_RCV_INTERRUPTED;
778 		return;
779 
780 	case THREAD_RESTART:
781 		/* something bad happened to the port/set */
782 		self->ith_state = MACH_RCV_PORT_CHANGED;
783 		return;
784 
785 	case THREAD_AWAKENED:
786 		/*
787 		 * We do not need to go select a message, somebody
788 		 * handed us one (or a too-large indication).
789 		 */
790 		switch (self->ith_state) {
791 		case MACH_RCV_SCATTER_SMALL:
792 		case MACH_RCV_TOO_LARGE:
793 			/*
794 			 * Somebody tried to give us a too large
795 			 * message. If we indicated that we cared,
796 			 * then they only gave us the indication,
797 			 * otherwise they gave us the indication
798 			 * AND the message anyway.
799 			 */
800 			if (option64 & MACH_RCV_LARGE) {
801 				return;
802 			}
803 			return;
804 		case MACH_MSG_SUCCESS:
805 			return;
806 		case MACH_PEEK_READY:
807 			return;
808 
809 		default:
810 			panic("ipc_mqueue_receive_results: strange ith_state");
811 		}
812 
813 	default:
814 		panic("ipc_mqueue_receive_results: strange wait_result");
815 	}
816 }
817 
818 void
ipc_mqueue_receive_continue(__unused void * param,wait_result_t wresult)819 ipc_mqueue_receive_continue(
820 	__unused void *param,
821 	wait_result_t wresult)
822 {
823 	ipc_mqueue_receive_results(wresult);
824 	mach_msg_receive_continue();  /* hard-coded for now */
825 }
826 
827 /*
828  *	Routine:	ipc_mqueue_receive
829  *	Purpose:
830  *		Receive a message from a message queue.
831  *
832  *	Conditions:
833  *		Our caller must hold a reference for the port or port set
834  *		to which this queue belongs, to keep the queue
835  *		from being deallocated.
836  *
837  *		The kmsg is returned with clean header fields
838  *		and with the circular bit turned off through the ith_kmsg
839  *		field of the thread's receive continuation state.
840  *	Returns:
841  *		MACH_MSG_SUCCESS	Message returned in ith_kmsg.
842  *		MACH_RCV_TOO_LARGE	Message size returned in ith_msize,
843  *                          Auxiliary data size returned in ith_asize
844  *		MACH_RCV_TIMED_OUT	No message obtained.
845  *		MACH_RCV_INTERRUPTED	No message obtained.
846  *		MACH_RCV_PORT_DIED	Port/set died; no message.
847  *		MACH_RCV_PORT_CHANGED	Port moved into set; no msg.
848  *
849  */
850 
851 void
ipc_mqueue_receive(struct waitq * waitq,mach_msg_option64_t option64,mach_msg_size_t max_size,mach_msg_size_t max_aux_size,mach_msg_timeout_t rcv_timeout,int interruptible,bool has_continuation)852 ipc_mqueue_receive(
853 	struct waitq            *waitq,
854 	mach_msg_option64_t     option64,
855 	mach_msg_size_t         max_size,
856 	mach_msg_size_t         max_aux_size,   /* 0 if no aux buffer */
857 	mach_msg_timeout_t      rcv_timeout,
858 	int                     interruptible,
859 	bool                    has_continuation)
860 {
861 	wait_result_t           wresult;
862 	thread_t                self = current_thread();
863 
864 	waitq_lock(waitq);
865 
866 	wresult = ipc_mqueue_receive_on_thread_and_unlock(waitq, option64, max_size,
867 	    max_aux_size, rcv_timeout, interruptible, self);
868 	/* object unlocked */
869 	if (wresult == THREAD_NOT_WAITING) {
870 		return;
871 	}
872 
873 	if (wresult == THREAD_WAITING) {
874 		if (has_continuation) {
875 			wresult = thread_block(ipc_mqueue_receive_continue);
876 			/* NOTREACHED */
877 		}
878 		wresult = thread_block(THREAD_CONTINUE_NULL);
879 	}
880 	ipc_mqueue_receive_results(wresult);
881 }
882 
883 /*
884  *	Routine:	ipc_mqueue_receive_on_thread_and_unlock
885  *	Purpose:
886  *		Receive a message from a message queue using a specified thread.
887  *		If no message available, assert_wait on the appropriate waitq.
888  *
889  *	Conditions:
890  *		Assumes thread is self.
891  *		The port/port-set waitq is locked on entry, unlocked on return.
892  *		May have assert-waited. Caller must block in those cases.
893  */
894 wait_result_t
ipc_mqueue_receive_on_thread_and_unlock(struct waitq * waitq,mach_msg_option64_t option64,mach_msg_size_t max_msg_size,mach_msg_size_t max_aux_size,mach_msg_timeout_t rcv_timeout,int interruptible,thread_t thread)895 ipc_mqueue_receive_on_thread_and_unlock(
896 	struct waitq            *waitq,
897 	mach_msg_option64_t     option64,
898 	mach_msg_size_t         max_msg_size,
899 	mach_msg_size_t         max_aux_size,
900 	mach_msg_timeout_t      rcv_timeout,
901 	int                     interruptible,
902 	thread_t                thread)
903 {
904 	ipc_object_t            object = io_from_waitq(waitq);
905 	ipc_port_t              port = IP_NULL;
906 	wait_result_t           wresult;
907 	uint64_t                deadline;
908 	struct turnstile        *rcv_turnstile = TURNSTILE_NULL;
909 
910 	if (waitq_type(waitq) == WQT_PORT_SET) {
911 		ipc_pset_t pset = ips_object_to_pset(object);
912 		struct waitq *port_wq;
913 
914 		/*
915 		 * Put the message at the back of the prepost list
916 		 * if it's not a PEEK.
917 		 *
918 		 * Might drop the pset lock temporarily.
919 		 */
920 		port_wq = waitq_set_first_prepost(&pset->ips_wqset, WQS_PREPOST_LOCK |
921 		    ((option64 & MACH64_PEEK_MSG) ? WQS_PREPOST_PEEK: 0));
922 
923 		/* Returns with port locked */
924 
925 		if (port_wq != NULL) {
926 			/*
927 			 * We get here if there is at least one message
928 			 * waiting on port_wq. We have instructed the prepost
929 			 * iteration logic to leave both the port_wq and the
930 			 * set waitq locked.
931 			 *
932 			 * Continue on to handling the message with just
933 			 * the port waitq locked.
934 			 */
935 			io_unlock(object);
936 			port = ip_from_waitq(port_wq);
937 		}
938 	} else if (waitq_type(waitq) == WQT_PORT) {
939 		port = ip_from_waitq(waitq);
940 		if (ipc_kmsg_queue_empty(&port->ip_messages.imq_messages)) {
941 			port = IP_NULL;
942 		}
943 	} else {
944 		panic("Unknown waitq type (%p/0x%x)", waitq, waitq_type(waitq));
945 	}
946 
947 	if (port) {
948 		if (option64 & MACH64_PEEK_MSG) {
949 			ipc_mqueue_peek_on_thread_locked(&port->ip_messages,
950 			    option64, thread);
951 		} else {
952 			ipc_mqueue_select_on_thread_locked(&port->ip_messages,
953 			    option64, max_msg_size, max_aux_size, thread);
954 		}
955 		ip_mq_unlock(port);
956 		return THREAD_NOT_WAITING;
957 	}
958 
959 	if (!waitq_is_valid(waitq)) {
960 		/* someone raced us to destroy this mqueue/port! */
961 		io_unlock(object);
962 		/*
963 		 * ipc_mqueue_receive_results updates the thread's ith_state
964 		 * TODO: differentiate between rights being moved and
965 		 * rights/ports being destroyed (21885327)
966 		 */
967 		return THREAD_RESTART;
968 	}
969 
970 	/*
971 	 * Looks like we'll have to block.  The waitq we will
972 	 * block on (whether the set's or the local port's) is
973 	 * still locked.
974 	 */
975 	if ((option64 & MACH_RCV_TIMEOUT) && rcv_timeout == 0) {
976 		io_unlock(object);
977 		thread->ith_state = MACH_RCV_TIMED_OUT;
978 		return THREAD_NOT_WAITING;
979 	}
980 
981 	thread->ith_option = option64;
982 	thread->ith_max_msize = max_msg_size;
983 	thread->ith_msize = 0;
984 
985 	thread->ith_max_asize = max_aux_size;
986 	thread->ith_asize = 0;
987 
988 	if (option64 & MACH64_PEEK_MSG) {
989 		thread->ith_state = MACH_PEEK_IN_PROGRESS;
990 	} else {
991 		thread->ith_state = MACH_RCV_IN_PROGRESS;
992 	}
993 
994 	if (option64 & MACH_RCV_TIMEOUT) {
995 		clock_interval_to_deadline(rcv_timeout, 1000 * NSEC_PER_USEC, &deadline);
996 	} else {
997 		deadline = 0;
998 	}
999 
1000 	/*
1001 	 * Threads waiting on a reply port (not portset)
1002 	 * will wait on its receive turnstile.
1003 	 *
1004 	 * Donate waiting thread's turnstile and
1005 	 * setup inheritor for special reply port.
1006 	 * Based on the state of the special reply
1007 	 * port, the inheritor would be the send
1008 	 * turnstile of the connection port on which
1009 	 * the send of sync ipc would happen or
1010 	 * workloop's turnstile who would reply to
1011 	 * the sync ipc message.
1012 	 *
1013 	 * Pass in mqueue wait in waitq_assert_wait to
1014 	 * support port set wakeup. The mqueue waitq of port
1015 	 * will be converted to to turnstile waitq
1016 	 * in waitq_assert_wait instead of global waitqs.
1017 	 */
1018 	if (waitq_type(waitq) == WQT_PORT) {
1019 		port = ip_from_waitq(waitq);
1020 		rcv_turnstile = turnstile_prepare((uintptr_t)port,
1021 		    port_rcv_turnstile_address(port),
1022 		    TURNSTILE_NULL, TURNSTILE_SYNC_IPC);
1023 
1024 		ipc_port_recv_update_inheritor(port, rcv_turnstile,
1025 		    TURNSTILE_DELAYED_UPDATE);
1026 	}
1027 
1028 	thread_set_pending_block_hint(thread, kThreadWaitPortReceive);
1029 	wresult = waitq_assert_wait64_locked(waitq,
1030 	    IPC_MQUEUE_RECEIVE,
1031 	    interruptible,
1032 	    TIMEOUT_URGENCY_USER_NORMAL,
1033 	    deadline,
1034 	    TIMEOUT_NO_LEEWAY,
1035 	    thread);
1036 	if (wresult == THREAD_AWAKENED) {
1037 		/*
1038 		 * The first thing we did was to look for preposts
1039 		 * (using waitq_set_first_prepost() for sets, or looking
1040 		 * at the port's queue for ports).
1041 		 *
1042 		 * Since we found none, we kept the waitq locked.
1043 		 *
1044 		 * It ensures that waitq_assert_wait64_locked() can't
1045 		 * find pre-posts either, won't drop the waitq lock
1046 		 * either (even for a set), and can't return THREAD_AWAKENED.
1047 		 */
1048 		panic("ipc_mqueue_receive_on_thread: sleep walking");
1049 	}
1050 
1051 	io_unlock(object);
1052 
1053 	/* Check if its a port mqueue and if it needs to call turnstile_update_inheritor_complete */
1054 	if (rcv_turnstile != TURNSTILE_NULL) {
1055 		turnstile_update_inheritor_complete(rcv_turnstile, TURNSTILE_INTERLOCK_NOT_HELD);
1056 	}
1057 	/* Its callers responsibility to call turnstile_complete to get the turnstile back */
1058 
1059 	return wresult;
1060 }
1061 
1062 
1063 /*
1064  *	Routine:	ipc_mqueue_peek_on_thread_locked
1065  *	Purpose:
1066  *		A receiver discovered that there was a message on the queue
1067  *		before he had to block. Tell a thread about the message queue,
1068  *		but don't pick off any messages.
1069  *	Conditions:
1070  *		port_mq locked
1071  *		at least one message on port_mq's message queue
1072  *
1073  *	Returns: (on thread->ith_state)
1074  *		MACH_PEEK_READY		ith_peekq contains a message queue
1075  */
1076 void
ipc_mqueue_peek_on_thread_locked(ipc_mqueue_t port_mq,__assert_only mach_msg_option64_t option64,thread_t thread)1077 ipc_mqueue_peek_on_thread_locked(
1078 	ipc_mqueue_t        port_mq,
1079 	__assert_only mach_msg_option64_t option64,
1080 	thread_t            thread)
1081 {
1082 	assert(option64 & MACH64_PEEK_MSG);
1083 	assert(ipc_kmsg_queue_first(&port_mq->imq_messages) != IKM_NULL);
1084 
1085 	/*
1086 	 * Take a reference on the mqueue's associated port:
1087 	 * the peeking thread will be responsible to release this reference
1088 	 */
1089 	ip_validate(ip_from_mq(port_mq));
1090 	ip_reference(ip_from_mq(port_mq));
1091 	thread->ith_peekq = port_mq;
1092 	thread->ith_state = MACH_PEEK_READY;
1093 }
1094 
1095 /*
1096  *	Routine:	ipc_mqueue_select_on_thread_locked
1097  *	Purpose:
1098  *		A receiver discovered that there was a message on the queue
1099  *		before he had to block.  Pick the message off the queue and
1100  *		"post" it to thread.
1101  *	Conditions:
1102  *		port locked.
1103  *              thread not locked.
1104  *		There is a message.
1105  *		No need to reserve prepost objects - it will never prepost
1106  *
1107  *	Returns:
1108  *		MACH_MSG_SUCCESS	Actually selected a message for ourselves.
1109  *		MACH_RCV_TOO_LARGE  May or may not have pull it, but it is large
1110  */
1111 void
ipc_mqueue_select_on_thread_locked(ipc_mqueue_t port_mq,mach_msg_option64_t option64,mach_msg_size_t max_msg_size,mach_msg_size_t max_aux_size,thread_t thread)1112 ipc_mqueue_select_on_thread_locked(
1113 	ipc_mqueue_t            port_mq,
1114 	mach_msg_option64_t     option64,
1115 	mach_msg_size_t         max_msg_size,
1116 	mach_msg_size_t         max_aux_size,
1117 	thread_t                thread)
1118 {
1119 	ipc_kmsg_t kmsg;
1120 	mach_msg_size_t msize, asize;
1121 
1122 	mach_msg_return_t mr = MACH_MSG_SUCCESS;
1123 
1124 	/*
1125 	 * Do some sanity checking of our ability to receive
1126 	 * before pulling the message off the queue.
1127 	 */
1128 	kmsg = ipc_kmsg_queue_first(&port_mq->imq_messages);
1129 	assert(kmsg != IKM_NULL);
1130 
1131 	/*
1132 	 * If we really can't receive it, but we had the
1133 	 * MACH_RCV_LARGE option set, then don't take it off
1134 	 * the queue, instead return the appropriate error
1135 	 * (and size needed).
1136 	 */
1137 	msize = ipc_kmsg_copyout_size(kmsg, thread->map);
1138 	asize = ipc_kmsg_aux_data_size(kmsg);
1139 
1140 	if (ipc_kmsg_too_large(msize, asize, option64,
1141 	    max_msg_size, max_aux_size, thread)) {
1142 		mr = MACH_RCV_TOO_LARGE;
1143 		if (option64 & MACH_RCV_LARGE) {
1144 			thread->ith_receiver_name = port_mq->imq_receiver_name;
1145 			thread->ith_kmsg = IKM_NULL;
1146 			thread->ith_msize = msize;
1147 			thread->ith_asize = asize;
1148 			thread->ith_seqno = 0;
1149 			thread->ith_state = mr;
1150 			return;
1151 		}
1152 	}
1153 
1154 	ipc_kmsg_rmqueue(&port_mq->imq_messages, kmsg);
1155 #if MACH_FLIPC
1156 	if (MACH_NODE_VALID(kmsg->ikm_node) && FPORT_VALID(port_mq->imq_fport)) {
1157 		flipc_msg_ack(kmsg->ikm_node, port_mq, TRUE);
1158 	}
1159 #endif
1160 	ipc_mqueue_release_msgcount(port_mq);
1161 	thread->ith_seqno = port_mq->imq_seqno++;
1162 	thread->ith_kmsg = kmsg;
1163 	thread->ith_state = mr;
1164 
1165 	counter_inc(&current_task()->messages_received);
1166 	return;
1167 }
1168 
1169 /*
1170  *	Routine:	ipc_mqueue_peek_locked
1171  *	Purpose:
1172  *		Peek at a (non-set) message queue to see if it has a message
1173  *		matching the sequence number provided (if zero, then the
1174  *		first message in the queue) and return vital info about the
1175  *		message.
1176  *
1177  *	Conditions:
1178  *		The io object corresponding to mq is locked by callers.
1179  *		Other locks may be held by callers, so this routine cannot block.
1180  *		Caller holds reference on the message queue.
1181  */
1182 unsigned
ipc_mqueue_peek_locked(ipc_mqueue_t mq,mach_port_seqno_t * seqnop,mach_msg_size_t * msg_sizep,mach_msg_id_t * msg_idp,mach_msg_max_trailer_t * msg_trailerp,ipc_kmsg_t * kmsgp)1183 ipc_mqueue_peek_locked(ipc_mqueue_t mq,
1184     mach_port_seqno_t * seqnop,
1185     mach_msg_size_t * msg_sizep,
1186     mach_msg_id_t * msg_idp,
1187     mach_msg_max_trailer_t * msg_trailerp,
1188     ipc_kmsg_t *kmsgp)
1189 {
1190 	ipc_kmsg_queue_t kmsgq;
1191 	ipc_kmsg_t kmsg;
1192 	mach_port_seqno_t seqno, msgoff;
1193 	unsigned res = 0;
1194 	mach_msg_header_t *hdr;
1195 
1196 	seqno = 0;
1197 	if (seqnop != NULL) {
1198 		seqno = *seqnop;
1199 	}
1200 
1201 	if (seqno == 0) {
1202 		seqno = mq->imq_seqno;
1203 		msgoff = 0;
1204 	} else if (seqno >= mq->imq_seqno &&
1205 	    seqno < mq->imq_seqno + mq->imq_msgcount) {
1206 		msgoff = seqno - mq->imq_seqno;
1207 	} else {
1208 		goto out;
1209 	}
1210 
1211 	/* look for the message that would match that seqno */
1212 	kmsgq = &mq->imq_messages;
1213 	kmsg = ipc_kmsg_queue_first(kmsgq);
1214 	while (msgoff-- && kmsg != IKM_NULL) {
1215 		kmsg = ipc_kmsg_queue_next(kmsgq, kmsg);
1216 	}
1217 	if (kmsg == IKM_NULL) {
1218 		goto out;
1219 	}
1220 
1221 #if __has_feature(ptrauth_calls)
1222 	/*
1223 	 * Validate kmsg signature before doing anything with it. Since we are holding
1224 	 * the mqueue lock here, and only header + trailer will be peeked on, just
1225 	 * do a partial validation to finish quickly.
1226 	 *
1227 	 * Partial kmsg signature is only supported on PAC devices.
1228 	 */
1229 	ipc_kmsg_validate_sig(kmsg, true);
1230 #endif
1231 
1232 	hdr = ikm_header(kmsg);
1233 	/* found one - return the requested info */
1234 	if (seqnop != NULL) {
1235 		*seqnop = seqno;
1236 	}
1237 	if (msg_sizep != NULL) {
1238 		*msg_sizep = hdr->msgh_size;
1239 	}
1240 	if (msg_idp != NULL) {
1241 		*msg_idp = hdr->msgh_id;
1242 	}
1243 	if (msg_trailerp != NULL) {
1244 		memcpy(msg_trailerp, ipc_kmsg_get_trailer(kmsg, false), sizeof(mach_msg_max_trailer_t));
1245 	}
1246 	if (kmsgp != NULL) {
1247 		*kmsgp = kmsg;
1248 	}
1249 
1250 	res = 1;
1251 
1252 out:
1253 	return res;
1254 }
1255 
1256 
1257 /*
1258  *	Routine:	ipc_mqueue_peek
1259  *	Purpose:
1260  *		Peek at a (non-set) message queue to see if it has a message
1261  *		matching the sequence number provided (if zero, then the
1262  *		first message in the queue) and return vital info about the
1263  *		message.
1264  *
1265  *	Conditions:
1266  *		The ipc_mqueue_t is unlocked.
1267  *		Locks may be held by callers, so this routine cannot block.
1268  *		Caller holds reference on the message queue.
1269  */
1270 unsigned
ipc_mqueue_peek(ipc_mqueue_t mq,mach_port_seqno_t * seqnop,mach_msg_size_t * msg_sizep,mach_msg_id_t * msg_idp,mach_msg_max_trailer_t * msg_trailerp,ipc_kmsg_t * kmsgp)1271 ipc_mqueue_peek(ipc_mqueue_t mq,
1272     mach_port_seqno_t * seqnop,
1273     mach_msg_size_t * msg_sizep,
1274     mach_msg_id_t * msg_idp,
1275     mach_msg_max_trailer_t * msg_trailerp,
1276     ipc_kmsg_t *kmsgp)
1277 {
1278 	ipc_port_t port = ip_from_mq(mq);
1279 	unsigned res;
1280 
1281 	ip_mq_lock(port);
1282 
1283 	res = ipc_mqueue_peek_locked(mq, seqnop, msg_sizep, msg_idp,
1284 	    msg_trailerp, kmsgp);
1285 
1286 	ip_mq_unlock(port);
1287 	return res;
1288 }
1289 
1290 #if MACH_FLIPC
1291 /*
1292  *	Routine:	ipc_mqueue_release_peek_ref
1293  *	Purpose:
1294  *		Release the reference on an mqueue's associated port which was
1295  *		granted to a thread in ipc_mqueue_peek_on_thread (on the
1296  *		MACH64_PEEK_MSG thread wakeup path).
1297  *
1298  *	Conditions:
1299  *		The ipc_mqueue_t should be locked on entry.
1300  *		The ipc_mqueue_t will be _unlocked_ on return
1301  *			(and potentially invalid!)
1302  *
1303  */
1304 void
ipc_mqueue_release_peek_ref(ipc_mqueue_t mqueue)1305 ipc_mqueue_release_peek_ref(ipc_mqueue_t mqueue)
1306 {
1307 	ipc_port_t port = ip_from_mq(mqueue);
1308 
1309 	ip_mq_lock_held(port);
1310 
1311 	/*
1312 	 * clear any preposts this mq may have generated
1313 	 * (which would cause subsequent immediate wakeups)
1314 	 */
1315 	waitq_clear_prepost_locked(&port->ip_waitq);
1316 
1317 	ip_mq_unlock(port);
1318 
1319 	/*
1320 	 * release the port reference: we need to do this outside the lock
1321 	 * because we might be holding the last port reference!
1322 	 **/
1323 	ip_release(port);
1324 }
1325 #endif /* MACH_FLIPC */
1326 
1327 /*
1328  *	Routine:	ipc_mqueue_destroy_locked
1329  *	Purpose:
1330  *		Destroy a message queue.
1331  *		Set any blocked senders running.
1332  *		Destroy the kmsgs in the queue.
1333  *	Conditions:
1334  *		port locked
1335  *		Receivers were removed when the receive right was "changed"
1336  */
1337 boolean_t
ipc_mqueue_destroy_locked(ipc_mqueue_t mqueue,waitq_link_list_t * free_l)1338 ipc_mqueue_destroy_locked(ipc_mqueue_t mqueue, waitq_link_list_t *free_l)
1339 {
1340 	ipc_port_t port = ip_from_mq(mqueue);
1341 	boolean_t reap = FALSE;
1342 	struct turnstile *send_turnstile = port_send_turnstile(port);
1343 
1344 	/*
1345 	 *	rouse all blocked senders
1346 	 *	(don't boost anyone - we're tearing this queue down)
1347 	 *	(never preposts)
1348 	 */
1349 	port->ip_fullwaiters = false;
1350 
1351 	if (send_turnstile != TURNSTILE_NULL) {
1352 		waitq_wakeup64_all(&send_turnstile->ts_waitq,
1353 		    IPC_MQUEUE_FULL,
1354 		    THREAD_RESTART, WAITQ_WAKEUP_DEFAULT);
1355 	}
1356 
1357 #if MACH_FLIPC
1358 	ipc_kmsg_t kmsg;
1359 
1360 	cqe_foreach_element_safe(kmsg, &mqueue->imq_messages, ikm_link) {
1361 		if (MACH_NODE_VALID(kmsg->ikm_node) &&
1362 		    FPORT_VALID(mqueue->imq_fport)) {
1363 			flipc_msg_ack(kmsg->ikm_node, mqueue, TRUE);
1364 		}
1365 	}
1366 #endif
1367 
1368 	/*
1369 	 * Move messages from the specified queue to the per-thread
1370 	 * clean/drain queue while we have the mqueue lock.
1371 	 */
1372 	reap = ipc_kmsg_delayed_destroy_queue(&mqueue->imq_messages);
1373 
1374 	/*
1375 	 * Wipe out message count, both for messages about to be
1376 	 * reaped and for reserved space for (previously) woken senders.
1377 	 * This is the indication to them that their reserved space is gone
1378 	 * (the mqueue was destroyed).
1379 	 */
1380 	mqueue->imq_msgcount = 0;
1381 
1382 	/*
1383 	 * invalidate the waitq for subsequent mqueue operations,
1384 	 * the port lock could be dropped after invalidating the mqueue.
1385 	 */
1386 
1387 	waitq_invalidate(&port->ip_waitq);
1388 
1389 	waitq_unlink_all_locked(&port->ip_waitq, NULL, free_l);
1390 
1391 	return reap;
1392 }
1393 
1394 /*
1395  *	Routine:	ipc_mqueue_set_qlimit_locked
1396  *	Purpose:
1397  *		Changes a message queue limit; the maximum number
1398  *		of messages which may be queued.
1399  *	Conditions:
1400  *		Port locked.
1401  */
1402 
1403 void
ipc_mqueue_set_qlimit_locked(ipc_mqueue_t mqueue,mach_port_msgcount_t qlimit)1404 ipc_mqueue_set_qlimit_locked(
1405 	ipc_mqueue_t           mqueue,
1406 	mach_port_msgcount_t   qlimit)
1407 {
1408 	ipc_port_t port = ip_from_mq(mqueue);
1409 
1410 	assert(qlimit <= MACH_PORT_QLIMIT_MAX);
1411 
1412 	/* wake up senders allowed by the new qlimit */
1413 	if (qlimit > mqueue->imq_qlimit) {
1414 		mach_port_msgcount_t i, wakeup;
1415 		struct turnstile *send_turnstile = port_send_turnstile(port);
1416 
1417 		/* caution: wakeup, qlimit are unsigned */
1418 		wakeup = qlimit - mqueue->imq_qlimit;
1419 
1420 		for (i = 0; i < wakeup; i++) {
1421 			/*
1422 			 * boost the priority of the awoken thread
1423 			 * (WAITQ_PROMOTE_PRIORITY) to ensure it uses
1424 			 * the message queue slot we've just reserved.
1425 			 *
1426 			 * NOTE: this will never prepost
1427 			 */
1428 			if (send_turnstile == TURNSTILE_NULL ||
1429 			    waitq_wakeup64_one(&send_turnstile->ts_waitq,
1430 			    IPC_MQUEUE_FULL,
1431 			    THREAD_AWAKENED,
1432 			    WAITQ_PROMOTE_PRIORITY) == KERN_NOT_WAITING) {
1433 				port->ip_fullwaiters = false;
1434 				break;
1435 			}
1436 			mqueue->imq_msgcount++;  /* give it to the awakened thread */
1437 		}
1438 	}
1439 	mqueue->imq_qlimit = (uint16_t)qlimit;
1440 }
1441 
1442 /*
1443  *	Routine:	ipc_mqueue_set_seqno_locked
1444  *	Purpose:
1445  *		Changes an mqueue's sequence number.
1446  *	Conditions:
1447  *		Caller holds a reference to the queue's containing object.
1448  */
1449 void
ipc_mqueue_set_seqno_locked(ipc_mqueue_t mqueue,mach_port_seqno_t seqno)1450 ipc_mqueue_set_seqno_locked(
1451 	ipc_mqueue_t            mqueue,
1452 	mach_port_seqno_t       seqno)
1453 {
1454 	mqueue->imq_seqno = seqno;
1455 }
1456 
1457 
1458 /*
1459  *	Routine:	ipc_mqueue_copyin
1460  *	Purpose:
1461  *		Convert a name in a space to a message queue.
1462  *	Conditions:
1463  *		Nothing locked.  If successful, the caller gets a ref for
1464  *		for the object.	This ref ensures the continued existence of
1465  *		the queue.
1466  *	Returns:
1467  *		MACH_MSG_SUCCESS	Found a message queue.
1468  *		MACH_RCV_INVALID_NAME	The space is dead.
1469  *		MACH_RCV_INVALID_NAME	The name doesn't denote a right.
1470  *		MACH_RCV_INVALID_NAME
1471  *			The denoted right is not receive or port set.
1472  *		MACH_RCV_IN_SET		Receive right is a member of a set.
1473  */
1474 
1475 mach_msg_return_t
ipc_mqueue_copyin(ipc_space_t space,mach_port_name_t name,ipc_object_t * objectp)1476 ipc_mqueue_copyin(
1477 	ipc_space_t             space,
1478 	mach_port_name_t        name,
1479 	ipc_object_t            *objectp)
1480 {
1481 	ipc_entry_bits_t bits;
1482 	ipc_object_t object;
1483 	kern_return_t kr;
1484 
1485 	kr = ipc_right_lookup_read(space, name, &bits, &object);
1486 	if (kr != KERN_SUCCESS) {
1487 		return MACH_RCV_INVALID_NAME;
1488 	}
1489 	/* object is locked and active */
1490 
1491 	if (bits & MACH_PORT_TYPE_RECEIVE) {
1492 		__assert_only ipc_port_t port = ip_object_to_port(object);
1493 		assert(ip_get_receiver_name(port) == name);
1494 		assert(ip_in_space(port, space));
1495 	}
1496 	if (bits & (MACH_PORT_TYPE_RECEIVE | MACH_PORT_TYPE_PORT_SET)) {
1497 		io_reference(object);
1498 		io_unlock(object);
1499 	} else {
1500 		io_unlock(object);
1501 		/* guard exception if we never held the receive right in this entry */
1502 		if ((bits & MACH_PORT_TYPE_EX_RECEIVE) == 0) {
1503 			mach_port_guard_exception(name, 0, 0, kGUARD_EXC_RCV_INVALID_NAME);
1504 		}
1505 		return MACH_RCV_INVALID_NAME;
1506 	}
1507 
1508 	*objectp = object;
1509 	return MACH_MSG_SUCCESS;
1510 }
1511