]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_port.c
xnu-2050.24.15.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_port.c
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 Software.Distribution@CS.CMU.EDU
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 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 */
62 /*
63 */
64 /*
65 * File: ipc/ipc_port.c
66 * Author: Rich Draves
67 * Date: 1989
68 *
69 * Functions to manipulate IPC ports.
70 */
71
72 #include <norma_vm.h>
73 #include <zone_debug.h>
74 #include <mach_assert.h>
75
76 #include <mach/port.h>
77 #include <mach/kern_return.h>
78 #include <kern/lock.h>
79 #include <kern/ipc_kobject.h>
80 #include <kern/thread.h>
81 #include <kern/misc_protos.h>
82 #include <kern/wait_queue.h>
83 #include <ipc/ipc_entry.h>
84 #include <ipc/ipc_space.h>
85 #include <ipc/ipc_object.h>
86 #include <ipc/ipc_port.h>
87 #include <ipc/ipc_pset.h>
88 #include <ipc/ipc_kmsg.h>
89 #include <ipc/ipc_mqueue.h>
90 #include <ipc/ipc_notify.h>
91 #include <ipc/ipc_table.h>
92
93 #include <security/mac_mach_internal.h>
94
95 #include <string.h>
96
97 decl_lck_mtx_data(, ipc_port_multiple_lock_data)
98 lck_mtx_ext_t ipc_port_multiple_lock_data_ext;
99 ipc_port_timestamp_t ipc_port_timestamp_data;
100 int ipc_portbt;
101
102 #if MACH_ASSERT
103 void ipc_port_init_debug(
104 ipc_port_t port,
105 natural_t *callstack,
106 unsigned int callstack_max);
107
108 void ipc_port_callstack_init_debug(
109 natural_t *callstack,
110 unsigned int callstack_max);
111
112 #endif /* MACH_ASSERT */
113
114 void
115 ipc_port_release(ipc_port_t port)
116 {
117 ip_release(port);
118 }
119
120 void
121 ipc_port_reference(ipc_port_t port)
122 {
123 ip_reference(port);
124 }
125
126 /*
127 * Routine: ipc_port_timestamp
128 * Purpose:
129 * Retrieve a timestamp value.
130 */
131
132 ipc_port_timestamp_t
133 ipc_port_timestamp(void)
134 {
135 return OSIncrementAtomic(&ipc_port_timestamp_data);
136 }
137
138 /*
139 * Routine: ipc_port_request_alloc
140 * Purpose:
141 * Try to allocate a request slot.
142 * If successful, returns the request index.
143 * Otherwise returns zero.
144 * Conditions:
145 * The port is locked and active.
146 * Returns:
147 * KERN_SUCCESS A request index was found.
148 * KERN_NO_SPACE No index allocated.
149 */
150
151 kern_return_t
152 ipc_port_request_alloc(
153 ipc_port_t port,
154 mach_port_name_t name,
155 ipc_port_t soright,
156 boolean_t send_possible,
157 boolean_t immediate,
158 ipc_port_request_index_t *indexp)
159 {
160 ipc_port_request_t ipr, table;
161 ipc_port_request_index_t index;
162 uintptr_t mask = 0;
163
164 assert(ip_active(port));
165 assert(name != MACH_PORT_NULL);
166 assert(soright != IP_NULL);
167
168 table = port->ip_requests;
169
170 if (table == IPR_NULL)
171 return KERN_NO_SPACE;
172
173 index = table->ipr_next;
174 if (index == 0)
175 return KERN_NO_SPACE;
176
177 ipr = &table[index];
178 assert(ipr->ipr_name == MACH_PORT_NULL);
179
180 table->ipr_next = ipr->ipr_next;
181 ipr->ipr_name = name;
182
183 if (send_possible) {
184 mask |= IPR_SOR_SPREQ_MASK;
185 if (immediate) {
186 mask |= IPR_SOR_SPARM_MASK;
187 port->ip_sprequests = TRUE;
188 }
189 }
190 ipr->ipr_soright = IPR_SOR_MAKE(soright, mask);
191
192 *indexp = index;
193
194 return KERN_SUCCESS;
195 }
196
197 /*
198 * Routine: ipc_port_request_grow
199 * Purpose:
200 * Grow a port's table of requests.
201 * Conditions:
202 * The port must be locked and active.
203 * Nothing else locked; will allocate memory.
204 * Upon return the port is unlocked.
205 * Returns:
206 * KERN_SUCCESS Grew the table.
207 * KERN_SUCCESS Somebody else grew the table.
208 * KERN_SUCCESS The port died.
209 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
210 * KERN_NO_SPACE Couldn't grow to desired size
211 */
212
213 kern_return_t
214 ipc_port_request_grow(
215 ipc_port_t port,
216 ipc_table_elems_t target_size)
217 {
218 ipc_table_size_t its;
219 ipc_port_request_t otable, ntable;
220
221 assert(ip_active(port));
222
223 otable = port->ip_requests;
224 if (otable == IPR_NULL)
225 its = &ipc_table_requests[0];
226 else
227 its = otable->ipr_size + 1;
228
229 if (target_size != ITS_SIZE_NONE) {
230 if ((otable != IPR_NULL) &&
231 (target_size <= otable->ipr_size->its_size)) {
232 ip_unlock(port);
233 return KERN_SUCCESS;
234 }
235 while ((its->its_size) && (its->its_size < target_size)) {
236 its++;
237 }
238 if (its->its_size == 0) {
239 ip_unlock(port);
240 return KERN_NO_SPACE;
241 }
242 }
243
244 ip_reference(port);
245 ip_unlock(port);
246
247 if ((its->its_size == 0) ||
248 ((ntable = it_requests_alloc(its)) == IPR_NULL)) {
249 ip_release(port);
250 return KERN_RESOURCE_SHORTAGE;
251 }
252
253 ip_lock(port);
254
255 /*
256 * Check that port is still active and that nobody else
257 * has slipped in and grown the table on us. Note that
258 * just checking if the current table pointer == otable
259 * isn't sufficient; must check ipr_size.
260 */
261
262 if (ip_active(port) && (port->ip_requests == otable) &&
263 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
264 ipc_table_size_t oits;
265 ipc_table_elems_t osize, nsize;
266 ipc_port_request_index_t free, i;
267
268 /* copy old table to new table */
269
270 if (otable != IPR_NULL) {
271 oits = otable->ipr_size;
272 osize = oits->its_size;
273 free = otable->ipr_next;
274
275 (void) memcpy((void *)(ntable + 1),
276 (const void *)(otable + 1),
277 (osize - 1) * sizeof(struct ipc_port_request));
278 } else {
279 osize = 1;
280 oits = 0;
281 free = 0;
282 }
283
284 nsize = its->its_size;
285 assert(nsize > osize);
286
287 /* add new elements to the new table's free list */
288
289 for (i = osize; i < nsize; i++) {
290 ipc_port_request_t ipr = &ntable[i];
291
292 ipr->ipr_name = MACH_PORT_NULL;
293 ipr->ipr_next = free;
294 free = i;
295 }
296
297 ntable->ipr_next = free;
298 ntable->ipr_size = its;
299 port->ip_requests = ntable;
300 ip_unlock(port);
301 ip_release(port);
302
303 if (otable != IPR_NULL) {
304 it_requests_free(oits, otable);
305 }
306 } else {
307 ip_unlock(port);
308 ip_release(port);
309 it_requests_free(its, ntable);
310 }
311
312 return KERN_SUCCESS;
313 }
314
315 /*
316 * Routine: ipc_port_request_sparm
317 * Purpose:
318 * Arm delayed send-possible request.
319 * Conditions:
320 * The port must be locked and active.
321 */
322
323 void
324 ipc_port_request_sparm(
325 ipc_port_t port,
326 __assert_only mach_port_name_t name,
327 ipc_port_request_index_t index)
328 {
329 if (index != IE_REQ_NONE) {
330 ipc_port_request_t ipr, table;
331
332 assert(ip_active(port));
333
334 table = port->ip_requests;
335 assert(table != IPR_NULL);
336
337 ipr = &table[index];
338 assert(ipr->ipr_name == name);
339
340 if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
341 ipr->ipr_soright = IPR_SOR_MAKE(ipr->ipr_soright, IPR_SOR_SPARM_MASK);
342 port->ip_sprequests = TRUE;
343 }
344 }
345 }
346
347 /*
348 * Routine: ipc_port_request_type
349 * Purpose:
350 * Determine the type(s) of port requests enabled for a name.
351 * Conditions:
352 * The port must be locked or inactive (to avoid table growth).
353 * The index must not be IE_REQ_NONE and for the name in question.
354 */
355 mach_port_type_t
356 ipc_port_request_type(
357 ipc_port_t port,
358 __assert_only mach_port_name_t name,
359 ipc_port_request_index_t index)
360 {
361 ipc_port_request_t ipr, table;
362 mach_port_type_t type = 0;
363
364 table = port->ip_requests;
365 assert (table != IPR_NULL);
366
367 assert(index != IE_REQ_NONE);
368 ipr = &table[index];
369 assert(ipr->ipr_name == name);
370
371 if (IP_VALID(IPR_SOR_PORT(ipr->ipr_soright))) {
372 type |= MACH_PORT_TYPE_DNREQUEST;
373
374 if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
375 type |= MACH_PORT_TYPE_SPREQUEST;
376
377 if (!IPR_SOR_SPARMED(ipr->ipr_soright)) {
378 type |= MACH_PORT_TYPE_SPREQUEST_DELAYED;
379 }
380 }
381 }
382 return type;
383 }
384
385 /*
386 * Routine: ipc_port_request_cancel
387 * Purpose:
388 * Cancel a dead-name/send-possible request and return the send-once right.
389 * Conditions:
390 * The port must be locked and active.
391 * The index must not be IPR_REQ_NONE and must correspond with name.
392 */
393
394 ipc_port_t
395 ipc_port_request_cancel(
396 ipc_port_t port,
397 __assert_only mach_port_name_t name,
398 ipc_port_request_index_t index)
399 {
400 ipc_port_request_t ipr, table;
401 ipc_port_t request = IP_NULL;
402
403 assert(ip_active(port));
404 table = port->ip_requests;
405 assert(table != IPR_NULL);
406
407 assert (index != IE_REQ_NONE);
408 ipr = &table[index];
409 assert(ipr->ipr_name == name);
410 request = IPR_SOR_PORT(ipr->ipr_soright);
411
412 /* return ipr to the free list inside the table */
413 ipr->ipr_name = MACH_PORT_NULL;
414 ipr->ipr_next = table->ipr_next;
415 table->ipr_next = index;
416
417 return request;
418 }
419
420 /*
421 * Routine: ipc_port_pdrequest
422 * Purpose:
423 * Make a port-deleted request, returning the
424 * previously registered send-once right.
425 * Just cancels the previous request if notify is IP_NULL.
426 * Conditions:
427 * The port is locked and active. It is unlocked.
428 * Consumes a ref for notify (if non-null), and
429 * returns previous with a ref (if non-null).
430 */
431
432 void
433 ipc_port_pdrequest(
434 ipc_port_t port,
435 ipc_port_t notify,
436 ipc_port_t *previousp)
437 {
438 ipc_port_t previous;
439
440 assert(ip_active(port));
441
442 previous = port->ip_pdrequest;
443 port->ip_pdrequest = notify;
444 ip_unlock(port);
445
446 *previousp = previous;
447 }
448
449 /*
450 * Routine: ipc_port_nsrequest
451 * Purpose:
452 * Make a no-senders request, returning the
453 * previously registered send-once right.
454 * Just cancels the previous request if notify is IP_NULL.
455 * Conditions:
456 * The port is locked and active. It is unlocked.
457 * Consumes a ref for notify (if non-null), and
458 * returns previous with a ref (if non-null).
459 */
460
461 void
462 ipc_port_nsrequest(
463 ipc_port_t port,
464 mach_port_mscount_t sync,
465 ipc_port_t notify,
466 ipc_port_t *previousp)
467 {
468 ipc_port_t previous;
469 mach_port_mscount_t mscount;
470
471 assert(ip_active(port));
472
473 previous = port->ip_nsrequest;
474 mscount = port->ip_mscount;
475
476 if ((port->ip_srights == 0) && (sync <= mscount) &&
477 (notify != IP_NULL)) {
478 port->ip_nsrequest = IP_NULL;
479 ip_unlock(port);
480 ipc_notify_no_senders(notify, mscount);
481 } else {
482 port->ip_nsrequest = notify;
483 ip_unlock(port);
484 }
485
486 *previousp = previous;
487 }
488
489
490 /*
491 * Routine: ipc_port_clear_receiver
492 * Purpose:
493 * Prepares a receive right for transmission/destruction.
494 * Conditions:
495 * The port is locked and active.
496 */
497
498 void
499 ipc_port_clear_receiver(
500 ipc_port_t port,
501 queue_t links)
502 {
503 spl_t s;
504
505 assert(ip_active(port));
506
507 /*
508 * pull ourselves from any sets.
509 */
510 if (port->ip_pset_count != 0) {
511 ipc_pset_remove_from_all(port, links);
512 assert(port->ip_pset_count == 0);
513 }
514
515 /*
516 * Send anyone waiting on the port's queue directly away.
517 * Also clear the mscount and seqno.
518 */
519 s = splsched();
520 imq_lock(&port->ip_messages);
521 ipc_mqueue_changed(&port->ip_messages);
522 ipc_port_set_mscount(port, 0);
523 port->ip_messages.imq_seqno = 0;
524 imq_unlock(&port->ip_messages);
525 splx(s);
526 }
527
528 /*
529 * Routine: ipc_port_init
530 * Purpose:
531 * Initializes a newly-allocated port.
532 * Doesn't touch the ip_object fields.
533 */
534
535 void
536 ipc_port_init(
537 ipc_port_t port,
538 ipc_space_t space,
539 mach_port_name_t name)
540 {
541 /* port->ip_kobject doesn't have to be initialized */
542
543 port->ip_receiver = space;
544 port->ip_receiver_name = name;
545
546 port->ip_mscount = 0;
547 port->ip_srights = 0;
548 port->ip_sorights = 0;
549
550 port->ip_nsrequest = IP_NULL;
551 port->ip_pdrequest = IP_NULL;
552 port->ip_requests = IPR_NULL;
553
554 port->ip_pset_count = 0;
555 port->ip_premsg = IKM_NULL;
556 port->ip_context = 0;
557
558 ipc_mqueue_init(&port->ip_messages, FALSE /* set */);
559 }
560
561 /*
562 * Routine: ipc_port_alloc
563 * Purpose:
564 * Allocate a port.
565 * Conditions:
566 * Nothing locked. If successful, the port is returned
567 * locked. (The caller doesn't have a reference.)
568 * Returns:
569 * KERN_SUCCESS The port is allocated.
570 * KERN_INVALID_TASK The space is dead.
571 * KERN_NO_SPACE No room for an entry in the space.
572 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
573 */
574
575 kern_return_t
576 ipc_port_alloc(
577 ipc_space_t space,
578 mach_port_name_t *namep,
579 ipc_port_t *portp)
580 {
581 ipc_port_t port;
582 mach_port_name_t name;
583 kern_return_t kr;
584
585 #if MACH_ASSERT
586 natural_t buf[IP_CALLSTACK_MAX];
587 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
588 #endif /* MACH_ASSERT */
589
590 kr = ipc_object_alloc(space, IOT_PORT,
591 MACH_PORT_TYPE_RECEIVE, 0,
592 &name, (ipc_object_t *) &port);
593 if (kr != KERN_SUCCESS)
594 return kr;
595
596 /* port and space are locked */
597 ipc_port_init(port, space, name);
598
599 #if MACH_ASSERT
600 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
601 #endif /* MACH_ASSERT */
602
603 /* unlock space after init */
604 is_write_unlock(space);
605
606 #if CONFIG_MACF_MACH
607 task_t issuer = current_task();
608 tasklabel_lock2 (issuer, space->is_task);
609 mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
610 &port->ip_label);
611 tasklabel_unlock2 (issuer, space->is_task);
612 #endif
613
614 *namep = name;
615 *portp = port;
616
617 return KERN_SUCCESS;
618 }
619
620 /*
621 * Routine: ipc_port_alloc_name
622 * Purpose:
623 * Allocate a port, with a specific name.
624 * Conditions:
625 * Nothing locked. If successful, the port is returned
626 * locked. (The caller doesn't have a reference.)
627 * Returns:
628 * KERN_SUCCESS The port is allocated.
629 * KERN_INVALID_TASK The space is dead.
630 * KERN_NAME_EXISTS The name already denotes a right.
631 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
632 */
633
634 kern_return_t
635 ipc_port_alloc_name(
636 ipc_space_t space,
637 mach_port_name_t name,
638 ipc_port_t *portp)
639 {
640 ipc_port_t port;
641 kern_return_t kr;
642
643 #if MACH_ASSERT
644 natural_t buf[IP_CALLSTACK_MAX];
645 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
646 #endif /* MACH_ASSERT */
647
648 kr = ipc_object_alloc_name(space, IOT_PORT,
649 MACH_PORT_TYPE_RECEIVE, 0,
650 name, (ipc_object_t *) &port);
651 if (kr != KERN_SUCCESS)
652 return kr;
653
654 /* port is locked */
655
656 ipc_port_init(port, space, name);
657
658 #if MACH_ASSERT
659 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
660 #endif /* MACH_ASSERT */
661
662 #if CONFIG_MACF_MACH
663 task_t issuer = current_task();
664 tasklabel_lock2 (issuer, space->is_task);
665 mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
666 &port->ip_label);
667 tasklabel_unlock2 (issuer, space->is_task);
668 #endif
669
670 *portp = port;
671
672 return KERN_SUCCESS;
673 }
674
675 /*
676 * Routine: ipc_port_spnotify
677 * Purpose:
678 * Generate send-possible port notifications.
679 * Conditions:
680 * Nothing locked, reference held on port.
681 */
682 void
683 ipc_port_spnotify(
684 ipc_port_t port)
685 {
686 ipc_port_request_index_t index = 0;
687 ipc_table_elems_t size = 0;
688
689 /*
690 * If the port has no send-possible request
691 * armed, don't bother to lock the port.
692 */
693 if (!port->ip_sprequests)
694 return;
695
696 ip_lock(port);
697 if (!port->ip_sprequests) {
698 ip_unlock(port);
699 return;
700 }
701 port->ip_sprequests = FALSE;
702
703 revalidate:
704 if (ip_active(port)) {
705 ipc_port_request_t requests;
706
707 /* table may change each time port unlocked (reload) */
708 requests = port->ip_requests;
709 assert(requests != IPR_NULL);
710
711 /*
712 * no need to go beyond table size when first
713 * we entered - those are future notifications.
714 */
715 if (size == 0)
716 size = requests->ipr_size->its_size;
717
718 /* no need to backtrack either */
719 while (++index < size) {
720 ipc_port_request_t ipr = &requests[index];
721 mach_port_name_t name = ipr->ipr_name;
722 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
723 boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
724
725 if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
726 /* claim send-once right - slot still inuse */
727 ipr->ipr_soright = IP_NULL;
728 ip_unlock(port);
729
730 ipc_notify_send_possible(soright, name);
731
732 ip_lock(port);
733 goto revalidate;
734 }
735 }
736 }
737 ip_unlock(port);
738 }
739
740 /*
741 * Routine: ipc_port_dnnotify
742 * Purpose:
743 * Generate dead name notifications for
744 * all outstanding dead-name and send-
745 * possible requests.
746 * Conditions:
747 * Nothing locked.
748 * Port must be inactive.
749 * Reference held on port.
750 */
751 void
752 ipc_port_dnnotify(
753 ipc_port_t port)
754 {
755 ipc_port_request_t requests = port->ip_requests;
756
757 assert(!ip_active(port));
758 if (requests != IPR_NULL) {
759 ipc_table_size_t its = requests->ipr_size;
760 ipc_table_elems_t size = its->its_size;
761 ipc_port_request_index_t index;
762 for (index = 1; index < size; index++) {
763 ipc_port_request_t ipr = &requests[index];
764 mach_port_name_t name = ipr->ipr_name;
765 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
766
767 if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
768 ipc_notify_dead_name(soright, name);
769 }
770 }
771 }
772 }
773
774
775 /*
776 * Routine: ipc_port_destroy
777 * Purpose:
778 * Destroys a port. Cleans up queued messages.
779 *
780 * If the port has a backup, it doesn't get destroyed,
781 * but is sent in a port-destroyed notification to the backup.
782 * Conditions:
783 * The port is locked and alive; nothing else locked.
784 * The caller has a reference, which is consumed.
785 * Afterwards, the port is unlocked and dead.
786 */
787
788 void
789 ipc_port_destroy(
790 ipc_port_t port)
791 {
792 ipc_port_t pdrequest, nsrequest;
793 ipc_mqueue_t mqueue;
794 ipc_kmsg_t kmsg;
795
796 assert(ip_active(port));
797 /* port->ip_receiver_name is garbage */
798 /* port->ip_receiver/port->ip_destination is garbage */
799 assert(port->ip_pset_count == 0);
800 assert(port->ip_mscount == 0);
801
802 /* first check for a backup port */
803
804 pdrequest = port->ip_pdrequest;
805 if (pdrequest != IP_NULL) {
806 /* we assume the ref for pdrequest */
807 port->ip_pdrequest = IP_NULL;
808
809 /* make port be in limbo */
810 port->ip_receiver_name = MACH_PORT_NULL;
811 port->ip_destination = IP_NULL;
812 ip_unlock(port);
813
814 /* consumes our refs for port and pdrequest */
815 ipc_notify_port_destroyed(pdrequest, port);
816 return;
817 }
818
819 /* once port is dead, we don't need to keep it locked */
820
821 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
822 port->ip_timestamp = ipc_port_timestamp();
823
824 /*
825 * If the port has a preallocated message buffer and that buffer
826 * is not inuse, free it. If it has an inuse one, then the kmsg
827 * free will detect that we freed the association and it can free it
828 * like a normal buffer.
829 */
830 if (IP_PREALLOC(port)) {
831 ipc_port_t inuse_port;
832
833 kmsg = port->ip_premsg;
834 assert(kmsg != IKM_NULL);
835 inuse_port = ikm_prealloc_inuse_port(kmsg);
836 IP_CLEAR_PREALLOC(port, kmsg);
837 ip_unlock(port);
838 if (inuse_port != IP_NULL) {
839 assert(inuse_port == port);
840 } else {
841 ipc_kmsg_free(kmsg);
842 }
843 } else {
844 ip_unlock(port);
845 }
846
847 /* throw away no-senders request */
848 nsrequest = port->ip_nsrequest;
849 if (nsrequest != IP_NULL)
850 ipc_notify_send_once(nsrequest); /* consumes ref */
851
852 /* destroy any queued messages */
853 mqueue = &port->ip_messages;
854 ipc_mqueue_destroy(mqueue);
855
856 /* generate dead-name notifications */
857 ipc_port_dnnotify(port);
858
859 ipc_kobject_destroy(port);
860
861 ip_release(port); /* consume caller's ref */
862 }
863
864 /*
865 * Routine: ipc_port_check_circularity
866 * Purpose:
867 * Check if queueing "port" in a message for "dest"
868 * would create a circular group of ports and messages.
869 *
870 * If no circularity (FALSE returned), then "port"
871 * is changed from "in limbo" to "in transit".
872 *
873 * That is, we want to set port->ip_destination == dest,
874 * but guaranteeing that this doesn't create a circle
875 * port->ip_destination->ip_destination->... == port
876 * Conditions:
877 * No ports locked. References held for "port" and "dest".
878 */
879
880 boolean_t
881 ipc_port_check_circularity(
882 ipc_port_t port,
883 ipc_port_t dest)
884 {
885 ipc_port_t base;
886
887 assert(port != IP_NULL);
888 assert(dest != IP_NULL);
889
890 if (port == dest)
891 return TRUE;
892 base = dest;
893
894 /*
895 * First try a quick check that can run in parallel.
896 * No circularity if dest is not in transit.
897 */
898
899 ip_lock(port);
900 if (ip_lock_try(dest)) {
901 if (!ip_active(dest) ||
902 (dest->ip_receiver_name != MACH_PORT_NULL) ||
903 (dest->ip_destination == IP_NULL))
904 goto not_circular;
905
906 /* dest is in transit; further checking necessary */
907
908 ip_unlock(dest);
909 }
910 ip_unlock(port);
911
912 ipc_port_multiple_lock(); /* massive serialization */
913
914 /*
915 * Search for the end of the chain (a port not in transit),
916 * acquiring locks along the way.
917 */
918
919 for (;;) {
920 ip_lock(base);
921
922 if (!ip_active(base) ||
923 (base->ip_receiver_name != MACH_PORT_NULL) ||
924 (base->ip_destination == IP_NULL))
925 break;
926
927 base = base->ip_destination;
928 }
929
930 /* all ports in chain from dest to base, inclusive, are locked */
931
932 if (port == base) {
933 /* circularity detected! */
934
935 ipc_port_multiple_unlock();
936
937 /* port (== base) is in limbo */
938
939 assert(ip_active(port));
940 assert(port->ip_receiver_name == MACH_PORT_NULL);
941 assert(port->ip_destination == IP_NULL);
942
943 while (dest != IP_NULL) {
944 ipc_port_t next;
945
946 /* dest is in transit or in limbo */
947
948 assert(ip_active(dest));
949 assert(dest->ip_receiver_name == MACH_PORT_NULL);
950
951 next = dest->ip_destination;
952 ip_unlock(dest);
953 dest = next;
954 }
955
956 return TRUE;
957 }
958
959 /*
960 * The guarantee: lock port while the entire chain is locked.
961 * Once port is locked, we can take a reference to dest,
962 * add port to the chain, and unlock everything.
963 */
964
965 ip_lock(port);
966 ipc_port_multiple_unlock();
967
968 not_circular:
969
970 /* port is in limbo */
971
972 assert(ip_active(port));
973 assert(port->ip_receiver_name == MACH_PORT_NULL);
974 assert(port->ip_destination == IP_NULL);
975
976 ip_reference(dest);
977 port->ip_destination = dest;
978
979 /* now unlock chain */
980
981 while (port != base) {
982 ipc_port_t next;
983
984 /* port is in transit */
985
986 assert(ip_active(port));
987 assert(port->ip_receiver_name == MACH_PORT_NULL);
988 assert(port->ip_destination != IP_NULL);
989
990 next = port->ip_destination;
991 ip_unlock(port);
992 port = next;
993 }
994
995 /* base is not in transit */
996
997 assert(!ip_active(base) ||
998 (base->ip_receiver_name != MACH_PORT_NULL) ||
999 (base->ip_destination == IP_NULL));
1000 ip_unlock(base);
1001
1002 return FALSE;
1003 }
1004
1005 /*
1006 * Routine: ipc_port_lookup_notify
1007 * Purpose:
1008 * Make a send-once notify port from a receive right.
1009 * Returns IP_NULL if name doesn't denote a receive right.
1010 * Conditions:
1011 * The space must be locked (read or write) and active.
1012 * Being the active space, we can rely on thread server_id
1013 * context to give us the proper server level sub-order
1014 * within the space.
1015 */
1016
1017 ipc_port_t
1018 ipc_port_lookup_notify(
1019 ipc_space_t space,
1020 mach_port_name_t name)
1021 {
1022 ipc_port_t port;
1023 ipc_entry_t entry;
1024
1025 assert(is_active(space));
1026
1027 entry = ipc_entry_lookup(space, name);
1028 if (entry == IE_NULL)
1029 return IP_NULL;
1030 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1031 return IP_NULL;
1032
1033 port = (ipc_port_t) entry->ie_object;
1034 assert(port != IP_NULL);
1035
1036 ip_lock(port);
1037 assert(ip_active(port));
1038 assert(port->ip_receiver_name == name);
1039 assert(port->ip_receiver == space);
1040
1041 ip_reference(port);
1042 port->ip_sorights++;
1043 ip_unlock(port);
1044
1045 return port;
1046 }
1047
1048 /*
1049 * Routine: ipc_port_make_send_locked
1050 * Purpose:
1051 * Make a naked send right from a receive right.
1052 *
1053 * Conditions:
1054 * port locked and active.
1055 */
1056 ipc_port_t
1057 ipc_port_make_send_locked(
1058 ipc_port_t port)
1059 {
1060 assert(ip_active(port));
1061 port->ip_mscount++;
1062 port->ip_srights++;
1063 ip_reference(port);
1064 ip_unlock(port);
1065 return port;
1066 }
1067
1068 /*
1069 * Routine: ipc_port_make_send
1070 * Purpose:
1071 * Make a naked send right from a receive right.
1072 */
1073
1074 ipc_port_t
1075 ipc_port_make_send(
1076 ipc_port_t port)
1077 {
1078
1079 if (!IP_VALID(port))
1080 return port;
1081
1082 ip_lock(port);
1083 if (ip_active(port)) {
1084 port->ip_mscount++;
1085 port->ip_srights++;
1086 ip_reference(port);
1087 ip_unlock(port);
1088 return port;
1089 }
1090 ip_unlock(port);
1091 return IP_DEAD;
1092 }
1093
1094 /*
1095 * Routine: ipc_port_copy_send
1096 * Purpose:
1097 * Make a naked send right from another naked send right.
1098 * IP_NULL -> IP_NULL
1099 * IP_DEAD -> IP_DEAD
1100 * dead port -> IP_DEAD
1101 * live port -> port + ref
1102 * Conditions:
1103 * Nothing locked except possibly a space.
1104 */
1105
1106 ipc_port_t
1107 ipc_port_copy_send(
1108 ipc_port_t port)
1109 {
1110 ipc_port_t sright;
1111
1112 if (!IP_VALID(port))
1113 return port;
1114
1115 ip_lock(port);
1116 if (ip_active(port)) {
1117 assert(port->ip_srights > 0);
1118
1119 ip_reference(port);
1120 port->ip_srights++;
1121 sright = port;
1122 } else
1123 sright = IP_DEAD;
1124 ip_unlock(port);
1125
1126 return sright;
1127 }
1128
1129 /*
1130 * Routine: ipc_port_copyout_send
1131 * Purpose:
1132 * Copyout a naked send right (possibly null/dead),
1133 * or if that fails, destroy the right.
1134 * Conditions:
1135 * Nothing locked.
1136 */
1137
1138 mach_port_name_t
1139 ipc_port_copyout_send(
1140 ipc_port_t sright,
1141 ipc_space_t space)
1142 {
1143 mach_port_name_t name;
1144
1145 if (IP_VALID(sright)) {
1146 kern_return_t kr;
1147
1148 kr = ipc_object_copyout(space, (ipc_object_t) sright,
1149 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
1150 if (kr != KERN_SUCCESS) {
1151 ipc_port_release_send(sright);
1152
1153 if (kr == KERN_INVALID_CAPABILITY)
1154 name = MACH_PORT_DEAD;
1155 else
1156 name = MACH_PORT_NULL;
1157 }
1158 } else
1159 name = CAST_MACH_PORT_TO_NAME(sright);
1160
1161 return name;
1162 }
1163
1164 /*
1165 * Routine: ipc_port_release_send
1166 * Purpose:
1167 * Release a naked send right.
1168 * Consumes a ref for the port.
1169 * Conditions:
1170 * Nothing locked.
1171 */
1172
1173 void
1174 ipc_port_release_send(
1175 ipc_port_t port)
1176 {
1177 ipc_port_t nsrequest = IP_NULL;
1178 mach_port_mscount_t mscount;
1179
1180 if (!IP_VALID(port))
1181 return;
1182
1183 ip_lock(port);
1184
1185 if (!ip_active(port)) {
1186 ip_unlock(port);
1187 ip_release(port);
1188 return;
1189 }
1190
1191 assert(port->ip_srights > 0);
1192
1193 if (--port->ip_srights == 0 &&
1194 port->ip_nsrequest != IP_NULL) {
1195 nsrequest = port->ip_nsrequest;
1196 port->ip_nsrequest = IP_NULL;
1197 mscount = port->ip_mscount;
1198 ip_unlock(port);
1199 ip_release(port);
1200 ipc_notify_no_senders(nsrequest, mscount);
1201 } else {
1202 ip_unlock(port);
1203 ip_release(port);
1204 }
1205 }
1206
1207 /*
1208 * Routine: ipc_port_make_sonce_locked
1209 * Purpose:
1210 * Make a naked send-once right from a receive right.
1211 * Conditions:
1212 * The port is locked and active.
1213 */
1214
1215 ipc_port_t
1216 ipc_port_make_sonce_locked(
1217 ipc_port_t port)
1218 {
1219 assert(ip_active(port));
1220 port->ip_sorights++;
1221 ip_reference(port);
1222 return port;
1223 }
1224
1225 /*
1226 * Routine: ipc_port_make_sonce
1227 * Purpose:
1228 * Make a naked send-once right from a receive right.
1229 * Conditions:
1230 * The port is not locked.
1231 */
1232
1233 ipc_port_t
1234 ipc_port_make_sonce(
1235 ipc_port_t port)
1236 {
1237 if (!IP_VALID(port))
1238 return port;
1239
1240 ip_lock(port);
1241 if (ip_active(port)) {
1242 port->ip_sorights++;
1243 ip_reference(port);
1244 ip_unlock(port);
1245 return port;
1246 }
1247 ip_unlock(port);
1248 return IP_DEAD;
1249 }
1250
1251 /*
1252 * Routine: ipc_port_release_sonce
1253 * Purpose:
1254 * Release a naked send-once right.
1255 * Consumes a ref for the port.
1256 *
1257 * In normal situations, this is never used.
1258 * Send-once rights are only consumed when
1259 * a message (possibly a send-once notification)
1260 * is sent to them.
1261 * Conditions:
1262 * Nothing locked except possibly a space.
1263 */
1264
1265 void
1266 ipc_port_release_sonce(
1267 ipc_port_t port)
1268 {
1269 if (!IP_VALID(port))
1270 return;
1271
1272 ip_lock(port);
1273
1274 assert(port->ip_sorights > 0);
1275
1276 port->ip_sorights--;
1277
1278 ip_unlock(port);
1279 ip_release(port);
1280 }
1281
1282 /*
1283 * Routine: ipc_port_release_receive
1284 * Purpose:
1285 * Release a naked (in limbo or in transit) receive right.
1286 * Consumes a ref for the port; destroys the port.
1287 * Conditions:
1288 * Nothing locked.
1289 */
1290
1291 void
1292 ipc_port_release_receive(
1293 ipc_port_t port)
1294 {
1295 ipc_port_t dest;
1296
1297 if (!IP_VALID(port))
1298 return;
1299
1300 ip_lock(port);
1301 assert(ip_active(port));
1302 assert(port->ip_receiver_name == MACH_PORT_NULL);
1303 dest = port->ip_destination;
1304
1305 ipc_port_destroy(port); /* consumes ref, unlocks */
1306
1307 if (dest != IP_NULL)
1308 ip_release(dest);
1309 }
1310
1311 /*
1312 * Routine: ipc_port_alloc_special
1313 * Purpose:
1314 * Allocate a port in a special space.
1315 * The new port is returned with one ref.
1316 * If unsuccessful, IP_NULL is returned.
1317 * Conditions:
1318 * Nothing locked.
1319 */
1320
1321 ipc_port_t
1322 ipc_port_alloc_special(
1323 ipc_space_t space)
1324 {
1325 ipc_port_t port;
1326
1327 port = (ipc_port_t) io_alloc(IOT_PORT);
1328 if (port == IP_NULL)
1329 return IP_NULL;
1330
1331 #if MACH_ASSERT
1332 natural_t buf[IP_CALLSTACK_MAX];
1333 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
1334 #endif /* MACH_ASSERT */
1335
1336 bzero((char *)port, sizeof(*port));
1337 io_lock_init(&port->ip_object);
1338 port->ip_references = 1;
1339 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1340
1341 ipc_port_init(port, space, 1);
1342
1343 #if MACH_ASSERT
1344 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
1345 #endif /* MACH_ASSERT */
1346
1347 #if CONFIG_MACF_MACH
1348 /* Currently, ipc_port_alloc_special is used for two things:
1349 * - Reply ports for messages from the kernel
1350 * - Ports for communication with the kernel (e.g. task ports)
1351 * Since both of these would typically be labelled as kernel objects,
1352 * we will use a new entry point for this purpose, as current_task()
1353 * is often wrong (i.e. not kernel_task) or null.
1354 */
1355 mac_port_label_init(&port->ip_label);
1356 mac_port_label_associate_kernel(&port->ip_label, space == ipc_space_reply);
1357 #endif
1358
1359 return port;
1360 }
1361
1362 /*
1363 * Routine: ipc_port_dealloc_special
1364 * Purpose:
1365 * Deallocate a port in a special space.
1366 * Consumes one ref for the port.
1367 * Conditions:
1368 * Nothing locked.
1369 */
1370
1371 void
1372 ipc_port_dealloc_special(
1373 ipc_port_t port,
1374 __assert_only ipc_space_t space)
1375 {
1376 ip_lock(port);
1377 assert(ip_active(port));
1378 // assert(port->ip_receiver_name != MACH_PORT_NULL);
1379 assert(port->ip_receiver == space);
1380
1381 /*
1382 * We clear ip_receiver_name and ip_receiver to simplify
1383 * the ipc_space_kernel check in ipc_mqueue_send.
1384 */
1385
1386 port->ip_receiver_name = MACH_PORT_NULL;
1387 port->ip_receiver = IS_NULL;
1388
1389 /* relevant part of ipc_port_clear_receiver */
1390 ipc_port_set_mscount(port, 0);
1391 port->ip_messages.imq_seqno = 0;
1392
1393 ipc_port_destroy(port);
1394 }
1395
1396 /*
1397 * Routine: ipc_port_finalize
1398 * Purpose:
1399 * Called on last reference deallocate to
1400 * free any remaining data associated with the
1401 * port.
1402 * Conditions:
1403 * Nothing locked.
1404 */
1405 void
1406 ipc_port_finalize(
1407 ipc_port_t port)
1408 {
1409 ipc_port_request_t requests = port->ip_requests;
1410
1411 assert(!ip_active(port));
1412 if (requests != IPR_NULL) {
1413 ipc_table_size_t its = requests->ipr_size;
1414 it_requests_free(its, requests);
1415 port->ip_requests = IPR_NULL;
1416 }
1417
1418 #if MACH_ASSERT
1419 ipc_port_track_dealloc(port);
1420 #endif /* MACH_ASSERT */
1421
1422 #if CONFIG_MACF_MACH
1423 /* Port label should have been initialized after creation. */
1424 mac_port_label_destroy(&port->ip_label);
1425 #endif
1426 }
1427
1428 #if MACH_ASSERT
1429 #include <kern/machine.h>
1430
1431 /*
1432 * Keep a list of all allocated ports.
1433 * Allocation is intercepted via ipc_port_init;
1434 * deallocation is intercepted via io_free.
1435 */
1436 queue_head_t port_alloc_queue;
1437 lck_spin_t port_alloc_queue_lock;
1438
1439 unsigned long port_count = 0;
1440 unsigned long port_count_warning = 20000;
1441 unsigned long port_timestamp = 0;
1442
1443 void db_port_stack_trace(
1444 ipc_port_t port);
1445 void db_ref(
1446 int refs);
1447 int db_port_walk(
1448 unsigned int verbose,
1449 unsigned int display,
1450 unsigned int ref_search,
1451 unsigned int ref_target);
1452
1453 /*
1454 * Initialize global state needed for run-time
1455 * port debugging.
1456 */
1457 void
1458 ipc_port_debug_init(void)
1459 {
1460 queue_init(&port_alloc_queue);
1461
1462 lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr);
1463
1464 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
1465 ipc_portbt = 0;
1466 }
1467
1468 #ifdef MACH_BSD
1469 extern int proc_pid(struct proc*);
1470 #endif /* MACH_BSD */
1471
1472 /*
1473 * Initialize all of the debugging state in a port.
1474 * Insert the port into a global list of all allocated ports.
1475 */
1476 void
1477 ipc_port_init_debug(
1478 ipc_port_t port,
1479 natural_t *callstack,
1480 unsigned int callstack_max)
1481 {
1482 unsigned int i;
1483
1484 port->ip_thread = current_thread();
1485 port->ip_timetrack = port_timestamp++;
1486 for (i = 0; i < callstack_max; ++i)
1487 port->ip_callstack[i] = callstack[i];
1488 for (i = 0; i < IP_NSPARES; ++i)
1489 port->ip_spares[i] = 0;
1490
1491 #ifdef MACH_BSD
1492 task_t task = current_task();
1493 if (task != TASK_NULL) {
1494 struct proc* proc = (struct proc*) get_bsdtask_info(task);
1495 if (proc)
1496 port->ip_spares[0] = proc_pid(proc);
1497 }
1498 #endif /* MACH_BSD */
1499
1500 #if 0
1501 lck_spin_lock(&port_alloc_queue_lock);
1502 ++port_count;
1503 if (port_count_warning > 0 && port_count >= port_count_warning)
1504 assert(port_count < port_count_warning);
1505 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1506 lck_spin_unlock(&port_alloc_queue_lock);
1507 #endif
1508 }
1509
1510 /*
1511 * Routine: ipc_port_callstack_init_debug
1512 * Purpose:
1513 * Calls the machine-dependent routine to
1514 * fill in an array with up to IP_CALLSTACK_MAX
1515 * levels of return pc information
1516 * Conditions:
1517 * May block (via copyin)
1518 */
1519 void
1520 ipc_port_callstack_init_debug(
1521 natural_t *callstack,
1522 unsigned int callstack_max)
1523 {
1524 unsigned int i;
1525
1526 /* guarantee the callstack is initialized */
1527 for (i=0; i < callstack_max; i++)
1528 callstack[i] = 0;
1529
1530 if (ipc_portbt)
1531 machine_callstack(callstack, callstack_max);
1532 }
1533
1534 /*
1535 * Remove a port from the queue of allocated ports.
1536 * This routine should be invoked JUST prior to
1537 * deallocating the actual memory occupied by the port.
1538 */
1539 #if 1
1540 void
1541 ipc_port_track_dealloc(
1542 __unused ipc_port_t port)
1543 {
1544 }
1545 #else
1546 void
1547 ipc_port_track_dealloc(
1548 ipc_port_t port)
1549 {
1550 lck_spin_lock(&port_alloc_queue_lock);
1551 assert(port_count > 0);
1552 --port_count;
1553 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1554 lck_spin_unlock(&port_alloc_queue_lock);
1555 }
1556 #endif
1557
1558
1559 #endif /* MACH_ASSERT */