]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_port.c
d76463f64e07b24995af9c353dd54fa67250ac00
[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 is locked */
597
598 ipc_port_init(port, space, name);
599
600 #if MACH_ASSERT
601 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
602 #endif /* MACH_ASSERT */
603
604 #if CONFIG_MACF_MACH
605 task_t issuer = current_task();
606 tasklabel_lock2 (issuer, space->is_task);
607 mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
608 &port->ip_label);
609 tasklabel_unlock2 (issuer, space->is_task);
610 #endif
611
612 *namep = name;
613 *portp = port;
614
615 return KERN_SUCCESS;
616 }
617
618 /*
619 * Routine: ipc_port_alloc_name
620 * Purpose:
621 * Allocate a port, with a specific name.
622 * Conditions:
623 * Nothing locked. If successful, the port is returned
624 * locked. (The caller doesn't have a reference.)
625 * Returns:
626 * KERN_SUCCESS The port is allocated.
627 * KERN_INVALID_TASK The space is dead.
628 * KERN_NAME_EXISTS The name already denotes a right.
629 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
630 */
631
632 kern_return_t
633 ipc_port_alloc_name(
634 ipc_space_t space,
635 mach_port_name_t name,
636 ipc_port_t *portp)
637 {
638 ipc_port_t port;
639 kern_return_t kr;
640
641 #if MACH_ASSERT
642 natural_t buf[IP_CALLSTACK_MAX];
643 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
644 #endif /* MACH_ASSERT */
645
646 kr = ipc_object_alloc_name(space, IOT_PORT,
647 MACH_PORT_TYPE_RECEIVE, 0,
648 name, (ipc_object_t *) &port);
649 if (kr != KERN_SUCCESS)
650 return kr;
651
652 /* port is locked */
653
654 ipc_port_init(port, space, name);
655
656 #if MACH_ASSERT
657 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
658 #endif /* MACH_ASSERT */
659
660 #if CONFIG_MACF_MACH
661 task_t issuer = current_task();
662 tasklabel_lock2 (issuer, space->is_task);
663 mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
664 &port->ip_label);
665 tasklabel_unlock2 (issuer, space->is_task);
666 #endif
667
668 *portp = port;
669
670 return KERN_SUCCESS;
671 }
672
673 /*
674 * Routine: ipc_port_spnotify
675 * Purpose:
676 * Generate send-possible port notifications.
677 * Conditions:
678 * Nothing locked, reference held on port.
679 */
680 void
681 ipc_port_spnotify(
682 ipc_port_t port)
683 {
684 ipc_port_request_index_t index = 0;
685 ipc_table_elems_t size = 0;
686
687 /*
688 * If the port has no send-possible request
689 * armed, don't bother to lock the port.
690 */
691 if (!port->ip_sprequests)
692 return;
693
694 ip_lock(port);
695 if (!port->ip_sprequests) {
696 ip_unlock(port);
697 return;
698 }
699 port->ip_sprequests = FALSE;
700
701 revalidate:
702 if (ip_active(port)) {
703 ipc_port_request_t requests;
704
705 /* table may change each time port unlocked (reload) */
706 requests = port->ip_requests;
707 assert(requests != IPR_NULL);
708
709 /*
710 * no need to go beyond table size when first
711 * we entered - those are future notifications.
712 */
713 if (size == 0)
714 size = requests->ipr_size->its_size;
715
716 /* no need to backtrack either */
717 while (++index < size) {
718 ipc_port_request_t ipr = &requests[index];
719 mach_port_name_t name = ipr->ipr_name;
720 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
721 boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
722
723 if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
724 /* claim send-once right - slot still inuse */
725 ipr->ipr_soright = IP_NULL;
726 ip_unlock(port);
727
728 ipc_notify_send_possible(soright, name);
729
730 ip_lock(port);
731 goto revalidate;
732 }
733 }
734 }
735 ip_unlock(port);
736 }
737
738 /*
739 * Routine: ipc_port_dnnotify
740 * Purpose:
741 * Generate dead name notifications for
742 * all outstanding dead-name and send-
743 * possible requests.
744 * Conditions:
745 * Nothing locked.
746 * Port must be inactive.
747 * Reference held on port.
748 */
749 void
750 ipc_port_dnnotify(
751 ipc_port_t port)
752 {
753 ipc_port_request_t requests = port->ip_requests;
754
755 assert(!ip_active(port));
756 if (requests != IPR_NULL) {
757 ipc_table_size_t its = requests->ipr_size;
758 ipc_table_elems_t size = its->its_size;
759 ipc_port_request_index_t index;
760 for (index = 1; index < size; index++) {
761 ipc_port_request_t ipr = &requests[index];
762 mach_port_name_t name = ipr->ipr_name;
763 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
764
765 if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
766 ipc_notify_dead_name(soright, name);
767 }
768 }
769 }
770 }
771
772
773 /*
774 * Routine: ipc_port_destroy
775 * Purpose:
776 * Destroys a port. Cleans up queued messages.
777 *
778 * If the port has a backup, it doesn't get destroyed,
779 * but is sent in a port-destroyed notification to the backup.
780 * Conditions:
781 * The port is locked and alive; nothing else locked.
782 * The caller has a reference, which is consumed.
783 * Afterwards, the port is unlocked and dead.
784 */
785
786 void
787 ipc_port_destroy(
788 ipc_port_t port)
789 {
790 ipc_port_t pdrequest, nsrequest;
791 ipc_mqueue_t mqueue;
792 ipc_kmsg_t kmsg;
793
794 assert(ip_active(port));
795 /* port->ip_receiver_name is garbage */
796 /* port->ip_receiver/port->ip_destination is garbage */
797 assert(port->ip_pset_count == 0);
798 assert(port->ip_mscount == 0);
799
800 /* first check for a backup port */
801
802 pdrequest = port->ip_pdrequest;
803 if (pdrequest != IP_NULL) {
804 /* we assume the ref for pdrequest */
805 port->ip_pdrequest = IP_NULL;
806
807 /* make port be in limbo */
808 port->ip_receiver_name = MACH_PORT_NULL;
809 port->ip_destination = IP_NULL;
810 ip_unlock(port);
811
812 /* consumes our refs for port and pdrequest */
813 ipc_notify_port_destroyed(pdrequest, port);
814 return;
815 }
816
817 /* once port is dead, we don't need to keep it locked */
818
819 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
820 port->ip_timestamp = ipc_port_timestamp();
821
822 /*
823 * If the port has a preallocated message buffer and that buffer
824 * is not inuse, free it. If it has an inuse one, then the kmsg
825 * free will detect that we freed the association and it can free it
826 * like a normal buffer.
827 */
828 if (IP_PREALLOC(port)) {
829 ipc_port_t inuse_port;
830
831 kmsg = port->ip_premsg;
832 assert(kmsg != IKM_NULL);
833 inuse_port = ikm_prealloc_inuse_port(kmsg);
834 IP_CLEAR_PREALLOC(port, kmsg);
835 ip_unlock(port);
836 if (inuse_port != IP_NULL) {
837 assert(inuse_port == port);
838 } else {
839 ipc_kmsg_free(kmsg);
840 }
841 } else {
842 ip_unlock(port);
843 }
844
845 /* throw away no-senders request */
846 nsrequest = port->ip_nsrequest;
847 if (nsrequest != IP_NULL)
848 ipc_notify_send_once(nsrequest); /* consumes ref */
849
850 /* destroy any queued messages */
851 mqueue = &port->ip_messages;
852 ipc_mqueue_destroy(mqueue);
853
854 /* generate dead-name notifications */
855 ipc_port_dnnotify(port);
856
857 ipc_kobject_destroy(port);
858
859 ip_release(port); /* consume caller's ref */
860 }
861
862 /*
863 * Routine: ipc_port_check_circularity
864 * Purpose:
865 * Check if queueing "port" in a message for "dest"
866 * would create a circular group of ports and messages.
867 *
868 * If no circularity (FALSE returned), then "port"
869 * is changed from "in limbo" to "in transit".
870 *
871 * That is, we want to set port->ip_destination == dest,
872 * but guaranteeing that this doesn't create a circle
873 * port->ip_destination->ip_destination->... == port
874 * Conditions:
875 * No ports locked. References held for "port" and "dest".
876 */
877
878 boolean_t
879 ipc_port_check_circularity(
880 ipc_port_t port,
881 ipc_port_t dest)
882 {
883 ipc_port_t base;
884
885 assert(port != IP_NULL);
886 assert(dest != IP_NULL);
887
888 if (port == dest)
889 return TRUE;
890 base = dest;
891
892 /*
893 * First try a quick check that can run in parallel.
894 * No circularity if dest is not in transit.
895 */
896
897 ip_lock(port);
898 if (ip_lock_try(dest)) {
899 if (!ip_active(dest) ||
900 (dest->ip_receiver_name != MACH_PORT_NULL) ||
901 (dest->ip_destination == IP_NULL))
902 goto not_circular;
903
904 /* dest is in transit; further checking necessary */
905
906 ip_unlock(dest);
907 }
908 ip_unlock(port);
909
910 ipc_port_multiple_lock(); /* massive serialization */
911
912 /*
913 * Search for the end of the chain (a port not in transit),
914 * acquiring locks along the way.
915 */
916
917 for (;;) {
918 ip_lock(base);
919
920 if (!ip_active(base) ||
921 (base->ip_receiver_name != MACH_PORT_NULL) ||
922 (base->ip_destination == IP_NULL))
923 break;
924
925 base = base->ip_destination;
926 }
927
928 /* all ports in chain from dest to base, inclusive, are locked */
929
930 if (port == base) {
931 /* circularity detected! */
932
933 ipc_port_multiple_unlock();
934
935 /* port (== base) is in limbo */
936
937 assert(ip_active(port));
938 assert(port->ip_receiver_name == MACH_PORT_NULL);
939 assert(port->ip_destination == IP_NULL);
940
941 while (dest != IP_NULL) {
942 ipc_port_t next;
943
944 /* dest is in transit or in limbo */
945
946 assert(ip_active(dest));
947 assert(dest->ip_receiver_name == MACH_PORT_NULL);
948
949 next = dest->ip_destination;
950 ip_unlock(dest);
951 dest = next;
952 }
953
954 return TRUE;
955 }
956
957 /*
958 * The guarantee: lock port while the entire chain is locked.
959 * Once port is locked, we can take a reference to dest,
960 * add port to the chain, and unlock everything.
961 */
962
963 ip_lock(port);
964 ipc_port_multiple_unlock();
965
966 not_circular:
967
968 /* port is in limbo */
969
970 assert(ip_active(port));
971 assert(port->ip_receiver_name == MACH_PORT_NULL);
972 assert(port->ip_destination == IP_NULL);
973
974 ip_reference(dest);
975 port->ip_destination = dest;
976
977 /* now unlock chain */
978
979 while (port != base) {
980 ipc_port_t next;
981
982 /* port is in transit */
983
984 assert(ip_active(port));
985 assert(port->ip_receiver_name == MACH_PORT_NULL);
986 assert(port->ip_destination != IP_NULL);
987
988 next = port->ip_destination;
989 ip_unlock(port);
990 port = next;
991 }
992
993 /* base is not in transit */
994
995 assert(!ip_active(base) ||
996 (base->ip_receiver_name != MACH_PORT_NULL) ||
997 (base->ip_destination == IP_NULL));
998 ip_unlock(base);
999
1000 return FALSE;
1001 }
1002
1003 /*
1004 * Routine: ipc_port_lookup_notify
1005 * Purpose:
1006 * Make a send-once notify port from a receive right.
1007 * Returns IP_NULL if name doesn't denote a receive right.
1008 * Conditions:
1009 * The space must be locked (read or write) and active.
1010 * Being the active space, we can rely on thread server_id
1011 * context to give us the proper server level sub-order
1012 * within the space.
1013 */
1014
1015 ipc_port_t
1016 ipc_port_lookup_notify(
1017 ipc_space_t space,
1018 mach_port_name_t name)
1019 {
1020 ipc_port_t port;
1021 ipc_entry_t entry;
1022
1023 assert(is_active(space));
1024
1025 entry = ipc_entry_lookup(space, name);
1026 if (entry == IE_NULL)
1027 return IP_NULL;
1028 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1029 return IP_NULL;
1030
1031 port = (ipc_port_t) entry->ie_object;
1032 assert(port != IP_NULL);
1033
1034 ip_lock(port);
1035 assert(ip_active(port));
1036 assert(port->ip_receiver_name == name);
1037 assert(port->ip_receiver == space);
1038
1039 ip_reference(port);
1040 port->ip_sorights++;
1041 ip_unlock(port);
1042
1043 return port;
1044 }
1045
1046 /*
1047 * Routine: ipc_port_make_send_locked
1048 * Purpose:
1049 * Make a naked send right from a receive right.
1050 *
1051 * Conditions:
1052 * port locked and active.
1053 */
1054 ipc_port_t
1055 ipc_port_make_send_locked(
1056 ipc_port_t port)
1057 {
1058 assert(ip_active(port));
1059 port->ip_mscount++;
1060 port->ip_srights++;
1061 ip_reference(port);
1062 ip_unlock(port);
1063 return port;
1064 }
1065
1066 /*
1067 * Routine: ipc_port_make_send
1068 * Purpose:
1069 * Make a naked send right from a receive right.
1070 */
1071
1072 ipc_port_t
1073 ipc_port_make_send(
1074 ipc_port_t port)
1075 {
1076
1077 if (!IP_VALID(port))
1078 return port;
1079
1080 ip_lock(port);
1081 if (ip_active(port)) {
1082 port->ip_mscount++;
1083 port->ip_srights++;
1084 ip_reference(port);
1085 ip_unlock(port);
1086 return port;
1087 }
1088 ip_unlock(port);
1089 return IP_DEAD;
1090 }
1091
1092 /*
1093 * Routine: ipc_port_copy_send
1094 * Purpose:
1095 * Make a naked send right from another naked send right.
1096 * IP_NULL -> IP_NULL
1097 * IP_DEAD -> IP_DEAD
1098 * dead port -> IP_DEAD
1099 * live port -> port + ref
1100 * Conditions:
1101 * Nothing locked except possibly a space.
1102 */
1103
1104 ipc_port_t
1105 ipc_port_copy_send(
1106 ipc_port_t port)
1107 {
1108 ipc_port_t sright;
1109
1110 if (!IP_VALID(port))
1111 return port;
1112
1113 ip_lock(port);
1114 if (ip_active(port)) {
1115 assert(port->ip_srights > 0);
1116
1117 ip_reference(port);
1118 port->ip_srights++;
1119 sright = port;
1120 } else
1121 sright = IP_DEAD;
1122 ip_unlock(port);
1123
1124 return sright;
1125 }
1126
1127 /*
1128 * Routine: ipc_port_copyout_send
1129 * Purpose:
1130 * Copyout a naked send right (possibly null/dead),
1131 * or if that fails, destroy the right.
1132 * Conditions:
1133 * Nothing locked.
1134 */
1135
1136 mach_port_name_t
1137 ipc_port_copyout_send(
1138 ipc_port_t sright,
1139 ipc_space_t space)
1140 {
1141 mach_port_name_t name;
1142
1143 if (IP_VALID(sright)) {
1144 kern_return_t kr;
1145
1146 kr = ipc_object_copyout(space, (ipc_object_t) sright,
1147 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
1148 if (kr != KERN_SUCCESS) {
1149 ipc_port_release_send(sright);
1150
1151 if (kr == KERN_INVALID_CAPABILITY)
1152 name = MACH_PORT_DEAD;
1153 else
1154 name = MACH_PORT_NULL;
1155 }
1156 } else
1157 name = CAST_MACH_PORT_TO_NAME(sright);
1158
1159 return name;
1160 }
1161
1162 /*
1163 * Routine: ipc_port_release_send
1164 * Purpose:
1165 * Release a naked send right.
1166 * Consumes a ref for the port.
1167 * Conditions:
1168 * Nothing locked.
1169 */
1170
1171 void
1172 ipc_port_release_send(
1173 ipc_port_t port)
1174 {
1175 ipc_port_t nsrequest = IP_NULL;
1176 mach_port_mscount_t mscount;
1177
1178 if (!IP_VALID(port))
1179 return;
1180
1181 ip_lock(port);
1182
1183 if (!ip_active(port)) {
1184 ip_unlock(port);
1185 ip_release(port);
1186 return;
1187 }
1188
1189 assert(port->ip_srights > 0);
1190
1191 if (--port->ip_srights == 0 &&
1192 port->ip_nsrequest != IP_NULL) {
1193 nsrequest = port->ip_nsrequest;
1194 port->ip_nsrequest = IP_NULL;
1195 mscount = port->ip_mscount;
1196 ip_unlock(port);
1197 ip_release(port);
1198 ipc_notify_no_senders(nsrequest, mscount);
1199 } else {
1200 ip_unlock(port);
1201 ip_release(port);
1202 }
1203 }
1204
1205 /*
1206 * Routine: ipc_port_make_sonce_locked
1207 * Purpose:
1208 * Make a naked send-once right from a receive right.
1209 * Conditions:
1210 * The port is locked and active.
1211 */
1212
1213 ipc_port_t
1214 ipc_port_make_sonce_locked(
1215 ipc_port_t port)
1216 {
1217 assert(ip_active(port));
1218 port->ip_sorights++;
1219 ip_reference(port);
1220 return port;
1221 }
1222
1223 /*
1224 * Routine: ipc_port_make_sonce
1225 * Purpose:
1226 * Make a naked send-once right from a receive right.
1227 * Conditions:
1228 * The port is not locked.
1229 */
1230
1231 ipc_port_t
1232 ipc_port_make_sonce(
1233 ipc_port_t port)
1234 {
1235 if (!IP_VALID(port))
1236 return port;
1237
1238 ip_lock(port);
1239 if (ip_active(port)) {
1240 port->ip_sorights++;
1241 ip_reference(port);
1242 ip_unlock(port);
1243 return port;
1244 }
1245 ip_unlock(port);
1246 return IP_DEAD;
1247 }
1248
1249 /*
1250 * Routine: ipc_port_release_sonce
1251 * Purpose:
1252 * Release a naked send-once right.
1253 * Consumes a ref for the port.
1254 *
1255 * In normal situations, this is never used.
1256 * Send-once rights are only consumed when
1257 * a message (possibly a send-once notification)
1258 * is sent to them.
1259 * Conditions:
1260 * Nothing locked except possibly a space.
1261 */
1262
1263 void
1264 ipc_port_release_sonce(
1265 ipc_port_t port)
1266 {
1267 if (!IP_VALID(port))
1268 return;
1269
1270 ip_lock(port);
1271
1272 assert(port->ip_sorights > 0);
1273
1274 port->ip_sorights--;
1275
1276 ip_unlock(port);
1277 ip_release(port);
1278 }
1279
1280 /*
1281 * Routine: ipc_port_release_receive
1282 * Purpose:
1283 * Release a naked (in limbo or in transit) receive right.
1284 * Consumes a ref for the port; destroys the port.
1285 * Conditions:
1286 * Nothing locked.
1287 */
1288
1289 void
1290 ipc_port_release_receive(
1291 ipc_port_t port)
1292 {
1293 ipc_port_t dest;
1294
1295 if (!IP_VALID(port))
1296 return;
1297
1298 ip_lock(port);
1299 assert(ip_active(port));
1300 assert(port->ip_receiver_name == MACH_PORT_NULL);
1301 dest = port->ip_destination;
1302
1303 ipc_port_destroy(port); /* consumes ref, unlocks */
1304
1305 if (dest != IP_NULL)
1306 ip_release(dest);
1307 }
1308
1309 /*
1310 * Routine: ipc_port_alloc_special
1311 * Purpose:
1312 * Allocate a port in a special space.
1313 * The new port is returned with one ref.
1314 * If unsuccessful, IP_NULL is returned.
1315 * Conditions:
1316 * Nothing locked.
1317 */
1318
1319 ipc_port_t
1320 ipc_port_alloc_special(
1321 ipc_space_t space)
1322 {
1323 ipc_port_t port;
1324
1325 port = (ipc_port_t) io_alloc(IOT_PORT);
1326 if (port == IP_NULL)
1327 return IP_NULL;
1328
1329 #if MACH_ASSERT
1330 natural_t buf[IP_CALLSTACK_MAX];
1331 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
1332 #endif /* MACH_ASSERT */
1333
1334 bzero((char *)port, sizeof(*port));
1335 io_lock_init(&port->ip_object);
1336 port->ip_references = 1;
1337 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1338
1339 ipc_port_init(port, space, 1);
1340
1341 #if MACH_ASSERT
1342 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
1343 #endif /* MACH_ASSERT */
1344
1345 #if CONFIG_MACF_MACH
1346 /* Currently, ipc_port_alloc_special is used for two things:
1347 * - Reply ports for messages from the kernel
1348 * - Ports for communication with the kernel (e.g. task ports)
1349 * Since both of these would typically be labelled as kernel objects,
1350 * we will use a new entry point for this purpose, as current_task()
1351 * is often wrong (i.e. not kernel_task) or null.
1352 */
1353 mac_port_label_init(&port->ip_label);
1354 mac_port_label_associate_kernel(&port->ip_label, space == ipc_space_reply);
1355 #endif
1356
1357 return port;
1358 }
1359
1360 /*
1361 * Routine: ipc_port_dealloc_special
1362 * Purpose:
1363 * Deallocate a port in a special space.
1364 * Consumes one ref for the port.
1365 * Conditions:
1366 * Nothing locked.
1367 */
1368
1369 void
1370 ipc_port_dealloc_special(
1371 ipc_port_t port,
1372 __assert_only ipc_space_t space)
1373 {
1374 ip_lock(port);
1375 assert(ip_active(port));
1376 // assert(port->ip_receiver_name != MACH_PORT_NULL);
1377 assert(port->ip_receiver == space);
1378
1379 /*
1380 * We clear ip_receiver_name and ip_receiver to simplify
1381 * the ipc_space_kernel check in ipc_mqueue_send.
1382 */
1383
1384 port->ip_receiver_name = MACH_PORT_NULL;
1385 port->ip_receiver = IS_NULL;
1386
1387 /* relevant part of ipc_port_clear_receiver */
1388 ipc_port_set_mscount(port, 0);
1389 port->ip_messages.imq_seqno = 0;
1390
1391 ipc_port_destroy(port);
1392 }
1393
1394 /*
1395 * Routine: ipc_port_finalize
1396 * Purpose:
1397 * Called on last reference deallocate to
1398 * free any remaining data associated with the
1399 * port.
1400 * Conditions:
1401 * Nothing locked.
1402 */
1403 void
1404 ipc_port_finalize(
1405 ipc_port_t port)
1406 {
1407 ipc_port_request_t requests = port->ip_requests;
1408
1409 assert(!ip_active(port));
1410 if (requests != IPR_NULL) {
1411 ipc_table_size_t its = requests->ipr_size;
1412 it_requests_free(its, requests);
1413 port->ip_requests = IPR_NULL;
1414 }
1415
1416 #if MACH_ASSERT
1417 ipc_port_track_dealloc(port);
1418 #endif /* MACH_ASSERT */
1419
1420 #if CONFIG_MACF_MACH
1421 /* Port label should have been initialized after creation. */
1422 mac_port_label_destroy(&port->ip_label);
1423 #endif
1424 }
1425
1426 #if MACH_ASSERT
1427 #include <kern/machine.h>
1428
1429 /*
1430 * Keep a list of all allocated ports.
1431 * Allocation is intercepted via ipc_port_init;
1432 * deallocation is intercepted via io_free.
1433 */
1434 queue_head_t port_alloc_queue;
1435 lck_spin_t port_alloc_queue_lock;
1436
1437 unsigned long port_count = 0;
1438 unsigned long port_count_warning = 20000;
1439 unsigned long port_timestamp = 0;
1440
1441 void db_port_stack_trace(
1442 ipc_port_t port);
1443 void db_ref(
1444 int refs);
1445 int db_port_walk(
1446 unsigned int verbose,
1447 unsigned int display,
1448 unsigned int ref_search,
1449 unsigned int ref_target);
1450
1451 /*
1452 * Initialize global state needed for run-time
1453 * port debugging.
1454 */
1455 void
1456 ipc_port_debug_init(void)
1457 {
1458 queue_init(&port_alloc_queue);
1459
1460 lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr);
1461
1462 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
1463 ipc_portbt = 0;
1464 }
1465
1466 #ifdef MACH_BSD
1467 extern int proc_pid(struct proc*);
1468 #endif /* MACH_BSD */
1469
1470 /*
1471 * Initialize all of the debugging state in a port.
1472 * Insert the port into a global list of all allocated ports.
1473 */
1474 void
1475 ipc_port_init_debug(
1476 ipc_port_t port,
1477 natural_t *callstack,
1478 unsigned int callstack_max)
1479 {
1480 unsigned int i;
1481
1482 port->ip_thread = current_thread();
1483 port->ip_timetrack = port_timestamp++;
1484 for (i = 0; i < callstack_max; ++i)
1485 port->ip_callstack[i] = callstack[i];
1486 for (i = 0; i < IP_NSPARES; ++i)
1487 port->ip_spares[i] = 0;
1488
1489 #ifdef MACH_BSD
1490 task_t task = current_task();
1491 if (task != TASK_NULL) {
1492 struct proc* proc = (struct proc*) get_bsdtask_info(task);
1493 if (proc)
1494 port->ip_spares[0] = proc_pid(proc);
1495 }
1496 #endif /* MACH_BSD */
1497
1498 #if 0
1499 lck_spin_lock(&port_alloc_queue_lock);
1500 ++port_count;
1501 if (port_count_warning > 0 && port_count >= port_count_warning)
1502 assert(port_count < port_count_warning);
1503 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1504 lck_spin_unlock(&port_alloc_queue_lock);
1505 #endif
1506 }
1507
1508 /*
1509 * Routine: ipc_port_callstack_init_debug
1510 * Purpose:
1511 * Calls the machine-dependent routine to
1512 * fill in an array with up to IP_CALLSTACK_MAX
1513 * levels of return pc information
1514 * Conditions:
1515 * May block (via copyin)
1516 */
1517 void
1518 ipc_port_callstack_init_debug(
1519 natural_t *callstack,
1520 unsigned int callstack_max)
1521 {
1522 unsigned int i;
1523
1524 /* guarantee the callstack is initialized */
1525 for (i=0; i < callstack_max; i++)
1526 callstack[i] = 0;
1527
1528 if (ipc_portbt)
1529 machine_callstack(callstack, callstack_max);
1530 }
1531
1532 /*
1533 * Remove a port from the queue of allocated ports.
1534 * This routine should be invoked JUST prior to
1535 * deallocating the actual memory occupied by the port.
1536 */
1537 #if 1
1538 void
1539 ipc_port_track_dealloc(
1540 __unused ipc_port_t port)
1541 {
1542 }
1543 #else
1544 void
1545 ipc_port_track_dealloc(
1546 ipc_port_t port)
1547 {
1548 lck_spin_lock(&port_alloc_queue_lock);
1549 assert(port_count > 0);
1550 --port_count;
1551 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1552 lck_spin_unlock(&port_alloc_queue_lock);
1553 }
1554 #endif
1555
1556
1557 #endif /* MACH_ASSERT */