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