]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_right.c
00a256e177fa5ddd57bbb21b392495cbe90e0eb1
[apple/xnu.git] / osfmk / ipc / ipc_right.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 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
63 /*
64 */
65 /*
66 * File: ipc/ipc_right.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Functions to manipulate IPC capabilities.
71 */
72
73 #include <mach/boolean.h>
74 #include <mach/kern_return.h>
75 #include <mach/port.h>
76 #include <mach/message.h>
77 #include <kern/assert.h>
78 #include <kern/ipc_kobject.h>
79 #include <kern/misc_protos.h>
80 #include <ipc/port.h>
81 #include <ipc/ipc_entry.h>
82 #include <ipc/ipc_space.h>
83 #include <ipc/ipc_object.h>
84 #include <ipc/ipc_hash.h>
85 #include <ipc/ipc_port.h>
86 #include <ipc/ipc_pset.h>
87 #include <ipc/ipc_right.h>
88 #include <ipc/ipc_notify.h>
89 #include <ipc/ipc_table.h>
90 #include <ipc/ipc_importance.h>
91 #include <security/mac_mach_internal.h>
92
93 /*
94 * Routine: ipc_right_lookup_write
95 * Purpose:
96 * Finds an entry in a space, given the name.
97 * Conditions:
98 * Nothing locked. If successful, the space is write-locked.
99 * Returns:
100 * KERN_SUCCESS Found an entry.
101 * KERN_INVALID_TASK The space is dead.
102 * KERN_INVALID_NAME Name doesn't exist in space.
103 */
104
105 kern_return_t
106 ipc_right_lookup_write(
107 ipc_space_t space,
108 mach_port_name_t name,
109 ipc_entry_t *entryp)
110 {
111 ipc_entry_t entry;
112
113 assert(space != IS_NULL);
114
115 is_write_lock(space);
116
117 if (!is_active(space)) {
118 is_write_unlock(space);
119 return KERN_INVALID_TASK;
120 }
121
122 if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
123 is_write_unlock(space);
124 return KERN_INVALID_NAME;
125 }
126
127 *entryp = entry;
128 return KERN_SUCCESS;
129 }
130
131 /*
132 * Routine: ipc_right_lookup_two_write
133 * Purpose:
134 * Like ipc_right_lookup except that it returns two
135 * entries for two different names that were looked
136 * up under the same space lock.
137 * Conditions:
138 * Nothing locked. If successful, the space is write-locked.
139 * Returns:
140 * KERN_INVALID_TASK The space is dead.
141 * KERN_INVALID_NAME Name doesn't exist in space.
142 */
143
144 kern_return_t
145 ipc_right_lookup_two_write(
146 ipc_space_t space,
147 mach_port_name_t name1,
148 ipc_entry_t *entryp1,
149 mach_port_name_t name2,
150 ipc_entry_t *entryp2)
151 {
152 ipc_entry_t entry1;
153 ipc_entry_t entry2;
154
155 assert(space != IS_NULL);
156
157 is_write_lock(space);
158
159 if (!is_active(space)) {
160 is_write_unlock(space);
161 return KERN_INVALID_TASK;
162 }
163
164 if ((entry1 = ipc_entry_lookup(space, name1)) == IE_NULL) {
165 is_write_unlock(space);
166 mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_NAME);
167 return KERN_INVALID_NAME;
168 }
169 if ((entry2 = ipc_entry_lookup(space, name2)) == IE_NULL) {
170 is_write_unlock(space);
171 mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_NAME);
172 return KERN_INVALID_NAME;
173 }
174 *entryp1 = entry1;
175 *entryp2 = entry2;
176 return KERN_SUCCESS;
177 }
178
179 /*
180 * Routine: ipc_right_reverse
181 * Purpose:
182 * Translate (space, object) -> (name, entry).
183 * Only finds send/receive rights.
184 * Returns TRUE if an entry is found; if so,
185 * the object is locked and active.
186 * Conditions:
187 * The space must be locked (read or write) and active.
188 * Nothing else locked.
189 */
190
191 boolean_t
192 ipc_right_reverse(
193 ipc_space_t space,
194 ipc_object_t object,
195 mach_port_name_t *namep,
196 ipc_entry_t *entryp)
197 {
198 ipc_port_t port;
199 mach_port_name_t name;
200 ipc_entry_t entry;
201
202 /* would switch on io_otype to handle multiple types of object */
203
204 assert(is_active(space));
205 assert(io_otype(object) == IOT_PORT);
206
207 port = ip_object_to_port(object);
208
209 ip_lock(port);
210 if (!ip_active(port)) {
211 ip_unlock(port);
212
213 return FALSE;
214 }
215
216 if (port->ip_receiver == space) {
217 name = port->ip_receiver_name;
218 assert(name != MACH_PORT_NULL);
219
220 entry = ipc_entry_lookup(space, name);
221
222 assert(entry != IE_NULL);
223 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
224 assert(port == ip_object_to_port(entry->ie_object));
225
226 *namep = name;
227 *entryp = entry;
228 return TRUE;
229 }
230
231 if (ipc_hash_lookup(space, ip_to_object(port), namep, entryp)) {
232 assert((entry = *entryp) != IE_NULL);
233 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
234 assert(port == ip_object_to_port(entry->ie_object));
235
236 return TRUE;
237 }
238
239 ip_unlock(port);
240 return FALSE;
241 }
242
243 /*
244 * Routine: ipc_right_dnrequest
245 * Purpose:
246 * Make a dead-name request, returning the previously
247 * registered send-once right. If notify is IP_NULL,
248 * just cancels the previously registered request.
249 *
250 * Conditions:
251 * Nothing locked. May allocate memory.
252 * Only consumes/returns refs if successful.
253 * Returns:
254 * KERN_SUCCESS Made/canceled dead-name request.
255 * KERN_INVALID_TASK The space is dead.
256 * KERN_INVALID_NAME Name doesn't exist in space.
257 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
258 * KERN_INVALID_ARGUMENT Name denotes dead name, but
259 * immediate is FALSE or notify is IP_NULL.
260 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
261 */
262
263 kern_return_t
264 ipc_right_request_alloc(
265 ipc_space_t space,
266 mach_port_name_t name,
267 boolean_t immediate,
268 boolean_t send_possible,
269 ipc_port_t notify,
270 ipc_port_t *previousp)
271 {
272 ipc_port_request_index_t prev_request;
273 ipc_port_t previous = IP_NULL;
274 ipc_entry_t entry;
275 kern_return_t kr;
276
277 #if IMPORTANCE_INHERITANCE
278 boolean_t needboost = FALSE;
279 #endif /* IMPORTANCE_INHERITANCE */
280
281 for (;;) {
282 ipc_port_t port = IP_NULL;
283
284 kr = ipc_right_lookup_write(space, name, &entry);
285 if (kr != KERN_SUCCESS) {
286 return kr;
287 }
288
289 /* space is write-locked and active */
290
291 prev_request = entry->ie_request;
292
293 /* if nothing to do or undo, we're done */
294 if (notify == IP_NULL && prev_request == IE_REQ_NONE) {
295 is_write_unlock(space);
296 *previousp = IP_NULL;
297 return KERN_SUCCESS;
298 }
299
300 /* see if the entry is of proper type for requests */
301 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
302 ipc_port_request_index_t new_request;
303
304 port = ip_object_to_port(entry->ie_object);
305 assert(port != IP_NULL);
306
307 if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
308 /* port is locked and active */
309
310 /* if no new request, just cancel previous */
311 if (notify == IP_NULL) {
312 if (prev_request != IE_REQ_NONE) {
313 previous = ipc_port_request_cancel(port, name, prev_request);
314 }
315 ip_unlock(port);
316 entry->ie_request = IE_REQ_NONE;
317 ipc_entry_modified(space, name, entry);
318 is_write_unlock(space);
319 break;
320 }
321
322 /*
323 * send-once rights, kernel objects, and non-full other queues
324 * fire immediately (if immediate specified).
325 */
326 if (send_possible && immediate &&
327 ((entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE) ||
328 port->ip_receiver == ipc_space_kernel || !ip_full(port))) {
329 if (prev_request != IE_REQ_NONE) {
330 previous = ipc_port_request_cancel(port, name, prev_request);
331 }
332 ip_unlock(port);
333 entry->ie_request = IE_REQ_NONE;
334 ipc_entry_modified(space, name, entry);
335 is_write_unlock(space);
336
337 ipc_notify_send_possible(notify, name);
338 break;
339 }
340
341 /*
342 * If there is a previous request, free it. Any subsequent
343 * allocation cannot fail, thus assuring an atomic swap.
344 */
345 if (prev_request != IE_REQ_NONE) {
346 previous = ipc_port_request_cancel(port, name, prev_request);
347 }
348
349 #if IMPORTANCE_INHERITANCE
350 kr = ipc_port_request_alloc(port, name, notify,
351 send_possible, immediate,
352 &new_request, &needboost);
353 #else
354 kr = ipc_port_request_alloc(port, name, notify,
355 send_possible, immediate,
356 &new_request);
357 #endif /* IMPORTANCE_INHERITANCE */
358 if (kr != KERN_SUCCESS) {
359 assert(previous == IP_NULL);
360 is_write_unlock(space);
361
362 kr = ipc_port_request_grow(port, ITS_SIZE_NONE);
363 /* port is unlocked */
364
365 if (kr != KERN_SUCCESS) {
366 return kr;
367 }
368
369 continue;
370 }
371
372
373 assert(new_request != IE_REQ_NONE);
374 entry->ie_request = new_request;
375 ipc_entry_modified(space, name, entry);
376 is_write_unlock(space);
377
378 #if IMPORTANCE_INHERITANCE
379 if (needboost == TRUE) {
380 if (ipc_port_importance_delta(port, IPID_OPTION_SENDPOSSIBLE, 1) == FALSE) {
381 ip_unlock(port);
382 }
383 } else
384 #endif /* IMPORTANCE_INHERITANCE */
385 ip_unlock(port);
386
387 break;
388 }
389 /* entry may have changed to dead-name by ipc_right_check() */
390 }
391
392 /* treat send_possible requests as immediate w.r.t. dead-name */
393 if ((send_possible || immediate) && notify != IP_NULL &&
394 (entry->ie_bits & MACH_PORT_TYPE_DEAD_NAME)) {
395 mach_port_urefs_t urefs = IE_BITS_UREFS(entry->ie_bits);
396
397 assert(urefs > 0);
398
399 /* leave urefs pegged to maximum if it overflowed */
400 if (urefs < MACH_PORT_UREFS_MAX) {
401 (entry->ie_bits)++; /* increment urefs */
402 }
403 ipc_entry_modified(space, name, entry);
404
405 is_write_unlock(space);
406
407 if (port != IP_NULL) {
408 ip_release(port);
409 }
410
411 ipc_notify_dead_name(notify, name);
412 previous = IP_NULL;
413 break;
414 }
415
416 kr = (entry->ie_bits & MACH_PORT_TYPE_PORT_OR_DEAD) ?
417 KERN_INVALID_ARGUMENT : KERN_INVALID_RIGHT;
418
419 is_write_unlock(space);
420
421 if (port != IP_NULL) {
422 ip_release(port);
423 }
424
425 return kr;
426 }
427
428 *previousp = previous;
429 return KERN_SUCCESS;
430 }
431
432 /*
433 * Routine: ipc_right_request_cancel
434 * Purpose:
435 * Cancel a notification request and return the send-once right.
436 * Afterwards, entry->ie_request == 0.
437 * Conditions:
438 * The space must be write-locked; the port must be locked.
439 * The port must be active; the space doesn't have to be.
440 */
441
442 ipc_port_t
443 ipc_right_request_cancel(
444 __unused ipc_space_t space,
445 ipc_port_t port,
446 mach_port_name_t name,
447 ipc_entry_t entry)
448 {
449 ipc_port_t previous;
450
451 require_ip_active(port);
452 assert(port == ip_object_to_port(entry->ie_object));
453
454 if (entry->ie_request == IE_REQ_NONE) {
455 return IP_NULL;
456 }
457
458 previous = ipc_port_request_cancel(port, name, entry->ie_request);
459 entry->ie_request = IE_REQ_NONE;
460 ipc_entry_modified(space, name, entry);
461 return previous;
462 }
463
464 /*
465 * Routine: ipc_right_inuse
466 * Purpose:
467 * Check if an entry is being used.
468 * Returns TRUE if it is.
469 * Conditions:
470 * The space is write-locked and active.
471 * It is unlocked if the entry is inuse.
472 */
473
474 boolean_t
475 ipc_right_inuse(
476 ipc_space_t space,
477 __unused mach_port_name_t name,
478 ipc_entry_t entry)
479 {
480 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
481 is_write_unlock(space);
482 return TRUE;
483 }
484 return FALSE;
485 }
486
487 /*
488 * Routine: ipc_right_check
489 * Purpose:
490 * Check if the port has died. If it has,
491 * and IPC_RIGHT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE is not
492 * passed and it is not a send once right then
493 * clean up the entry and return TRUE.
494 * Conditions:
495 * The space is write-locked; the port is not locked.
496 * If returns FALSE, the port is also locked.
497 * Otherwise, entry is converted to a dead name.
498 *
499 * Caller is responsible for a reference to port if it
500 * had died (returns TRUE).
501 */
502
503 boolean_t
504 ipc_right_check(
505 ipc_space_t space,
506 ipc_port_t port,
507 mach_port_name_t name,
508 ipc_entry_t entry,
509 ipc_right_copyin_flags_t flags)
510 {
511 ipc_entry_bits_t bits;
512
513 assert(is_active(space));
514 assert(port == ip_object_to_port(entry->ie_object));
515
516 ip_lock(port);
517 if (ip_active(port) ||
518 ((flags & IPC_RIGHT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE) &&
519 entry->ie_request == IE_REQ_NONE &&
520 (entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE))) {
521 return FALSE;
522 }
523
524 /* this was either a pure send right or a send-once right */
525
526 bits = entry->ie_bits;
527 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
528 assert(IE_BITS_UREFS(bits) > 0);
529
530 if (bits & MACH_PORT_TYPE_SEND) {
531 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
532 assert(IE_BITS_UREFS(bits) > 0);
533 assert(port->ip_srights > 0);
534 port->ip_srights--;
535 } else {
536 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
537 assert(IE_BITS_UREFS(bits) == 1);
538 assert(port->ip_sorights > 0);
539 port->ip_sorights--;
540 }
541 ip_unlock(port);
542
543 /*
544 * delete SEND rights from ipc hash.
545 */
546
547 if ((bits & MACH_PORT_TYPE_SEND) != 0) {
548 ipc_hash_delete(space, ip_to_object(port), name, entry);
549 }
550
551 /* convert entry to dead name */
552 bits = (bits & ~IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
553
554 /*
555 * If there was a notification request outstanding on this
556 * name, and the port went dead, that notification
557 * must already be on its way up from the port layer.
558 *
559 * Add the reference that the notification carries. It
560 * is done here, and not in the notification delivery,
561 * because the latter doesn't have a space reference and
562 * trying to actually move a send-right reference would
563 * get short-circuited into a MACH_PORT_DEAD by IPC. Since
564 * all calls that deal with the right eventually come
565 * through here, it has the same result.
566 *
567 * Once done, clear the request index so we only account
568 * for it once.
569 */
570 if (entry->ie_request != IE_REQ_NONE) {
571 if (ipc_port_request_type(port, name, entry->ie_request) != 0) {
572 /* if urefs are pegged due to overflow, leave them pegged */
573 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
574 bits++; /* increment urefs */
575 }
576 }
577 entry->ie_request = IE_REQ_NONE;
578 }
579 entry->ie_bits = bits;
580 entry->ie_object = IO_NULL;
581 ipc_entry_modified(space, name, entry);
582 return TRUE;
583 }
584
585 /*
586 * Routine: ipc_right_terminate
587 * Purpose:
588 * Cleans up an entry in a terminated space.
589 * The entry isn't deallocated or removed
590 * from reverse hash tables.
591 * Conditions:
592 * The space is dead and unlocked.
593 */
594
595 void
596 ipc_right_terminate(
597 ipc_space_t space,
598 mach_port_name_t name,
599 ipc_entry_t entry)
600 {
601 ipc_entry_bits_t bits;
602 mach_port_type_t type;
603
604 bits = entry->ie_bits;
605 type = IE_BITS_TYPE(bits);
606
607 assert(!is_active(space));
608
609 /*
610 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
611 * problem, because we check that the port is active. If
612 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
613 * would still work, but dead space refs would accumulate
614 * in ip_dnrequests. They would use up slots in
615 * ip_dnrequests and keep the spaces from being freed.
616 */
617
618 switch (type) {
619 case MACH_PORT_TYPE_DEAD_NAME:
620 assert(entry->ie_request == IE_REQ_NONE);
621 assert(entry->ie_object == IO_NULL);
622 break;
623
624 case MACH_PORT_TYPE_PORT_SET: {
625 ipc_pset_t pset = ips_object_to_pset(entry->ie_object);
626
627 assert(entry->ie_request == IE_REQ_NONE);
628 assert(pset != IPS_NULL);
629
630 ips_lock(pset);
631 assert(ips_active(pset));
632 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
633 break;
634 }
635
636 case MACH_PORT_TYPE_SEND:
637 case MACH_PORT_TYPE_RECEIVE:
638 case MACH_PORT_TYPE_SEND_RECEIVE:
639 case MACH_PORT_TYPE_SEND_ONCE: {
640 ipc_port_t port = ip_object_to_port(entry->ie_object);
641 ipc_port_t request;
642 ipc_port_t nsrequest = IP_NULL;
643 mach_port_mscount_t mscount = 0;
644
645 assert(port != IP_NULL);
646 ip_lock(port);
647
648 if (!ip_active(port)) {
649 ip_unlock(port);
650 ip_release(port);
651 break;
652 }
653
654 request = ipc_right_request_cancel_macro(space, port,
655 name, entry);
656
657 if (type & MACH_PORT_TYPE_SEND) {
658 assert(port->ip_srights > 0);
659 if (--port->ip_srights == 0
660 ) {
661 nsrequest = port->ip_nsrequest;
662 if (nsrequest != IP_NULL) {
663 port->ip_nsrequest = IP_NULL;
664 mscount = port->ip_mscount;
665 }
666 }
667 }
668
669 if (type & MACH_PORT_TYPE_RECEIVE) {
670 assert(port->ip_receiver_name == name);
671 assert(port->ip_receiver == space);
672
673 ipc_port_destroy(port); /* clears receiver, consumes our ref, unlocks */
674 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
675 assert(port->ip_sorights > 0);
676 port->ip_reply_context = 0;
677 ip_unlock(port);
678
679 ipc_notify_send_once(port); /* consumes our ref */
680 } else {
681 assert(port->ip_receiver != space);
682
683 ip_unlock(port);
684 ip_release(port);
685 }
686
687 if (nsrequest != IP_NULL) {
688 ipc_notify_no_senders(nsrequest, mscount);
689 }
690
691 if (request != IP_NULL) {
692 ipc_notify_port_deleted(request, name);
693 }
694 break;
695 }
696
697 default:
698 panic("ipc_right_terminate: strange type - 0x%x", type);
699 }
700 }
701
702 /*
703 * Routine: ipc_right_destroy
704 * Purpose:
705 * Destroys an entry in a space.
706 * Conditions:
707 * The space is write-locked (returns unlocked).
708 * The space must be active.
709 * Returns:
710 * KERN_SUCCESS The entry was destroyed.
711 */
712
713 kern_return_t
714 ipc_right_destroy(
715 ipc_space_t space,
716 mach_port_name_t name,
717 ipc_entry_t entry,
718 boolean_t check_guard,
719 uint64_t guard)
720 {
721 ipc_entry_bits_t bits;
722 mach_port_type_t type;
723
724 bits = entry->ie_bits;
725 entry->ie_bits &= ~IE_BITS_TYPE_MASK;
726 type = IE_BITS_TYPE(bits);
727
728 assert(is_active(space));
729
730 switch (type) {
731 case MACH_PORT_TYPE_DEAD_NAME:
732 assert(entry->ie_request == IE_REQ_NONE);
733 assert(entry->ie_object == IO_NULL);
734
735 ipc_entry_dealloc(space, name, entry);
736 is_write_unlock(space);
737 break;
738
739 case MACH_PORT_TYPE_PORT_SET: {
740 ipc_pset_t pset = ips_object_to_pset(entry->ie_object);
741
742 assert(entry->ie_request == IE_REQ_NONE);
743 assert(pset != IPS_NULL);
744
745 entry->ie_object = IO_NULL;
746 ipc_entry_dealloc(space, name, entry);
747
748 ips_lock(pset);
749 is_write_unlock(space);
750
751 assert(ips_active(pset));
752 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
753 break;
754 }
755
756 case MACH_PORT_TYPE_SEND:
757 case MACH_PORT_TYPE_RECEIVE:
758 case MACH_PORT_TYPE_SEND_RECEIVE:
759 case MACH_PORT_TYPE_SEND_ONCE: {
760 ipc_port_t port = ip_object_to_port(entry->ie_object);
761 ipc_port_t nsrequest = IP_NULL;
762 mach_port_mscount_t mscount = 0;
763 ipc_port_t request;
764
765 assert(port != IP_NULL);
766
767 if (type == MACH_PORT_TYPE_SEND) {
768 ipc_hash_delete(space, ip_to_object(port), name, entry);
769 }
770
771 ip_lock(port);
772
773 if (!ip_active(port)) {
774 assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
775 ip_unlock(port);
776 entry->ie_request = IE_REQ_NONE;
777 entry->ie_object = IO_NULL;
778 ipc_entry_dealloc(space, name, entry);
779 is_write_unlock(space);
780 ip_release(port);
781 break;
782 }
783
784 /* For receive rights, check for guarding */
785 if ((type & MACH_PORT_TYPE_RECEIVE) &&
786 (check_guard) && (port->ip_guarded) &&
787 (guard != port->ip_context)) {
788 /* Guard Violation */
789 uint64_t portguard = port->ip_context;
790 ip_unlock(port);
791 is_write_unlock(space);
792 /* Raise mach port guard exception */
793 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
794 return KERN_INVALID_RIGHT;
795 }
796
797
798 request = ipc_right_request_cancel_macro(space, port, name, entry);
799
800 entry->ie_object = IO_NULL;
801 ipc_entry_dealloc(space, name, entry);
802 is_write_unlock(space);
803
804 if (type & MACH_PORT_TYPE_SEND) {
805 assert(port->ip_srights > 0);
806 if (--port->ip_srights == 0) {
807 nsrequest = port->ip_nsrequest;
808 if (nsrequest != IP_NULL) {
809 port->ip_nsrequest = IP_NULL;
810 mscount = port->ip_mscount;
811 }
812 }
813 }
814
815 if (type & MACH_PORT_TYPE_RECEIVE) {
816 require_ip_active(port);
817 assert(port->ip_receiver == space);
818
819 ipc_port_destroy(port); /* clears receiver, consumes our ref, unlocks */
820 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
821 assert(port->ip_sorights > 0);
822 port->ip_reply_context = 0;
823 ip_unlock(port);
824
825 ipc_notify_send_once(port); /* consumes our ref */
826 } else {
827 assert(port->ip_receiver != space);
828
829 ip_unlock(port);
830 ip_release(port);
831 }
832
833 if (nsrequest != IP_NULL) {
834 ipc_notify_no_senders(nsrequest, mscount);
835 }
836
837 if (request != IP_NULL) {
838 ipc_notify_port_deleted(request, name);
839 }
840
841
842 break;
843 }
844
845 default:
846 panic("ipc_right_destroy: strange type");
847 }
848
849 return KERN_SUCCESS;
850 }
851
852 /*
853 * Routine: ipc_right_dealloc
854 * Purpose:
855 * Releases a send/send-once/dead-name/port_set user ref.
856 * Like ipc_right_delta with a delta of -1,
857 * but looks at the entry to determine the right.
858 * Conditions:
859 * The space is write-locked, and is unlocked upon return.
860 * The space must be active.
861 * Returns:
862 * KERN_SUCCESS A user ref was released.
863 * KERN_INVALID_RIGHT Entry has wrong type.
864 */
865
866 kern_return_t
867 ipc_right_dealloc(
868 ipc_space_t space,
869 mach_port_name_t name,
870 ipc_entry_t entry)
871 {
872 ipc_port_t port = IP_NULL;
873 ipc_entry_bits_t bits;
874 mach_port_type_t type;
875
876 bits = entry->ie_bits;
877 type = IE_BITS_TYPE(bits);
878
879
880 assert(is_active(space));
881
882 switch (type) {
883 case MACH_PORT_TYPE_PORT_SET: {
884 ipc_pset_t pset;
885
886 assert(IE_BITS_UREFS(bits) == 0);
887 assert(entry->ie_request == IE_REQ_NONE);
888
889 pset = ips_object_to_pset(entry->ie_object);
890 assert(pset != IPS_NULL);
891
892 entry->ie_object = IO_NULL;
893 ipc_entry_dealloc(space, name, entry);
894
895 ips_lock(pset);
896 assert(ips_active(pset));
897 is_write_unlock(space);
898
899 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
900 break;
901 }
902
903 case MACH_PORT_TYPE_DEAD_NAME: {
904 dead_name:
905
906 assert(IE_BITS_UREFS(bits) > 0);
907 assert(entry->ie_request == IE_REQ_NONE);
908 assert(entry->ie_object == IO_NULL);
909
910 if (IE_BITS_UREFS(bits) == 1) {
911 ipc_entry_dealloc(space, name, entry);
912 } else {
913 /* if urefs are pegged due to overflow, leave them pegged */
914 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
915 entry->ie_bits = bits - 1; /* decrement urefs */
916 }
917 ipc_entry_modified(space, name, entry);
918 }
919 is_write_unlock(space);
920
921 /* release any port that got converted to dead name below */
922 if (port != IP_NULL) {
923 ip_release(port);
924 }
925 break;
926 }
927
928 case MACH_PORT_TYPE_SEND_ONCE: {
929 ipc_port_t request;
930
931 assert(IE_BITS_UREFS(bits) == 1);
932
933 port = ip_object_to_port(entry->ie_object);
934 assert(port != IP_NULL);
935
936 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
937 bits = entry->ie_bits;
938 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
939 goto dead_name; /* it will release port */
940 }
941 /* port is locked and active */
942
943 assert(port->ip_sorights > 0);
944
945 /*
946 * clear any reply context:
947 * no one will be sending the response b/c we are destroying
948 * the single, outstanding send once right.
949 */
950 port->ip_reply_context = 0;
951
952 request = ipc_right_request_cancel_macro(space, port, name, entry);
953 ip_unlock(port);
954
955 entry->ie_object = IO_NULL;
956 ipc_entry_dealloc(space, name, entry);
957
958 is_write_unlock(space);
959
960 ipc_notify_send_once(port);
961
962 if (request != IP_NULL) {
963 ipc_notify_port_deleted(request, name);
964 }
965 break;
966 }
967
968 case MACH_PORT_TYPE_SEND: {
969 ipc_port_t request = IP_NULL;
970 ipc_port_t nsrequest = IP_NULL;
971 mach_port_mscount_t mscount = 0;
972
973
974 assert(IE_BITS_UREFS(bits) > 0);
975
976 port = ip_object_to_port(entry->ie_object);
977 assert(port != IP_NULL);
978
979 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
980 bits = entry->ie_bits;
981 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
982 goto dead_name; /* it will release port */
983 }
984 /* port is locked and active */
985
986 assert(port->ip_srights > 0);
987
988 if (IE_BITS_UREFS(bits) == 1) {
989 if (--port->ip_srights == 0) {
990 nsrequest = port->ip_nsrequest;
991 if (nsrequest != IP_NULL) {
992 port->ip_nsrequest = IP_NULL;
993 mscount = port->ip_mscount;
994 }
995 }
996
997 request = ipc_right_request_cancel_macro(space, port,
998 name, entry);
999 ipc_hash_delete(space, ip_to_object(port), name, entry);
1000
1001 ip_unlock(port);
1002 entry->ie_object = IO_NULL;
1003 ipc_entry_dealloc(space, name, entry);
1004 is_write_unlock(space);
1005 ip_release(port);
1006 } else {
1007 ip_unlock(port);
1008 /* if urefs are pegged due to overflow, leave them pegged */
1009 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1010 entry->ie_bits = bits - 1; /* decrement urefs */
1011 }
1012 ipc_entry_modified(space, name, entry);
1013 is_write_unlock(space);
1014 }
1015
1016 if (nsrequest != IP_NULL) {
1017 ipc_notify_no_senders(nsrequest, mscount);
1018 }
1019
1020 if (request != IP_NULL) {
1021 ipc_notify_port_deleted(request, name);
1022 }
1023 break;
1024 }
1025
1026 case MACH_PORT_TYPE_SEND_RECEIVE: {
1027 ipc_port_t nsrequest = IP_NULL;
1028 mach_port_mscount_t mscount = 0;
1029
1030 assert(IE_BITS_UREFS(bits) > 0);
1031
1032 port = ip_object_to_port(entry->ie_object);
1033 assert(port != IP_NULL);
1034
1035 ip_lock(port);
1036 require_ip_active(port);
1037 assert(port->ip_receiver_name == name);
1038 assert(port->ip_receiver == space);
1039 assert(port->ip_srights > 0);
1040
1041 if (IE_BITS_UREFS(bits) == 1) {
1042 if (--port->ip_srights == 0) {
1043 nsrequest = port->ip_nsrequest;
1044 if (nsrequest != IP_NULL) {
1045 port->ip_nsrequest = IP_NULL;
1046 mscount = port->ip_mscount;
1047 }
1048 }
1049
1050 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK |
1051 MACH_PORT_TYPE_SEND);
1052 } else {
1053 /* if urefs are pegged due to overflow, leave them pegged */
1054 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1055 entry->ie_bits = bits - 1; /* decrement urefs */
1056 }
1057 }
1058 ip_unlock(port);
1059
1060 ipc_entry_modified(space, name, entry);
1061 is_write_unlock(space);
1062
1063 if (nsrequest != IP_NULL) {
1064 ipc_notify_no_senders(nsrequest, mscount);
1065 }
1066 break;
1067 }
1068
1069 default:
1070 is_write_unlock(space);
1071 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1072 return KERN_INVALID_RIGHT;
1073 }
1074
1075 return KERN_SUCCESS;
1076 }
1077
1078 /*
1079 * Routine: ipc_right_delta
1080 * Purpose:
1081 * Modifies the user-reference count for a right.
1082 * May deallocate the right, if the count goes to zero.
1083 * Conditions:
1084 * The space is write-locked, and is unlocked upon return.
1085 * The space must be active.
1086 * Returns:
1087 * KERN_SUCCESS Count was modified.
1088 * KERN_INVALID_RIGHT Entry has wrong type.
1089 * KERN_INVALID_VALUE Bad delta for the right.
1090 */
1091
1092 kern_return_t
1093 ipc_right_delta(
1094 ipc_space_t space,
1095 mach_port_name_t name,
1096 ipc_entry_t entry,
1097 mach_port_right_t right,
1098 mach_port_delta_t delta)
1099 {
1100 ipc_port_t port = IP_NULL;
1101 ipc_entry_bits_t bits;
1102
1103 bits = entry->ie_bits;
1104
1105 /*
1106 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1107 * switch below. It is used to keep track of those cases (in DIPC)
1108 * where we have postponed the dropping of a port reference. Since
1109 * the dropping of the reference could cause the port to disappear
1110 * we postpone doing so when we are holding the space lock.
1111 */
1112
1113 assert(is_active(space));
1114 assert(right < MACH_PORT_RIGHT_NUMBER);
1115
1116 /* Rights-specific restrictions and operations. */
1117
1118 switch (right) {
1119 case MACH_PORT_RIGHT_PORT_SET: {
1120 ipc_pset_t pset;
1121
1122 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1123 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1124 goto invalid_right;
1125 }
1126
1127 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
1128 assert(IE_BITS_UREFS(bits) == 0);
1129 assert(entry->ie_request == IE_REQ_NONE);
1130
1131 if (delta == 0) {
1132 goto success;
1133 }
1134
1135 if (delta != -1) {
1136 goto invalid_value;
1137 }
1138
1139 pset = ips_object_to_pset(entry->ie_object);
1140 assert(pset != IPS_NULL);
1141
1142 entry->ie_object = IO_NULL;
1143 ipc_entry_dealloc(space, name, entry);
1144
1145 ips_lock(pset);
1146 assert(ips_active(pset));
1147 is_write_unlock(space);
1148
1149 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
1150 break;
1151 }
1152
1153 case MACH_PORT_RIGHT_RECEIVE: {
1154 ipc_port_t request = IP_NULL;
1155
1156 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1157 if ((bits & MACH_PORT_TYPE_EX_RECEIVE) == 0) {
1158 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1159 }
1160 goto invalid_right;
1161 }
1162
1163 if (delta == 0) {
1164 goto success;
1165 }
1166
1167 if (delta != -1) {
1168 goto invalid_value;
1169 }
1170
1171 port = ip_object_to_port(entry->ie_object);
1172 assert(port != IP_NULL);
1173
1174 /*
1175 * The port lock is needed for ipc_right_dncancel;
1176 * otherwise, we wouldn't have to take the lock
1177 * until just before dropping the space lock.
1178 */
1179
1180 ip_lock(port);
1181 require_ip_active(port);
1182 assert(port->ip_receiver_name == name);
1183 assert(port->ip_receiver == space);
1184
1185 /* Mach Port Guard Checking */
1186 if (port->ip_guarded) {
1187 uint64_t portguard = port->ip_context;
1188 ip_unlock(port);
1189 is_write_unlock(space);
1190 /* Raise mach port guard exception */
1191 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_MOD_REFS);
1192 goto guard_failure;
1193 }
1194
1195 if (bits & MACH_PORT_TYPE_SEND) {
1196 assert(IE_BITS_TYPE(bits) ==
1197 MACH_PORT_TYPE_SEND_RECEIVE);
1198 assert(IE_BITS_UREFS(bits) > 0);
1199 assert(port->ip_srights > 0);
1200
1201 if (port->ip_pdrequest != NULL) {
1202 /*
1203 * Since another task has requested a
1204 * destroy notification for this port, it
1205 * isn't actually being destroyed - the receive
1206 * right is just being moved to another task.
1207 * Since we still have one or more send rights,
1208 * we need to record the loss of the receive
1209 * right and enter the remaining send right
1210 * into the hash table.
1211 */
1212 ipc_entry_modified(space, name, entry);
1213 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1214 entry->ie_bits |= MACH_PORT_TYPE_EX_RECEIVE;
1215 ipc_hash_insert(space, ip_to_object(port),
1216 name, entry);
1217 ip_reference(port);
1218 } else {
1219 /*
1220 * The remaining send right turns into a
1221 * dead name. Notice we don't decrement
1222 * ip_srights, generate a no-senders notif,
1223 * or use ipc_right_dncancel, because the
1224 * port is destroyed "first".
1225 */
1226 bits &= ~IE_BITS_TYPE_MASK;
1227 bits |= (MACH_PORT_TYPE_DEAD_NAME | MACH_PORT_TYPE_EX_RECEIVE);
1228 if (entry->ie_request) {
1229 entry->ie_request = IE_REQ_NONE;
1230 /* if urefs are pegged due to overflow, leave them pegged */
1231 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1232 bits++; /* increment urefs */
1233 }
1234 }
1235 entry->ie_bits = bits;
1236 entry->ie_object = IO_NULL;
1237 ipc_entry_modified(space, name, entry);
1238 }
1239 } else {
1240 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1241 assert(IE_BITS_UREFS(bits) == 0);
1242
1243 request = ipc_right_request_cancel_macro(space, port,
1244 name, entry);
1245 entry->ie_object = IO_NULL;
1246 ipc_entry_dealloc(space, name, entry);
1247 }
1248 is_write_unlock(space);
1249
1250 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
1251
1252 if (request != IP_NULL) {
1253 ipc_notify_port_deleted(request, name);
1254 }
1255 break;
1256 }
1257
1258 case MACH_PORT_RIGHT_SEND_ONCE: {
1259 ipc_port_t request;
1260
1261 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1262 goto invalid_right;
1263 }
1264
1265 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1266 assert(IE_BITS_UREFS(bits) == 1);
1267
1268 port = ip_object_to_port(entry->ie_object);
1269 assert(port != IP_NULL);
1270
1271 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1272 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1273 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1274 goto invalid_right;
1275 }
1276 /* port is locked and active */
1277
1278 assert(port->ip_sorights > 0);
1279
1280 if ((delta > 0) || (delta < -1)) {
1281 ip_unlock(port);
1282 goto invalid_value;
1283 }
1284
1285 if (delta == 0) {
1286 ip_unlock(port);
1287 goto success;
1288 }
1289
1290 /*
1291 * clear any reply context:
1292 * no one will be sending the response b/c we are destroying
1293 * the single, outstanding send once right.
1294 */
1295 port->ip_reply_context = 0;
1296
1297 request = ipc_right_request_cancel_macro(space, port, name, entry);
1298 ip_unlock(port);
1299
1300 entry->ie_object = IO_NULL;
1301 ipc_entry_dealloc(space, name, entry);
1302
1303 is_write_unlock(space);
1304
1305 ipc_notify_send_once(port);
1306
1307 if (request != IP_NULL) {
1308 ipc_notify_port_deleted(request, name);
1309 }
1310 break;
1311 }
1312
1313 case MACH_PORT_RIGHT_DEAD_NAME: {
1314 ipc_port_t relport = IP_NULL;
1315 mach_port_urefs_t urefs;
1316
1317 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1318 port = ip_object_to_port(entry->ie_object);
1319 assert(port != IP_NULL);
1320
1321 if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1322 /* port is locked and active */
1323 ip_unlock(port);
1324 port = IP_NULL;
1325 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1326 goto invalid_right;
1327 }
1328 bits = entry->ie_bits;
1329 relport = port;
1330 port = IP_NULL;
1331 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0) {
1332 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1333 goto invalid_right;
1334 }
1335
1336 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1337 assert(IE_BITS_UREFS(bits) > 0);
1338 assert(entry->ie_object == IO_NULL);
1339 assert(entry->ie_request == IE_REQ_NONE);
1340
1341 if (delta > ((mach_port_delta_t)MACH_PORT_UREFS_MAX) ||
1342 delta < (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1343 goto invalid_value;
1344 }
1345
1346 urefs = IE_BITS_UREFS(bits);
1347
1348 if (urefs == MACH_PORT_UREFS_MAX) {
1349 /*
1350 * urefs are pegged due to an overflow
1351 * only a delta removing all refs at once can change it
1352 */
1353
1354 if (delta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1355 delta = 0;
1356 }
1357 } else {
1358 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1359 goto invalid_value;
1360 }
1361 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) {
1362 /* leave urefs pegged to maximum if it overflowed */
1363 delta = MACH_PORT_UREFS_MAX - urefs;
1364 }
1365 }
1366
1367 if ((urefs + delta) == 0) {
1368 ipc_entry_dealloc(space, name, entry);
1369 } else if (delta != 0) {
1370 entry->ie_bits = bits + delta;
1371 ipc_entry_modified(space, name, entry);
1372 }
1373
1374 is_write_unlock(space);
1375
1376 if (relport != IP_NULL) {
1377 ip_release(relport);
1378 }
1379
1380 break;
1381 }
1382
1383 case MACH_PORT_RIGHT_SEND: {
1384 mach_port_urefs_t urefs;
1385 ipc_port_t request = IP_NULL;
1386 ipc_port_t nsrequest = IP_NULL;
1387 ipc_port_t port_to_release = IP_NULL;
1388 mach_port_mscount_t mscount = 0;
1389
1390 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1391 /* invalid right exception only when not live/dead confusion */
1392 if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0
1393 #if !defined(AE_MAKESENDRIGHT_FIXED)
1394 /*
1395 * AE tries to add single send right without knowing if it already owns one.
1396 * But if it doesn't, it should own the receive right and delta should be 1.
1397 */
1398 && (((bits & MACH_PORT_TYPE_RECEIVE) == 0) || (delta != 1))
1399 #endif
1400 ) {
1401 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1402 }
1403 goto invalid_right;
1404 }
1405
1406 /* maximum urefs for send is MACH_PORT_UREFS_MAX */
1407
1408 port = ip_object_to_port(entry->ie_object);
1409 assert(port != IP_NULL);
1410
1411 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1412 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1413 goto invalid_right;
1414 }
1415 /* port is locked and active */
1416
1417 assert(port->ip_srights > 0);
1418
1419 if (delta > ((mach_port_delta_t)MACH_PORT_UREFS_MAX) ||
1420 delta < (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1421 ip_unlock(port);
1422 goto invalid_value;
1423 }
1424
1425 urefs = IE_BITS_UREFS(bits);
1426
1427 if (urefs == MACH_PORT_UREFS_MAX) {
1428 /*
1429 * urefs are pegged due to an overflow
1430 * only a delta removing all refs at once can change it
1431 */
1432
1433 if (delta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1434 delta = 0;
1435 }
1436 } else {
1437 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1438 ip_unlock(port);
1439 goto invalid_value;
1440 }
1441 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) {
1442 /* leave urefs pegged to maximum if it overflowed */
1443 delta = MACH_PORT_UREFS_MAX - urefs;
1444 }
1445 }
1446
1447 if ((urefs + delta) == 0) {
1448 if (--port->ip_srights == 0) {
1449 nsrequest = port->ip_nsrequest;
1450 if (nsrequest != IP_NULL) {
1451 port->ip_nsrequest = IP_NULL;
1452 mscount = port->ip_mscount;
1453 }
1454 }
1455
1456 if (bits & MACH_PORT_TYPE_RECEIVE) {
1457 assert(port->ip_receiver_name == name);
1458 assert(port->ip_receiver == space);
1459 ip_unlock(port);
1460 assert(IE_BITS_TYPE(bits) ==
1461 MACH_PORT_TYPE_SEND_RECEIVE);
1462
1463 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK |
1464 MACH_PORT_TYPE_SEND);
1465 ipc_entry_modified(space, name, entry);
1466 } else {
1467 assert(IE_BITS_TYPE(bits) ==
1468 MACH_PORT_TYPE_SEND);
1469
1470 request = ipc_right_request_cancel_macro(space, port,
1471 name, entry);
1472 ipc_hash_delete(space, ip_to_object(port),
1473 name, entry);
1474
1475 ip_unlock(port);
1476 port_to_release = port;
1477
1478 entry->ie_object = IO_NULL;
1479 ipc_entry_dealloc(space, name, entry);
1480 }
1481 } else if (delta != 0) {
1482 ip_unlock(port);
1483 entry->ie_bits = bits + delta;
1484 ipc_entry_modified(space, name, entry);
1485 } else {
1486 ip_unlock(port);
1487 }
1488
1489 is_write_unlock(space);
1490
1491 if (port_to_release != IP_NULL) {
1492 ip_release(port_to_release);
1493 }
1494
1495 if (nsrequest != IP_NULL) {
1496 ipc_notify_no_senders(nsrequest, mscount);
1497 }
1498
1499 if (request != IP_NULL) {
1500 ipc_notify_port_deleted(request, name);
1501 }
1502 break;
1503 }
1504
1505 case MACH_PORT_RIGHT_LABELH:
1506 goto invalid_right;
1507
1508 default:
1509 panic("ipc_right_delta: strange right %d for 0x%x (%p) in space:%p",
1510 right, name, (void *)entry, (void *)space);
1511 }
1512
1513 return KERN_SUCCESS;
1514
1515 success:
1516 is_write_unlock(space);
1517 return KERN_SUCCESS;
1518
1519 invalid_right:
1520 is_write_unlock(space);
1521 if (port != IP_NULL) {
1522 ip_release(port);
1523 }
1524 return KERN_INVALID_RIGHT;
1525
1526 invalid_value:
1527 is_write_unlock(space);
1528 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
1529 return KERN_INVALID_VALUE;
1530
1531 guard_failure:
1532 return KERN_INVALID_RIGHT;
1533 }
1534
1535 /*
1536 * Routine: ipc_right_destruct
1537 * Purpose:
1538 * Deallocates the receive right and modifies the
1539 * user-reference count for the send rights as requested.
1540 * Conditions:
1541 * The space is write-locked, and is unlocked upon return.
1542 * The space must be active.
1543 * Returns:
1544 * KERN_SUCCESS Count was modified.
1545 * KERN_INVALID_RIGHT Entry has wrong type.
1546 * KERN_INVALID_VALUE Bad delta for the right.
1547 */
1548
1549 kern_return_t
1550 ipc_right_destruct(
1551 ipc_space_t space,
1552 mach_port_name_t name,
1553 ipc_entry_t entry,
1554 mach_port_delta_t srdelta,
1555 uint64_t guard)
1556 {
1557 ipc_port_t port = IP_NULL;
1558 ipc_entry_bits_t bits;
1559
1560 mach_port_urefs_t urefs;
1561 ipc_port_t request = IP_NULL;
1562 ipc_port_t nsrequest = IP_NULL;
1563 mach_port_mscount_t mscount = 0;
1564
1565 bits = entry->ie_bits;
1566
1567 assert(is_active(space));
1568
1569 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1570 is_write_unlock(space);
1571
1572 /* No exception if we used to have receive and held entry since */
1573 if ((bits & MACH_PORT_TYPE_EX_RECEIVE) == 0) {
1574 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1575 }
1576 return KERN_INVALID_RIGHT;
1577 }
1578
1579 if (srdelta && (bits & MACH_PORT_TYPE_SEND) == 0) {
1580 is_write_unlock(space);
1581 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1582 return KERN_INVALID_RIGHT;
1583 }
1584
1585 if (srdelta > 0) {
1586 goto invalid_value;
1587 }
1588
1589 port = ip_object_to_port(entry->ie_object);
1590 assert(port != IP_NULL);
1591
1592 ip_lock(port);
1593 require_ip_active(port);
1594 assert(port->ip_receiver_name == name);
1595 assert(port->ip_receiver == space);
1596
1597 /* Mach Port Guard Checking */
1598 if (port->ip_guarded && (guard != port->ip_context)) {
1599 uint64_t portguard = port->ip_context;
1600 ip_unlock(port);
1601 is_write_unlock(space);
1602 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
1603 return KERN_INVALID_ARGUMENT;
1604 }
1605
1606 /*
1607 * First reduce the send rights as requested and
1608 * adjust the entry->ie_bits accordingly. The
1609 * ipc_entry_modified() call is made once the receive
1610 * right is destroyed too.
1611 */
1612
1613 if (srdelta) {
1614 assert(port->ip_srights > 0);
1615
1616 urefs = IE_BITS_UREFS(bits);
1617
1618 /*
1619 * Since we made sure that srdelta is negative,
1620 * the check for urefs overflow is not required.
1621 */
1622 if (MACH_PORT_UREFS_UNDERFLOW(urefs, srdelta)) {
1623 ip_unlock(port);
1624 goto invalid_value;
1625 }
1626
1627 if (urefs == MACH_PORT_UREFS_MAX) {
1628 /*
1629 * urefs are pegged due to an overflow
1630 * only a delta removing all refs at once can change it
1631 */
1632 if (srdelta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1633 srdelta = 0;
1634 }
1635 }
1636
1637 if ((urefs + srdelta) == 0) {
1638 if (--port->ip_srights == 0) {
1639 nsrequest = port->ip_nsrequest;
1640 if (nsrequest != IP_NULL) {
1641 port->ip_nsrequest = IP_NULL;
1642 mscount = port->ip_mscount;
1643 }
1644 }
1645 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_RECEIVE);
1646 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK |
1647 MACH_PORT_TYPE_SEND);
1648 } else {
1649 entry->ie_bits = bits + srdelta;
1650 }
1651 }
1652
1653 /*
1654 * Now destroy the receive right. Update space and
1655 * entry accordingly.
1656 */
1657
1658 bits = entry->ie_bits;
1659 if (bits & MACH_PORT_TYPE_SEND) {
1660 assert(IE_BITS_UREFS(bits) > 0);
1661 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
1662
1663 if (port->ip_pdrequest != NULL) {
1664 /*
1665 * Since another task has requested a
1666 * destroy notification for this port, it
1667 * isn't actually being destroyed - the receive
1668 * right is just being moved to another task.
1669 * Since we still have one or more send rights,
1670 * we need to record the loss of the receive
1671 * right and enter the remaining send right
1672 * into the hash table.
1673 */
1674 ipc_entry_modified(space, name, entry);
1675 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1676 entry->ie_bits |= MACH_PORT_TYPE_EX_RECEIVE;
1677 ipc_hash_insert(space, ip_to_object(port),
1678 name, entry);
1679 ip_reference(port);
1680 } else {
1681 /*
1682 * The remaining send right turns into a
1683 * dead name. Notice we don't decrement
1684 * ip_srights, generate a no-senders notif,
1685 * or use ipc_right_dncancel, because the
1686 * port is destroyed "first".
1687 */
1688 bits &= ~IE_BITS_TYPE_MASK;
1689 bits |= (MACH_PORT_TYPE_DEAD_NAME | MACH_PORT_TYPE_EX_RECEIVE);
1690 if (entry->ie_request) {
1691 entry->ie_request = IE_REQ_NONE;
1692 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1693 bits++; /* increment urefs */
1694 }
1695 }
1696 entry->ie_bits = bits;
1697 entry->ie_object = IO_NULL;
1698 ipc_entry_modified(space, name, entry);
1699 }
1700 } else {
1701 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1702 assert(IE_BITS_UREFS(bits) == 0);
1703 request = ipc_right_request_cancel_macro(space, port,
1704 name, entry);
1705 entry->ie_object = IO_NULL;
1706 ipc_entry_dealloc(space, name, entry);
1707 }
1708
1709 /* Unlock space */
1710 is_write_unlock(space);
1711
1712 if (nsrequest != IP_NULL) {
1713 ipc_notify_no_senders(nsrequest, mscount);
1714 }
1715
1716 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
1717
1718 if (request != IP_NULL) {
1719 ipc_notify_port_deleted(request, name);
1720 }
1721
1722 return KERN_SUCCESS;
1723
1724 invalid_value:
1725 is_write_unlock(space);
1726 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
1727 return KERN_INVALID_VALUE;
1728 }
1729
1730
1731 /*
1732 * Routine: ipc_right_info
1733 * Purpose:
1734 * Retrieves information about the right.
1735 * Conditions:
1736 * The space is active and write-locked.
1737 * The space is unlocked upon return.
1738 * Returns:
1739 * KERN_SUCCESS Retrieved info
1740 */
1741
1742 kern_return_t
1743 ipc_right_info(
1744 ipc_space_t space,
1745 mach_port_name_t name,
1746 ipc_entry_t entry,
1747 mach_port_type_t *typep,
1748 mach_port_urefs_t *urefsp)
1749 {
1750 ipc_port_t port;
1751 ipc_entry_bits_t bits;
1752 mach_port_type_t type = 0;
1753 ipc_port_request_index_t request;
1754
1755 bits = entry->ie_bits;
1756 request = entry->ie_request;
1757 port = ip_object_to_port(entry->ie_object);
1758
1759 if (bits & MACH_PORT_TYPE_RECEIVE) {
1760 assert(IP_VALID(port));
1761
1762 if (request != IE_REQ_NONE) {
1763 ip_lock(port);
1764 require_ip_active(port);
1765 type |= ipc_port_request_type(port, name, request);
1766 ip_unlock(port);
1767 }
1768 is_write_unlock(space);
1769 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1770 /*
1771 * validate port is still alive - if so, get request
1772 * types while we still have it locked. Otherwise,
1773 * recapture the (now dead) bits.
1774 */
1775 if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1776 if (request != IE_REQ_NONE) {
1777 type |= ipc_port_request_type(port, name, request);
1778 }
1779 ip_unlock(port);
1780 is_write_unlock(space);
1781 } else {
1782 bits = entry->ie_bits;
1783 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1784 is_write_unlock(space);
1785 ip_release(port);
1786 }
1787 } else {
1788 is_write_unlock(space);
1789 }
1790
1791 type |= IE_BITS_TYPE(bits);
1792
1793 *typep = type;
1794 *urefsp = IE_BITS_UREFS(bits);
1795 return KERN_SUCCESS;
1796 }
1797
1798 /*
1799 * Routine: ipc_right_copyin_check_reply
1800 * Purpose:
1801 * Check if a subsequent ipc_right_copyin would succeed. Used only
1802 * by ipc_kmsg_copyin_header to check if reply_port can be copied in.
1803 * If the reply port is an immovable send right, it errors out.
1804 * Conditions:
1805 * The space is locked (read or write) and active.
1806 */
1807
1808 boolean_t
1809 ipc_right_copyin_check_reply(
1810 __assert_only ipc_space_t space,
1811 mach_port_name_t reply_name,
1812 ipc_entry_t reply_entry,
1813 mach_msg_type_name_t reply_type)
1814 {
1815 ipc_entry_bits_t bits;
1816 ipc_port_t reply_port;
1817
1818 bits = reply_entry->ie_bits;
1819 assert(is_active(space));
1820
1821 switch (reply_type) {
1822 case MACH_MSG_TYPE_MAKE_SEND:
1823 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1824 return FALSE;
1825 }
1826 break;
1827
1828 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1829 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1830 return FALSE;
1831 }
1832 break;
1833
1834 case MACH_MSG_TYPE_MOVE_RECEIVE:
1835 /* ipc_kmsg_copyin_header already filters it out */
1836 return FALSE;
1837
1838 case MACH_MSG_TYPE_COPY_SEND:
1839 case MACH_MSG_TYPE_MOVE_SEND:
1840 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1841 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
1842 break;
1843 }
1844
1845 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1846 return FALSE;
1847 }
1848
1849 reply_port = ip_object_to_port(reply_entry->ie_object);
1850 assert(reply_port != IP_NULL);
1851
1852 /*
1853 * active status peek to avoid checks that will be skipped
1854 * on copyin for dead ports. Lock not held, so will not be
1855 * atomic (but once dead, there's no going back).
1856 */
1857 if (!ip_active(reply_port)) {
1858 break;
1859 }
1860
1861 /*
1862 * Can't copyin a send right that is marked immovable. This bit
1863 * is set only during port creation and never unset. So it can
1864 * be read without a lock.
1865 */
1866 if (reply_port->ip_immovable_send) {
1867 mach_port_guard_exception(reply_name, 0, 0, kGUARD_EXC_IMMOVABLE);
1868 return FALSE;
1869 }
1870
1871 if (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1872 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1873 return FALSE;
1874 }
1875 } else {
1876 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1877 return FALSE;
1878 }
1879 }
1880
1881 break;
1882 }
1883
1884 default:
1885 panic("ipc_right_copyin_check: strange rights");
1886 }
1887
1888 return TRUE;
1889 }
1890
1891 /*
1892 * Routine: ipc_right_copyin_check_guard_locked
1893 * Purpose:
1894 * Check if the port is guarded and the guard
1895 * value matches the one passed in the arguments.
1896 * If MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND is set,
1897 * check if the port is unguarded.
1898 * Conditions:
1899 * The port is locked.
1900 * Returns:
1901 * KERN_SUCCESS Port is either unguarded
1902 * or guarded with expected value
1903 * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
1904 * This also raises a EXC_GUARD exception.
1905 */
1906 static kern_return_t
1907 ipc_right_copyin_check_guard_locked(
1908 mach_port_name_t name,
1909 ipc_port_t port,
1910 mach_port_context_t context,
1911 mach_msg_guard_flags_t *guard_flags)
1912 {
1913 mach_msg_guard_flags_t flags = *guard_flags;
1914 if ((flags & MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND) && !port->ip_guarded && !context) {
1915 return KERN_SUCCESS;
1916 } else if (port->ip_guarded && (port->ip_context == context)) {
1917 return KERN_SUCCESS;
1918 }
1919
1920 /* Incorrect guard; Raise exception */
1921 mach_port_guard_exception(name, context, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
1922 return KERN_INVALID_ARGUMENT;
1923 }
1924
1925 /*
1926 * Routine: ipc_right_copyin
1927 * Purpose:
1928 * Copyin a capability from a space.
1929 * If successful, the caller gets a ref
1930 * for the resulting object, unless it is IO_DEAD,
1931 * and possibly a send-once right which should
1932 * be used in a port-deleted notification.
1933 *
1934 * If deadok is not TRUE, the copyin operation
1935 * will fail instead of producing IO_DEAD.
1936 *
1937 * The entry is never deallocated (except
1938 * when KERN_INVALID_NAME), so the caller
1939 * should deallocate the entry if its type
1940 * is MACH_PORT_TYPE_NONE.
1941 * Conditions:
1942 * The space is write-locked and active.
1943 * Returns:
1944 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1945 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1946 * KERN_INVALID_CAPABILITY Trying to move an kobject port or an immovable right
1947 * KERN_INVALID_ARGUMENT Port is unguarded or guard mismatch
1948 */
1949
1950 kern_return_t
1951 ipc_right_copyin(
1952 ipc_space_t space,
1953 mach_port_name_t name,
1954 ipc_entry_t entry,
1955 mach_msg_type_name_t msgt_name,
1956 ipc_right_copyin_flags_t flags,
1957 ipc_object_t *objectp,
1958 ipc_port_t *sorightp,
1959 ipc_port_t *releasep,
1960 int *assertcntp,
1961 mach_port_context_t context,
1962 mach_msg_guard_flags_t *guard_flags)
1963 {
1964 ipc_entry_bits_t bits;
1965 ipc_port_t port;
1966 kern_return_t kr;
1967 boolean_t deadok = flags & IPC_RIGHT_COPYIN_FLAGS_DEADOK? TRUE : FALSE;
1968 boolean_t allow_imm_send = flags & IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND? TRUE : FALSE;
1969
1970 *releasep = IP_NULL;
1971 *assertcntp = 0;
1972
1973 bits = entry->ie_bits;
1974
1975 assert(is_active(space));
1976
1977 switch (msgt_name) {
1978 case MACH_MSG_TYPE_MAKE_SEND: {
1979 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1980 goto invalid_right;
1981 }
1982
1983 port = ip_object_to_port(entry->ie_object);
1984 assert(port != IP_NULL);
1985
1986 ip_lock(port);
1987 assert(port->ip_receiver_name == name);
1988 assert(port->ip_receiver == space);
1989
1990 ipc_port_make_send_locked(port);
1991 ip_unlock(port);
1992
1993 *objectp = ip_to_object(port);
1994 *sorightp = IP_NULL;
1995 break;
1996 }
1997
1998 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1999 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
2000 goto invalid_right;
2001 }
2002
2003 port = ip_object_to_port(entry->ie_object);
2004 assert(port != IP_NULL);
2005
2006 ip_lock(port);
2007 require_ip_active(port);
2008 assert(port->ip_receiver_name == name);
2009 assert(port->ip_receiver == space);
2010
2011 ipc_port_make_sonce_locked(port);
2012 ip_unlock(port);
2013
2014 *objectp = ip_to_object(port);
2015 *sorightp = IP_NULL;
2016 break;
2017 }
2018
2019 case MACH_MSG_TYPE_MOVE_RECEIVE: {
2020 ipc_port_t request = IP_NULL;
2021
2022 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
2023 goto invalid_right;
2024 }
2025
2026 /*
2027 * Disallow moving receive-right kobjects, e.g. mk_timer ports
2028 * The ipc_port structure uses the kdata union of kobject and
2029 * imp_task exclusively. Thus, general use of a kobject port as
2030 * a receive right can cause type confusion in the importance
2031 * code.
2032 */
2033 if (io_kotype(entry->ie_object) != IKOT_NONE) {
2034 /*
2035 * Distinguish an invalid right, e.g., trying to move
2036 * a send right as a receive right, from this
2037 * situation which is, "This is a valid receive right,
2038 * but it's also a kobject and you can't move it."
2039 */
2040 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
2041 return KERN_INVALID_CAPABILITY;
2042 }
2043
2044 port = ip_object_to_port(entry->ie_object);
2045 assert(port != IP_NULL);
2046
2047 ip_lock(port);
2048 require_ip_active(port);
2049 assert(port->ip_receiver_name == name);
2050 assert(port->ip_receiver == space);
2051
2052 if (port->ip_immovable_receive) {
2053 assert(port->ip_receiver != ipc_space_kernel);
2054 ip_unlock(port);
2055 assert(current_task() != kernel_task);
2056 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
2057 return KERN_INVALID_CAPABILITY;
2058 }
2059
2060 if (guard_flags != NULL) {
2061 kr = ipc_right_copyin_check_guard_locked(name, port, context, guard_flags);
2062 if (kr != KERN_SUCCESS) {
2063 ip_unlock(port);
2064 return kr;
2065 }
2066 }
2067
2068 if (bits & MACH_PORT_TYPE_SEND) {
2069 assert(IE_BITS_TYPE(bits) ==
2070 MACH_PORT_TYPE_SEND_RECEIVE);
2071 assert(IE_BITS_UREFS(bits) > 0);
2072 assert(port->ip_srights > 0);
2073
2074 ipc_hash_insert(space, ip_to_object(port),
2075 name, entry);
2076 ip_reference(port);
2077 } else {
2078 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2079 assert(IE_BITS_UREFS(bits) == 0);
2080
2081 request = ipc_right_request_cancel_macro(space, port,
2082 name, entry);
2083 entry->ie_object = IO_NULL;
2084 }
2085 entry->ie_bits = bits & ~MACH_PORT_TYPE_RECEIVE;
2086 entry->ie_bits |= MACH_PORT_TYPE_EX_RECEIVE;
2087 ipc_entry_modified(space, name, entry);
2088
2089 /* ipc_port_clear_receiver unguards the port and clears the ip_immovable_receive bit */
2090 (void)ipc_port_clear_receiver(port, FALSE); /* don't destroy the port/mqueue */
2091 if (guard_flags != NULL) {
2092 /* this flag will be cleared during copyout */
2093 *guard_flags = *guard_flags | MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND;
2094 }
2095
2096 #if IMPORTANCE_INHERITANCE
2097 /*
2098 * Account for boosts the current task is going to lose when
2099 * copying this right in. Tempowner ports have either not
2100 * been accounting to any task (and therefore are already in
2101 * "limbo" state w.r.t. assertions) or to some other specific
2102 * task. As we have no way to drop the latter task's assertions
2103 * here, We'll deduct those when we enqueue it on its
2104 * destination port (see ipc_port_check_circularity()).
2105 */
2106 if (port->ip_tempowner == 0) {
2107 assert(IIT_NULL == port->ip_imp_task);
2108
2109 /* ports in limbo have to be tempowner */
2110 port->ip_tempowner = 1;
2111 *assertcntp = port->ip_impcount;
2112 }
2113 #endif /* IMPORTANCE_INHERITANCE */
2114
2115 ip_unlock(port);
2116
2117 *objectp = ip_to_object(port);
2118 *sorightp = request;
2119 break;
2120 }
2121
2122 case MACH_MSG_TYPE_COPY_SEND: {
2123 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
2124 goto copy_dead;
2125 }
2126
2127 /* allow for dead send-once rights */
2128
2129 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
2130 goto invalid_right;
2131 }
2132
2133 assert(IE_BITS_UREFS(bits) > 0);
2134
2135 port = ip_object_to_port(entry->ie_object);
2136 assert(port != IP_NULL);
2137
2138 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2139 bits = entry->ie_bits;
2140 *releasep = port;
2141 goto copy_dead;
2142 }
2143 /* port is locked and active */
2144
2145 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2146 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2147 assert(port->ip_sorights > 0);
2148
2149 ip_unlock(port);
2150 goto invalid_right;
2151 }
2152
2153 if (!allow_imm_send && port->ip_immovable_send) {
2154 ip_unlock(port);
2155 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
2156 return KERN_INVALID_CAPABILITY;
2157 }
2158
2159 ipc_port_copy_send_locked(port);
2160 ip_unlock(port);
2161
2162 *objectp = ip_to_object(port);
2163 *sorightp = IP_NULL;
2164 break;
2165 }
2166
2167 case MACH_MSG_TYPE_MOVE_SEND: {
2168 ipc_port_t request = IP_NULL;
2169
2170 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
2171 goto move_dead;
2172 }
2173
2174 /* allow for dead send-once rights */
2175
2176 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
2177 goto invalid_right;
2178 }
2179
2180 assert(IE_BITS_UREFS(bits) > 0);
2181
2182 port = ip_object_to_port(entry->ie_object);
2183 assert(port != IP_NULL);
2184
2185 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2186 bits = entry->ie_bits;
2187 *releasep = port;
2188 goto move_dead;
2189 }
2190 /* port is locked and active */
2191
2192 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2193 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2194 assert(port->ip_sorights > 0);
2195
2196 ip_unlock(port);
2197 goto invalid_right;
2198 }
2199
2200 if (!allow_imm_send && port->ip_immovable_send) {
2201 ip_unlock(port);
2202 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
2203 return KERN_INVALID_CAPABILITY;
2204 }
2205
2206 if (IE_BITS_UREFS(bits) == 1) {
2207 assert(port->ip_srights > 0);
2208 if (bits & MACH_PORT_TYPE_RECEIVE) {
2209 assert(port->ip_receiver_name == name);
2210 assert(port->ip_receiver == space);
2211 assert(IE_BITS_TYPE(bits) ==
2212 MACH_PORT_TYPE_SEND_RECEIVE);
2213
2214 ip_reference(port);
2215 } else {
2216 assert(IE_BITS_TYPE(bits) ==
2217 MACH_PORT_TYPE_SEND);
2218
2219 request = ipc_right_request_cancel_macro(space, port,
2220 name, entry);
2221 ipc_hash_delete(space, ip_to_object(port),
2222 name, entry);
2223 entry->ie_object = IO_NULL;
2224 /* transfer entry's reference to caller */
2225 }
2226 entry->ie_bits = bits & ~
2227 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND);
2228 } else {
2229 ipc_port_copy_send_locked(port);
2230 /* if urefs are pegged due to overflow, leave them pegged */
2231 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2232 entry->ie_bits = bits - 1; /* decrement urefs */
2233 }
2234 }
2235
2236 ipc_entry_modified(space, name, entry);
2237 ip_unlock(port);
2238
2239 *objectp = ip_to_object(port);
2240 *sorightp = request;
2241 break;
2242 }
2243
2244 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
2245 ipc_port_t request;
2246
2247 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
2248 goto move_dead;
2249 }
2250
2251 /* allow for dead send rights */
2252
2253 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
2254 goto invalid_right;
2255 }
2256
2257 assert(IE_BITS_UREFS(bits) > 0);
2258
2259 port = ip_object_to_port(entry->ie_object);
2260 assert(port != IP_NULL);
2261
2262 if (ipc_right_check(space, port, name, entry, flags)) {
2263 bits = entry->ie_bits;
2264 *releasep = port;
2265 goto move_dead;
2266 }
2267 /*
2268 * port is locked, but may not be active:
2269 * Allow copyin of inactive ports with no dead name request and treat it
2270 * as if the copyin of the port was successful and port became inactive
2271 * later.
2272 */
2273
2274 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
2275 assert(bits & MACH_PORT_TYPE_SEND);
2276 assert(port->ip_srights > 0);
2277
2278 ip_unlock(port);
2279 goto invalid_right;
2280 }
2281
2282 if (!allow_imm_send && port->ip_immovable_send) {
2283 ip_unlock(port);
2284 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_IMMOVABLE);
2285 return KERN_INVALID_CAPABILITY;
2286 }
2287
2288 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2289 assert(IE_BITS_UREFS(bits) == 1);
2290 assert(port->ip_sorights > 0);
2291
2292 request = ipc_right_request_cancel_macro(space, port, name, entry);
2293 ip_unlock(port);
2294
2295 entry->ie_object = IO_NULL;
2296 entry->ie_bits = bits & ~
2297 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
2298 ipc_entry_modified(space, name, entry);
2299 *objectp = ip_to_object(port);
2300 *sorightp = request;
2301 break;
2302 }
2303
2304 default:
2305 invalid_right:
2306 return KERN_INVALID_RIGHT;
2307 }
2308
2309 return KERN_SUCCESS;
2310
2311 copy_dead:
2312 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2313 assert(IE_BITS_UREFS(bits) > 0);
2314 assert(entry->ie_request == IE_REQ_NONE);
2315 assert(entry->ie_object == 0);
2316
2317 if (!deadok) {
2318 goto invalid_right;
2319 }
2320
2321 *objectp = IO_DEAD;
2322 *sorightp = IP_NULL;
2323 return KERN_SUCCESS;
2324
2325 move_dead:
2326 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2327 assert(IE_BITS_UREFS(bits) > 0);
2328 assert(entry->ie_request == IE_REQ_NONE);
2329 assert(entry->ie_object == 0);
2330
2331 if (!deadok) {
2332 goto invalid_right;
2333 }
2334
2335 if (IE_BITS_UREFS(bits) == 1) {
2336 bits &= ~MACH_PORT_TYPE_DEAD_NAME;
2337 }
2338 /* if urefs are pegged due to overflow, leave them pegged */
2339 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2340 entry->ie_bits = bits - 1; /* decrement urefs */
2341 }
2342 ipc_entry_modified(space, name, entry);
2343 *objectp = IO_DEAD;
2344 *sorightp = IP_NULL;
2345 return KERN_SUCCESS;
2346 }
2347
2348 /*
2349 * Routine: ipc_right_copyin_two_move_sends
2350 * Purpose:
2351 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2352 * and deadok == FALSE, except that this moves two
2353 * send rights at once.
2354 * Conditions:
2355 * The space is write-locked and active.
2356 * The object is returned with two refs/send rights.
2357 * Returns:
2358 * KERN_SUCCESS Acquired an object.
2359 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2360 */
2361 static
2362 kern_return_t
2363 ipc_right_copyin_two_move_sends(
2364 ipc_space_t space,
2365 mach_port_name_t name,
2366 ipc_entry_t entry,
2367 ipc_object_t *objectp,
2368 ipc_port_t *sorightp,
2369 ipc_port_t *releasep)
2370 {
2371 ipc_entry_bits_t bits;
2372 mach_port_urefs_t urefs;
2373 ipc_port_t port;
2374 ipc_port_t request = IP_NULL;
2375
2376 *releasep = IP_NULL;
2377
2378 assert(is_active(space));
2379
2380 bits = entry->ie_bits;
2381
2382 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2383 goto invalid_right;
2384 }
2385
2386 urefs = IE_BITS_UREFS(bits);
2387 if (urefs < 2) {
2388 goto invalid_right;
2389 }
2390
2391 port = ip_object_to_port(entry->ie_object);
2392 assert(port != IP_NULL);
2393
2394 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2395 *releasep = port;
2396 goto invalid_right;
2397 }
2398 /* port is locked and active */
2399
2400 if (urefs > 2) {
2401 /*
2402 * We are moving 2 urefs as naked send rights, which is decomposed as:
2403 * - two copy sends (which doesn't affect the make send count)
2404 * - decrementing the local urefs twice.
2405 */
2406 ipc_port_copy_send_locked(port);
2407 ipc_port_copy_send_locked(port);
2408 /* if urefs are pegged due to overflow, leave them pegged */
2409 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2410 entry->ie_bits = bits - 2; /* decrement urefs */
2411 }
2412 } else {
2413 /*
2414 * We have exactly 2 send rights for this port in this space,
2415 * which means that we will liberate the naked send right held
2416 * by this entry.
2417 *
2418 * However refcounting rules around entries are that naked send rights
2419 * on behalf of spaces do not have an associated port reference,
2420 * so we need to donate one ...
2421 */
2422 ipc_port_copy_send_locked(port);
2423
2424 if (bits & MACH_PORT_TYPE_RECEIVE) {
2425 assert(port->ip_receiver_name == name);
2426 assert(port->ip_receiver == space);
2427 assert(IE_BITS_TYPE(bits) ==
2428 MACH_PORT_TYPE_SEND_RECEIVE);
2429
2430 /* ... that we inject manually when the entry stays alive */
2431 ip_reference(port);
2432 } else {
2433 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2434
2435 /* ... that we steal from the entry when it dies */
2436 request = ipc_right_request_cancel_macro(space, port,
2437 name, entry);
2438
2439 ipc_hash_delete(space, ip_to_object(port),
2440 name, entry);
2441 entry->ie_object = IO_NULL;
2442 }
2443
2444 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND);
2445 }
2446 ipc_entry_modified(space, name, entry);
2447
2448 ip_unlock(port);
2449
2450 *objectp = ip_to_object(port);
2451 *sorightp = request;
2452 return KERN_SUCCESS;
2453
2454 invalid_right:
2455 return KERN_INVALID_RIGHT;
2456 }
2457
2458
2459 /*
2460 * Routine: ipc_right_copyin_two
2461 * Purpose:
2462 * Like ipc_right_copyin with two dispositions,
2463 * each of which results in a send or send-once right,
2464 * and deadok = FALSE.
2465 * Conditions:
2466 * The space is write-locked and active.
2467 * The object is returned with two refs/rights.
2468 * Msgt_one refers to the dest_type
2469 * Returns:
2470 * KERN_SUCCESS Acquired an object.
2471 * KERN_INVALID_RIGHT Name doesn't denote correct right(s).
2472 * KERN_INVALID_CAPABILITY Name doesn't denote correct right for msgt_two.
2473 */
2474 kern_return_t
2475 ipc_right_copyin_two(
2476 ipc_space_t space,
2477 mach_port_name_t name,
2478 ipc_entry_t entry,
2479 mach_msg_type_name_t msgt_one,
2480 mach_msg_type_name_t msgt_two,
2481 ipc_object_t *objectp,
2482 ipc_port_t *sorightp,
2483 ipc_port_t *releasep)
2484 {
2485 kern_return_t kr;
2486 int assertcnt = 0;
2487
2488 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one));
2489 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two));
2490
2491 /*
2492 * This is a little tedious to make atomic, because
2493 * there are 25 combinations of valid dispositions.
2494 * However, most are easy.
2495 */
2496
2497 /*
2498 * If either is move-sonce, then there must be an error.
2499 */
2500 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND_ONCE ||
2501 msgt_two == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
2502 return KERN_INVALID_RIGHT;
2503 }
2504
2505 if ((msgt_one == MACH_MSG_TYPE_MAKE_SEND) ||
2506 (msgt_one == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
2507 (msgt_two == MACH_MSG_TYPE_MAKE_SEND) ||
2508 (msgt_two == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
2509 /*
2510 * One of the dispositions needs a receive right.
2511 *
2512 * If the copyin below succeeds, we know the receive
2513 * right is there (because the pre-validation of
2514 * the second disposition already succeeded in our
2515 * caller).
2516 *
2517 * Hence the port is not in danger of dying.
2518 */
2519 ipc_object_t object_two;
2520
2521 kr = ipc_right_copyin(space, name, entry,
2522 msgt_one, IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
2523 objectp, sorightp, releasep,
2524 &assertcnt, 0, NULL);
2525 assert(assertcnt == 0);
2526 if (kr != KERN_SUCCESS) {
2527 return kr;
2528 }
2529
2530 assert(IO_VALID(*objectp));
2531 assert(*sorightp == IP_NULL);
2532 assert(*releasep == IP_NULL);
2533
2534 /*
2535 * Now copyin the second (previously validated)
2536 * disposition. The result can't be a dead port,
2537 * as no valid disposition can make us lose our
2538 * receive right.
2539 */
2540 kr = ipc_right_copyin(space, name, entry,
2541 msgt_two, IPC_RIGHT_COPYIN_FLAGS_NONE,
2542 &object_two, sorightp, releasep,
2543 &assertcnt, 0, NULL);
2544 assert(assertcnt == 0);
2545 assert(kr == KERN_SUCCESS);
2546 assert(*sorightp == IP_NULL);
2547 assert(*releasep == IP_NULL);
2548 assert(object_two == *objectp);
2549 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
2550 } else if ((msgt_one == MACH_MSG_TYPE_MOVE_SEND) &&
2551 (msgt_two == MACH_MSG_TYPE_MOVE_SEND)) {
2552 /*
2553 * This is an easy case. Just use our
2554 * handy-dandy special-purpose copyin call
2555 * to get two send rights for the price of one.
2556 */
2557 kr = ipc_right_copyin_two_move_sends(space, name, entry,
2558 objectp, sorightp,
2559 releasep);
2560 if (kr != KERN_SUCCESS) {
2561 return kr;
2562 }
2563 } else {
2564 mach_msg_type_name_t msgt_name;
2565
2566 /*
2567 * Must be either a single move-send and a
2568 * copy-send, or two copy-send dispositions.
2569 * Use the disposition with the greatest side
2570 * effects for the actual copyin - then just
2571 * duplicate the send right you get back.
2572 */
2573 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND ||
2574 msgt_two == MACH_MSG_TYPE_MOVE_SEND) {
2575 msgt_name = MACH_MSG_TYPE_MOVE_SEND;
2576 } else {
2577 msgt_name = MACH_MSG_TYPE_COPY_SEND;
2578 }
2579
2580 kr = ipc_right_copyin(space, name, entry,
2581 msgt_name, IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND,
2582 objectp, sorightp, releasep,
2583 &assertcnt, 0, NULL);
2584 assert(assertcnt == 0);
2585 if (kr != KERN_SUCCESS) {
2586 return kr;
2587 }
2588
2589 /*
2590 * Copy the right we got back. If it is dead now,
2591 * that's OK. Neither right will be usable to send
2592 * a message anyway.
2593 */
2594 (void)ipc_port_copy_send(ip_object_to_port(*objectp));
2595 }
2596
2597 return KERN_SUCCESS;
2598 }
2599
2600
2601 /*
2602 * Routine: ipc_right_copyout
2603 * Purpose:
2604 * Copyout a capability to a space.
2605 * If successful, consumes a ref for the object.
2606 *
2607 * Always succeeds when given a newly-allocated entry,
2608 * because user-reference overflow isn't a possibility.
2609 *
2610 * If copying out the object would cause the user-reference
2611 * count in the entry to overflow, then the user-reference
2612 * count is left pegged to its maximum value and the copyout
2613 * succeeds anyway.
2614 * Conditions:
2615 * The space is write-locked and active.
2616 * The object is locked and active.
2617 * The object is unlocked; the space isn't.
2618 * Returns:
2619 * KERN_SUCCESS Copied out capability.
2620 */
2621
2622 kern_return_t
2623 ipc_right_copyout(
2624 ipc_space_t space,
2625 mach_port_name_t name,
2626 ipc_entry_t entry,
2627 mach_msg_type_name_t msgt_name,
2628 mach_port_context_t *context,
2629 mach_msg_guard_flags_t *guard_flags,
2630 ipc_object_t object)
2631 {
2632 ipc_entry_bits_t bits;
2633 ipc_port_t port;
2634
2635 bits = entry->ie_bits;
2636
2637 assert(IO_VALID(object));
2638 assert(io_otype(object) == IOT_PORT);
2639 assert(io_active(object));
2640 assert(entry->ie_object == object);
2641
2642 port = ip_object_to_port(object);
2643
2644 switch (msgt_name) {
2645 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2646
2647 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2648 assert(IE_BITS_UREFS(bits) == 0);
2649 assert(port->ip_sorights > 0);
2650
2651 if (port->ip_specialreply) {
2652 ipc_port_adjust_special_reply_port_locked(port,
2653 current_thread()->ith_knote, IPC_PORT_ADJUST_SR_LINK_WORKLOOP, FALSE);
2654 /* port unlocked on return */
2655 } else {
2656 ip_unlock(port);
2657 }
2658
2659 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1); /* set urefs to 1 */
2660 ipc_entry_modified(space, name, entry);
2661 break;
2662
2663 case MACH_MSG_TYPE_PORT_SEND:
2664 assert(port->ip_srights > 0);
2665
2666 if (bits & MACH_PORT_TYPE_SEND) {
2667 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2668
2669 assert(port->ip_srights > 1);
2670 assert(urefs > 0);
2671 assert(urefs <= MACH_PORT_UREFS_MAX);
2672
2673 if (urefs == MACH_PORT_UREFS_MAX) {
2674 /*
2675 * leave urefs pegged to maximum,
2676 * consume send right and ref
2677 */
2678
2679 port->ip_srights--;
2680 ip_unlock(port);
2681 ip_release(port);
2682 return KERN_SUCCESS;
2683 }
2684
2685 /* consume send right and ref */
2686 port->ip_srights--;
2687 ip_unlock(port);
2688 ip_release(port);
2689 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2690 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2691 assert(IE_BITS_UREFS(bits) == 0);
2692
2693 /* transfer send right to entry, consume ref */
2694 ip_unlock(port);
2695 ip_release(port);
2696 } else {
2697 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2698 assert(IE_BITS_UREFS(bits) == 0);
2699
2700 /* transfer send right and ref to entry */
2701 ip_unlock(port);
2702
2703 /* entry is locked holding ref, so can use port */
2704
2705 ipc_hash_insert(space, ip_to_object(port), name, entry);
2706 }
2707
2708 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; /* increment urefs */
2709 ipc_entry_modified(space, name, entry);
2710 break;
2711
2712 case MACH_MSG_TYPE_PORT_RECEIVE: {
2713 ipc_port_t dest;
2714 #if IMPORTANCE_INHERITANCE
2715 natural_t assertcnt = port->ip_impcount;
2716 #endif /* IMPORTANCE_INHERITANCE */
2717
2718 assert(port->ip_mscount == 0);
2719 assert(port->ip_receiver_name == MACH_PORT_NULL);
2720
2721 imq_lock(&port->ip_messages);
2722 dest = port->ip_destination;
2723
2724 port->ip_receiver_name = name;
2725 port->ip_receiver = space;
2726
2727 struct knote *kn = current_thread()->ith_knote;
2728
2729 if ((guard_flags != NULL) && ((*guard_flags & MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE) != 0)) {
2730 assert(port->ip_immovable_receive == 0);
2731 port->ip_guarded = 1;
2732 port->ip_strict_guard = 0;
2733 /* pseudo receive shouldn't set the receive right as immovable in the sender's space */
2734 if (kn != ITH_KNOTE_PSEUDO) {
2735 port->ip_immovable_receive = 1;
2736 }
2737 port->ip_context = current_thread()->ith_msg_addr;
2738 *context = port->ip_context;
2739 *guard_flags = *guard_flags & ~MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND;
2740 }
2741
2742 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2743 if (bits & MACH_PORT_TYPE_SEND) {
2744 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2745 assert(IE_BITS_UREFS(bits) > 0);
2746 assert(port->ip_srights > 0);
2747 } else {
2748 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2749 assert(IE_BITS_UREFS(bits) == 0);
2750 }
2751
2752 boolean_t sync_bootstrap_checkin = FALSE;
2753 if (kn != ITH_KNOTE_PSEUDO && port->ip_sync_bootstrap_checkin) {
2754 sync_bootstrap_checkin = TRUE;
2755 }
2756 if (!ITH_KNOTE_VALID(kn, MACH_MSG_TYPE_PORT_RECEIVE)) {
2757 kn = NULL;
2758 }
2759 ipc_port_adjust_port_locked(port, kn, sync_bootstrap_checkin);
2760 /* port & message queue are unlocked */
2761
2762 if (bits & MACH_PORT_TYPE_SEND) {
2763 ip_release(port);
2764
2765 /* entry is locked holding ref, so can use port */
2766 ipc_hash_delete(space, ip_to_object(port), name, entry);
2767 }
2768 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2769 ipc_entry_modified(space, name, entry);
2770
2771 if (dest != IP_NULL) {
2772 #if IMPORTANCE_INHERITANCE
2773 /*
2774 * Deduct the assertion counts we contributed to
2775 * the old destination port. They've already
2776 * been reflected into the task as a result of
2777 * getting enqueued.
2778 */
2779 ip_lock(dest);
2780 ipc_port_impcount_delta(dest, 0 - assertcnt, IP_NULL);
2781 ip_unlock(dest);
2782 #endif /* IMPORTANCE_INHERITANCE */
2783
2784 /* Drop turnstile ref on dest */
2785 ipc_port_send_turnstile_complete(dest);
2786 ip_release(dest);
2787 }
2788 break;
2789 }
2790
2791 default:
2792 panic("ipc_right_copyout: strange rights");
2793 }
2794 return KERN_SUCCESS;
2795 }