]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_right.c
xnu-4903.270.47.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 /*
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 = (ipc_port_t) 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 == (ipc_port_t) entry->ie_object);
225
226 *namep = name;
227 *entryp = entry;
228 return TRUE;
229 }
230
231 if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
232 assert((entry = *entryp) != IE_NULL);
233 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
234 assert(port == (ipc_port_t) 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 = (ipc_port_t) 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 assert(ip_active(port));
452 assert(port == (ipc_port_t) 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 == (ipc_port_t) 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, (ipc_object_t)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 = (ipc_pset_t) 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 = (ipc_port_t) 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 ip_unlock(port);
677
678 ipc_notify_send_once(port); /* consumes our ref */
679 } else {
680 assert(port->ip_receiver != space);
681
682 ip_unlock(port);
683 ip_release(port);
684 }
685
686 if (nsrequest != IP_NULL) {
687 ipc_notify_no_senders(nsrequest, mscount);
688 }
689
690 if (request != IP_NULL) {
691 ipc_notify_port_deleted(request, name);
692 }
693 break;
694 }
695
696 default:
697 panic("ipc_right_terminate: strange type - 0x%x", type);
698 }
699 }
700
701 /*
702 * Routine: ipc_right_destroy
703 * Purpose:
704 * Destroys an entry in a space.
705 * Conditions:
706 * The space is write-locked (returns unlocked).
707 * The space must be active.
708 * Returns:
709 * KERN_SUCCESS The entry was destroyed.
710 */
711
712 kern_return_t
713 ipc_right_destroy(
714 ipc_space_t space,
715 mach_port_name_t name,
716 ipc_entry_t entry,
717 boolean_t check_guard,
718 uint64_t guard)
719 {
720 ipc_entry_bits_t bits;
721 mach_port_type_t type;
722
723 bits = entry->ie_bits;
724 entry->ie_bits &= ~IE_BITS_TYPE_MASK;
725 type = IE_BITS_TYPE(bits);
726
727 assert(is_active(space));
728
729 switch (type) {
730 case MACH_PORT_TYPE_DEAD_NAME:
731 assert(entry->ie_request == IE_REQ_NONE);
732 assert(entry->ie_object == IO_NULL);
733
734 ipc_entry_dealloc(space, name, entry);
735 is_write_unlock(space);
736 break;
737
738 case MACH_PORT_TYPE_PORT_SET: {
739 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
740
741 assert(entry->ie_request == IE_REQ_NONE);
742 assert(pset != IPS_NULL);
743
744 entry->ie_object = IO_NULL;
745 ipc_entry_dealloc(space, name, entry);
746
747 ips_lock(pset);
748 is_write_unlock(space);
749
750 assert(ips_active(pset));
751 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
752 break;
753 }
754
755 case MACH_PORT_TYPE_SEND:
756 case MACH_PORT_TYPE_RECEIVE:
757 case MACH_PORT_TYPE_SEND_RECEIVE:
758 case MACH_PORT_TYPE_SEND_ONCE: {
759 ipc_port_t port = (ipc_port_t) entry->ie_object;
760 ipc_port_t nsrequest = IP_NULL;
761 mach_port_mscount_t mscount = 0;
762 ipc_port_t request;
763
764 assert(port != IP_NULL);
765
766 if (type == MACH_PORT_TYPE_SEND) {
767 ipc_hash_delete(space, (ipc_object_t) port,
768 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 assert(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 ip_unlock(port);
823
824 ipc_notify_send_once(port); /* consumes our ref */
825 } else {
826 assert(port->ip_receiver != space);
827
828 ip_unlock(port);
829 ip_release(port);
830 }
831
832 if (nsrequest != IP_NULL) {
833 ipc_notify_no_senders(nsrequest, mscount);
834 }
835
836 if (request != IP_NULL) {
837 ipc_notify_port_deleted(request, name);
838 }
839
840
841 break;
842 }
843
844 default:
845 panic("ipc_right_destroy: strange type");
846 }
847
848 return KERN_SUCCESS;
849 }
850
851 /*
852 * Routine: ipc_right_dealloc
853 * Purpose:
854 * Releases a send/send-once/dead-name/port_set user ref.
855 * Like ipc_right_delta with a delta of -1,
856 * but looks at the entry to determine the right.
857 * Conditions:
858 * The space is write-locked, and is unlocked upon return.
859 * The space must be active.
860 * Returns:
861 * KERN_SUCCESS A user ref was released.
862 * KERN_INVALID_RIGHT Entry has wrong type.
863 */
864
865 kern_return_t
866 ipc_right_dealloc(
867 ipc_space_t space,
868 mach_port_name_t name,
869 ipc_entry_t entry)
870 {
871 ipc_port_t port = IP_NULL;
872 ipc_entry_bits_t bits;
873 mach_port_type_t type;
874
875 bits = entry->ie_bits;
876 type = IE_BITS_TYPE(bits);
877
878
879 assert(is_active(space));
880
881 switch (type) {
882 case MACH_PORT_TYPE_PORT_SET: {
883 ipc_pset_t pset;
884
885 assert(IE_BITS_UREFS(bits) == 0);
886 assert(entry->ie_request == IE_REQ_NONE);
887
888 pset = (ipc_pset_t) entry->ie_object;
889 assert(pset != IPS_NULL);
890
891 entry->ie_object = IO_NULL;
892 ipc_entry_dealloc(space, name, entry);
893
894 ips_lock(pset);
895 assert(ips_active(pset));
896 is_write_unlock(space);
897
898 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
899 break;
900 }
901
902 case MACH_PORT_TYPE_DEAD_NAME: {
903 dead_name:
904
905 assert(IE_BITS_UREFS(bits) > 0);
906 assert(entry->ie_request == IE_REQ_NONE);
907 assert(entry->ie_object == IO_NULL);
908
909 if (IE_BITS_UREFS(bits) == 1) {
910 ipc_entry_dealloc(space, name, entry);
911 } else {
912 /* if urefs are pegged due to overflow, leave them pegged */
913 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
914 entry->ie_bits = bits - 1; /* decrement urefs */
915 }
916 ipc_entry_modified(space, name, entry);
917 }
918 is_write_unlock(space);
919
920 /* release any port that got converted to dead name below */
921 if (port != IP_NULL) {
922 ip_release(port);
923 }
924 break;
925 }
926
927 case MACH_PORT_TYPE_SEND_ONCE: {
928 ipc_port_t request;
929
930 assert(IE_BITS_UREFS(bits) == 1);
931
932 port = (ipc_port_t) entry->ie_object;
933 assert(port != IP_NULL);
934
935 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
936 bits = entry->ie_bits;
937 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
938 goto dead_name; /* it will release port */
939 }
940 /* port is locked and active */
941
942 assert(port->ip_sorights > 0);
943
944 request = ipc_right_request_cancel_macro(space, port, name, entry);
945 ip_unlock(port);
946
947 entry->ie_object = IO_NULL;
948 ipc_entry_dealloc(space, name, entry);
949
950 is_write_unlock(space);
951
952 ipc_notify_send_once(port);
953
954 if (request != IP_NULL) {
955 ipc_notify_port_deleted(request, name);
956 }
957 break;
958 }
959
960 case MACH_PORT_TYPE_SEND: {
961 ipc_port_t request = IP_NULL;
962 ipc_port_t nsrequest = IP_NULL;
963 mach_port_mscount_t mscount = 0;
964
965
966 assert(IE_BITS_UREFS(bits) > 0);
967
968 port = (ipc_port_t) entry->ie_object;
969 assert(port != IP_NULL);
970
971 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
972 bits = entry->ie_bits;
973 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
974 goto dead_name; /* it will release port */
975 }
976 /* port is locked and active */
977
978 assert(port->ip_srights > 0);
979
980 if (IE_BITS_UREFS(bits) == 1) {
981 if (--port->ip_srights == 0) {
982 nsrequest = port->ip_nsrequest;
983 if (nsrequest != IP_NULL) {
984 port->ip_nsrequest = IP_NULL;
985 mscount = port->ip_mscount;
986 }
987 }
988
989 request = ipc_right_request_cancel_macro(space, port,
990 name, entry);
991 ipc_hash_delete(space, (ipc_object_t) port,
992 name, entry);
993
994 ip_unlock(port);
995 entry->ie_object = IO_NULL;
996 ipc_entry_dealloc(space, name, entry);
997 is_write_unlock(space);
998 ip_release(port);
999 } else {
1000 ip_unlock(port);
1001 /* if urefs are pegged due to overflow, leave them pegged */
1002 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1003 entry->ie_bits = bits - 1; /* decrement urefs */
1004 }
1005 ipc_entry_modified(space, name, entry);
1006 is_write_unlock(space);
1007 }
1008
1009 if (nsrequest != IP_NULL) {
1010 ipc_notify_no_senders(nsrequest, mscount);
1011 }
1012
1013 if (request != IP_NULL) {
1014 ipc_notify_port_deleted(request, name);
1015 }
1016 break;
1017 }
1018
1019 case MACH_PORT_TYPE_SEND_RECEIVE: {
1020 ipc_port_t nsrequest = IP_NULL;
1021 mach_port_mscount_t mscount = 0;
1022
1023 assert(IE_BITS_UREFS(bits) > 0);
1024
1025 port = (ipc_port_t) entry->ie_object;
1026 assert(port != IP_NULL);
1027
1028 ip_lock(port);
1029 assert(ip_active(port));
1030 assert(port->ip_receiver_name == name);
1031 assert(port->ip_receiver == space);
1032 assert(port->ip_srights > 0);
1033
1034 if (IE_BITS_UREFS(bits) == 1) {
1035 if (--port->ip_srights == 0) {
1036 nsrequest = port->ip_nsrequest;
1037 if (nsrequest != IP_NULL) {
1038 port->ip_nsrequest = IP_NULL;
1039 mscount = port->ip_mscount;
1040 }
1041 }
1042
1043 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK |
1044 MACH_PORT_TYPE_SEND);
1045 } else {
1046 /* if urefs are pegged due to overflow, leave them pegged */
1047 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1048 entry->ie_bits = bits - 1; /* decrement urefs */
1049 }
1050 }
1051 ip_unlock(port);
1052
1053 ipc_entry_modified(space, name, entry);
1054 is_write_unlock(space);
1055
1056 if (nsrequest != IP_NULL) {
1057 ipc_notify_no_senders(nsrequest, mscount);
1058 }
1059 break;
1060 }
1061
1062 default:
1063 is_write_unlock(space);
1064 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1065 return KERN_INVALID_RIGHT;
1066 }
1067
1068 return KERN_SUCCESS;
1069 }
1070
1071 /*
1072 * Routine: ipc_right_delta
1073 * Purpose:
1074 * Modifies the user-reference count for a right.
1075 * May deallocate the right, if the count goes to zero.
1076 * Conditions:
1077 * The space is write-locked, and is unlocked upon return.
1078 * The space must be active.
1079 * Returns:
1080 * KERN_SUCCESS Count was modified.
1081 * KERN_INVALID_RIGHT Entry has wrong type.
1082 * KERN_INVALID_VALUE Bad delta for the right.
1083 */
1084
1085 kern_return_t
1086 ipc_right_delta(
1087 ipc_space_t space,
1088 mach_port_name_t name,
1089 ipc_entry_t entry,
1090 mach_port_right_t right,
1091 mach_port_delta_t delta)
1092 {
1093 ipc_port_t port = IP_NULL;
1094 ipc_entry_bits_t bits;
1095
1096 bits = entry->ie_bits;
1097
1098 /*
1099 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1100 * switch below. It is used to keep track of those cases (in DIPC)
1101 * where we have postponed the dropping of a port reference. Since
1102 * the dropping of the reference could cause the port to disappear
1103 * we postpone doing so when we are holding the space lock.
1104 */
1105
1106 assert(is_active(space));
1107 assert(right < MACH_PORT_RIGHT_NUMBER);
1108
1109 /* Rights-specific restrictions and operations. */
1110
1111 switch (right) {
1112 case MACH_PORT_RIGHT_PORT_SET: {
1113 ipc_pset_t pset;
1114
1115 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1116 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1117 goto invalid_right;
1118 }
1119
1120 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
1121 assert(IE_BITS_UREFS(bits) == 0);
1122 assert(entry->ie_request == IE_REQ_NONE);
1123
1124 if (delta == 0) {
1125 goto success;
1126 }
1127
1128 if (delta != -1) {
1129 goto invalid_value;
1130 }
1131
1132 pset = (ipc_pset_t) entry->ie_object;
1133 assert(pset != IPS_NULL);
1134
1135 entry->ie_object = IO_NULL;
1136 ipc_entry_dealloc(space, name, entry);
1137
1138 ips_lock(pset);
1139 assert(ips_active(pset));
1140 is_write_unlock(space);
1141
1142 ipc_pset_destroy(space, pset); /* consumes ref, unlocks */
1143 break;
1144 }
1145
1146 case MACH_PORT_RIGHT_RECEIVE: {
1147 ipc_port_t request = IP_NULL;
1148
1149 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1150 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1151 goto invalid_right;
1152 }
1153
1154 if (delta == 0) {
1155 goto success;
1156 }
1157
1158 if (delta != -1) {
1159 goto invalid_value;
1160 }
1161
1162 port = (ipc_port_t) entry->ie_object;
1163 assert(port != IP_NULL);
1164
1165 /*
1166 * The port lock is needed for ipc_right_dncancel;
1167 * otherwise, we wouldn't have to take the lock
1168 * until just before dropping the space lock.
1169 */
1170
1171 ip_lock(port);
1172 assert(ip_active(port));
1173 assert(port->ip_receiver_name == name);
1174 assert(port->ip_receiver == space);
1175
1176 /* Mach Port Guard Checking */
1177 if (port->ip_guarded) {
1178 uint64_t portguard = port->ip_context;
1179 ip_unlock(port);
1180 is_write_unlock(space);
1181 /* Raise mach port guard exception */
1182 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_MOD_REFS);
1183 goto guard_failure;
1184 }
1185
1186 if (bits & MACH_PORT_TYPE_SEND) {
1187 assert(IE_BITS_TYPE(bits) ==
1188 MACH_PORT_TYPE_SEND_RECEIVE);
1189 assert(IE_BITS_UREFS(bits) > 0);
1190 assert(port->ip_srights > 0);
1191
1192 if (port->ip_pdrequest != NULL) {
1193 /*
1194 * Since another task has requested a
1195 * destroy notification for this port, it
1196 * isn't actually being destroyed - the receive
1197 * right is just being moved to another task.
1198 * Since we still have one or more send rights,
1199 * we need to record the loss of the receive
1200 * right and enter the remaining send right
1201 * into the hash table.
1202 */
1203 ipc_entry_modified(space, name, entry);
1204 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1205 ipc_hash_insert(space, (ipc_object_t) port,
1206 name, entry);
1207 ip_reference(port);
1208 } else {
1209 /*
1210 * The remaining send right turns into a
1211 * dead name. Notice we don't decrement
1212 * ip_srights, generate a no-senders notif,
1213 * or use ipc_right_dncancel, because the
1214 * port is destroyed "first".
1215 */
1216 bits &= ~IE_BITS_TYPE_MASK;
1217 bits |= MACH_PORT_TYPE_DEAD_NAME;
1218 if (entry->ie_request) {
1219 entry->ie_request = IE_REQ_NONE;
1220 /* if urefs are pegged due to overflow, leave them pegged */
1221 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1222 bits++; /* increment urefs */
1223 }
1224 }
1225 entry->ie_bits = bits;
1226 entry->ie_object = IO_NULL;
1227 ipc_entry_modified(space, name, entry);
1228 }
1229 } else {
1230 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1231 assert(IE_BITS_UREFS(bits) == 0);
1232
1233 request = ipc_right_request_cancel_macro(space, port,
1234 name, entry);
1235 entry->ie_object = IO_NULL;
1236 ipc_entry_dealloc(space, name, entry);
1237 }
1238 is_write_unlock(space);
1239
1240 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
1241
1242 if (request != IP_NULL) {
1243 ipc_notify_port_deleted(request, name);
1244 }
1245 break;
1246 }
1247
1248 case MACH_PORT_RIGHT_SEND_ONCE: {
1249 ipc_port_t request;
1250
1251 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1252 goto invalid_right;
1253 }
1254
1255 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1256 assert(IE_BITS_UREFS(bits) == 1);
1257
1258 port = (ipc_port_t) entry->ie_object;
1259 assert(port != IP_NULL);
1260
1261 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1262 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1263 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1264 goto invalid_right;
1265 }
1266 /* port is locked and active */
1267
1268 assert(port->ip_sorights > 0);
1269
1270 if ((delta > 0) || (delta < -1)) {
1271 ip_unlock(port);
1272 goto invalid_value;
1273 }
1274
1275 if (delta == 0) {
1276 ip_unlock(port);
1277 goto success;
1278 }
1279
1280 request = ipc_right_request_cancel_macro(space, port, name, entry);
1281 ip_unlock(port);
1282
1283 entry->ie_object = IO_NULL;
1284 ipc_entry_dealloc(space, name, entry);
1285
1286 is_write_unlock(space);
1287
1288 ipc_notify_send_once(port);
1289
1290 if (request != IP_NULL) {
1291 ipc_notify_port_deleted(request, name);
1292 }
1293 break;
1294 }
1295
1296 case MACH_PORT_RIGHT_DEAD_NAME: {
1297 ipc_port_t relport = IP_NULL;
1298 mach_port_urefs_t urefs;
1299
1300 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1301 port = (ipc_port_t) entry->ie_object;
1302 assert(port != IP_NULL);
1303
1304 if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1305 /* port is locked and active */
1306 ip_unlock(port);
1307 port = IP_NULL;
1308 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1309 goto invalid_right;
1310 }
1311 bits = entry->ie_bits;
1312 relport = port;
1313 port = IP_NULL;
1314 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0) {
1315 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1316 goto invalid_right;
1317 }
1318
1319 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1320 assert(IE_BITS_UREFS(bits) > 0);
1321 assert(entry->ie_object == IO_NULL);
1322 assert(entry->ie_request == IE_REQ_NONE);
1323
1324 if (delta > ((mach_port_delta_t)MACH_PORT_UREFS_MAX) ||
1325 delta < (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1326 goto invalid_value;
1327 }
1328
1329 urefs = IE_BITS_UREFS(bits);
1330
1331 if (urefs == MACH_PORT_UREFS_MAX) {
1332 /*
1333 * urefs are pegged due to an overflow
1334 * only a delta removing all refs at once can change it
1335 */
1336
1337 if (delta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1338 delta = 0;
1339 }
1340 } else {
1341 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1342 goto invalid_value;
1343 }
1344 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) {
1345 /* leave urefs pegged to maximum if it overflowed */
1346 delta = MACH_PORT_UREFS_MAX - urefs;
1347 }
1348 }
1349
1350 if ((urefs + delta) == 0) {
1351 ipc_entry_dealloc(space, name, entry);
1352 } else if (delta != 0) {
1353 entry->ie_bits = bits + delta;
1354 ipc_entry_modified(space, name, entry);
1355 }
1356
1357 is_write_unlock(space);
1358
1359 if (relport != IP_NULL) {
1360 ip_release(relport);
1361 }
1362
1363 break;
1364 }
1365
1366 case MACH_PORT_RIGHT_SEND: {
1367 mach_port_urefs_t urefs;
1368 ipc_port_t request = IP_NULL;
1369 ipc_port_t nsrequest = IP_NULL;
1370 ipc_port_t port_to_release = IP_NULL;
1371 mach_port_mscount_t mscount = 0;
1372
1373 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1374 /* invalid right exception only when not live/dead confusion */
1375 if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0) {
1376 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1377 }
1378 goto invalid_right;
1379 }
1380
1381 /* maximum urefs for send is MACH_PORT_UREFS_MAX */
1382
1383 port = (ipc_port_t) entry->ie_object;
1384 assert(port != IP_NULL);
1385
1386 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1387 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1388 goto invalid_right;
1389 }
1390 /* port is locked and active */
1391
1392 assert(port->ip_srights > 0);
1393
1394 if (delta > ((mach_port_delta_t)MACH_PORT_UREFS_MAX) ||
1395 delta < (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1396 ip_unlock(port);
1397 goto invalid_value;
1398 }
1399
1400 urefs = IE_BITS_UREFS(bits);
1401
1402 if (urefs == MACH_PORT_UREFS_MAX) {
1403 /*
1404 * urefs are pegged due to an overflow
1405 * only a delta removing all refs at once can change it
1406 */
1407
1408 if (delta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1409 delta = 0;
1410 }
1411 } else {
1412 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1413 ip_unlock(port);
1414 goto invalid_value;
1415 }
1416 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) {
1417 /* leave urefs pegged to maximum if it overflowed */
1418 delta = MACH_PORT_UREFS_MAX - urefs;
1419 }
1420 }
1421
1422 if ((urefs + delta) == 0) {
1423 if (--port->ip_srights == 0) {
1424 nsrequest = port->ip_nsrequest;
1425 if (nsrequest != IP_NULL) {
1426 port->ip_nsrequest = IP_NULL;
1427 mscount = port->ip_mscount;
1428 }
1429 }
1430
1431 if (bits & MACH_PORT_TYPE_RECEIVE) {
1432 assert(port->ip_receiver_name == name);
1433 assert(port->ip_receiver == space);
1434 ip_unlock(port);
1435 assert(IE_BITS_TYPE(bits) ==
1436 MACH_PORT_TYPE_SEND_RECEIVE);
1437
1438 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK |
1439 MACH_PORT_TYPE_SEND);
1440 ipc_entry_modified(space, name, entry);
1441 } else {
1442 assert(IE_BITS_TYPE(bits) ==
1443 MACH_PORT_TYPE_SEND);
1444
1445 request = ipc_right_request_cancel_macro(space, port,
1446 name, entry);
1447 ipc_hash_delete(space, (ipc_object_t) port,
1448 name, entry);
1449
1450 ip_unlock(port);
1451 port_to_release = port;
1452
1453 entry->ie_object = IO_NULL;
1454 ipc_entry_dealloc(space, name, entry);
1455 }
1456 } else if (delta != 0) {
1457 ip_unlock(port);
1458 entry->ie_bits = bits + delta;
1459 ipc_entry_modified(space, name, entry);
1460 } else {
1461 ip_unlock(port);
1462 }
1463
1464 is_write_unlock(space);
1465
1466 if (port_to_release != IP_NULL) {
1467 ip_release(port_to_release);
1468 }
1469
1470 if (nsrequest != IP_NULL) {
1471 ipc_notify_no_senders(nsrequest, mscount);
1472 }
1473
1474 if (request != IP_NULL) {
1475 ipc_notify_port_deleted(request, name);
1476 }
1477 break;
1478 }
1479
1480 case MACH_PORT_RIGHT_LABELH:
1481 goto invalid_right;
1482
1483 default:
1484 panic("ipc_right_delta: strange right %d for 0x%x (%p) in space:%p",
1485 right, name, (void *)entry, (void *)space);
1486 }
1487
1488 return KERN_SUCCESS;
1489
1490 success:
1491 is_write_unlock(space);
1492 return KERN_SUCCESS;
1493
1494 invalid_right:
1495 is_write_unlock(space);
1496 if (port != IP_NULL) {
1497 ip_release(port);
1498 }
1499 return KERN_INVALID_RIGHT;
1500
1501 invalid_value:
1502 is_write_unlock(space);
1503 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
1504 return KERN_INVALID_VALUE;
1505
1506 guard_failure:
1507 return KERN_INVALID_RIGHT;
1508 }
1509
1510 /*
1511 * Routine: ipc_right_destruct
1512 * Purpose:
1513 * Deallocates the receive right and modifies the
1514 * user-reference count for the send rights as requested.
1515 * Conditions:
1516 * The space is write-locked, and is unlocked upon return.
1517 * The space must be active.
1518 * Returns:
1519 * KERN_SUCCESS Count was modified.
1520 * KERN_INVALID_RIGHT Entry has wrong type.
1521 * KERN_INVALID_VALUE Bad delta for the right.
1522 */
1523
1524 kern_return_t
1525 ipc_right_destruct(
1526 ipc_space_t space,
1527 mach_port_name_t name,
1528 ipc_entry_t entry,
1529 mach_port_delta_t srdelta,
1530 uint64_t guard)
1531 {
1532 ipc_port_t port = IP_NULL;
1533 ipc_entry_bits_t bits;
1534
1535 mach_port_urefs_t urefs;
1536 ipc_port_t request = IP_NULL;
1537 ipc_port_t nsrequest = IP_NULL;
1538 mach_port_mscount_t mscount = 0;
1539
1540 bits = entry->ie_bits;
1541
1542 assert(is_active(space));
1543
1544 if (((bits & MACH_PORT_TYPE_RECEIVE) == 0) ||
1545 (srdelta && ((bits & MACH_PORT_TYPE_SEND) == 0))) {
1546 is_write_unlock(space);
1547 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_RIGHT);
1548 return KERN_INVALID_RIGHT;
1549 }
1550
1551 if (srdelta > 0) {
1552 goto invalid_value;
1553 }
1554
1555 port = (ipc_port_t) entry->ie_object;
1556 assert(port != IP_NULL);
1557
1558 ip_lock(port);
1559 assert(ip_active(port));
1560 assert(port->ip_receiver_name == name);
1561 assert(port->ip_receiver == space);
1562
1563 /* Mach Port Guard Checking */
1564 if (port->ip_guarded && (guard != port->ip_context)) {
1565 uint64_t portguard = port->ip_context;
1566 ip_unlock(port);
1567 is_write_unlock(space);
1568 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
1569 return KERN_INVALID_ARGUMENT;
1570 }
1571
1572 /*
1573 * First reduce the send rights as requested and
1574 * adjust the entry->ie_bits accordingly. The
1575 * ipc_entry_modified() call is made once the receive
1576 * right is destroyed too.
1577 */
1578
1579 if (srdelta) {
1580 assert(port->ip_srights > 0);
1581
1582 urefs = IE_BITS_UREFS(bits);
1583
1584 /*
1585 * Since we made sure that srdelta is negative,
1586 * the check for urefs overflow is not required.
1587 */
1588 if (MACH_PORT_UREFS_UNDERFLOW(urefs, srdelta)) {
1589 ip_unlock(port);
1590 goto invalid_value;
1591 }
1592
1593 if (urefs == MACH_PORT_UREFS_MAX) {
1594 /*
1595 * urefs are pegged due to an overflow
1596 * only a delta removing all refs at once can change it
1597 */
1598 if (srdelta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1599 srdelta = 0;
1600 }
1601 }
1602
1603 if ((urefs + srdelta) == 0) {
1604 if (--port->ip_srights == 0) {
1605 nsrequest = port->ip_nsrequest;
1606 if (nsrequest != IP_NULL) {
1607 port->ip_nsrequest = IP_NULL;
1608 mscount = port->ip_mscount;
1609 }
1610 }
1611 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_RECEIVE);
1612 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK |
1613 MACH_PORT_TYPE_SEND);
1614 } else {
1615 entry->ie_bits = bits + srdelta;
1616 }
1617 }
1618
1619 /*
1620 * Now destroy the receive right. Update space and
1621 * entry accordingly.
1622 */
1623
1624 bits = entry->ie_bits;
1625 if (bits & MACH_PORT_TYPE_SEND) {
1626 assert(IE_BITS_UREFS(bits) > 0);
1627 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
1628
1629 if (port->ip_pdrequest != NULL) {
1630 /*
1631 * Since another task has requested a
1632 * destroy notification for this port, it
1633 * isn't actually being destroyed - the receive
1634 * right is just being moved to another task.
1635 * Since we still have one or more send rights,
1636 * we need to record the loss of the receive
1637 * right and enter the remaining send right
1638 * into the hash table.
1639 */
1640 ipc_entry_modified(space, name, entry);
1641 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1642 ipc_hash_insert(space, (ipc_object_t) port,
1643 name, entry);
1644 ip_reference(port);
1645 } else {
1646 /*
1647 * The remaining send right turns into a
1648 * dead name. Notice we don't decrement
1649 * ip_srights, generate a no-senders notif,
1650 * or use ipc_right_dncancel, because the
1651 * port is destroyed "first".
1652 */
1653 bits &= ~IE_BITS_TYPE_MASK;
1654 bits |= MACH_PORT_TYPE_DEAD_NAME;
1655 if (entry->ie_request) {
1656 entry->ie_request = IE_REQ_NONE;
1657 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
1658 bits++; /* increment urefs */
1659 }
1660 }
1661 entry->ie_bits = bits;
1662 entry->ie_object = IO_NULL;
1663 ipc_entry_modified(space, name, entry);
1664 }
1665 } else {
1666 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1667 assert(IE_BITS_UREFS(bits) == 0);
1668 request = ipc_right_request_cancel_macro(space, port,
1669 name, entry);
1670 entry->ie_object = IO_NULL;
1671 ipc_entry_dealloc(space, name, entry);
1672 }
1673
1674 /* Unlock space */
1675 is_write_unlock(space);
1676
1677 if (nsrequest != IP_NULL) {
1678 ipc_notify_no_senders(nsrequest, mscount);
1679 }
1680
1681 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
1682
1683 if (request != IP_NULL) {
1684 ipc_notify_port_deleted(request, name);
1685 }
1686
1687 return KERN_SUCCESS;
1688
1689 invalid_value:
1690 is_write_unlock(space);
1691 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_VALUE);
1692 return KERN_INVALID_VALUE;
1693 }
1694
1695
1696 /*
1697 * Routine: ipc_right_info
1698 * Purpose:
1699 * Retrieves information about the right.
1700 * Conditions:
1701 * The space is active and write-locked.
1702 * The space is unlocked upon return.
1703 * Returns:
1704 * KERN_SUCCESS Retrieved info
1705 */
1706
1707 kern_return_t
1708 ipc_right_info(
1709 ipc_space_t space,
1710 mach_port_name_t name,
1711 ipc_entry_t entry,
1712 mach_port_type_t *typep,
1713 mach_port_urefs_t *urefsp)
1714 {
1715 ipc_port_t port;
1716 ipc_entry_bits_t bits;
1717 mach_port_type_t type = 0;
1718 ipc_port_request_index_t request;
1719
1720 bits = entry->ie_bits;
1721 request = entry->ie_request;
1722 port = (ipc_port_t) entry->ie_object;
1723
1724 if (bits & MACH_PORT_TYPE_RECEIVE) {
1725 assert(IP_VALID(port));
1726
1727 if (request != IE_REQ_NONE) {
1728 ip_lock(port);
1729 assert(ip_active(port));
1730 type |= ipc_port_request_type(port, name, request);
1731 ip_unlock(port);
1732 }
1733 is_write_unlock(space);
1734 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1735 /*
1736 * validate port is still alive - if so, get request
1737 * types while we still have it locked. Otherwise,
1738 * recapture the (now dead) bits.
1739 */
1740 if (!ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
1741 if (request != IE_REQ_NONE) {
1742 type |= ipc_port_request_type(port, name, request);
1743 }
1744 ip_unlock(port);
1745 is_write_unlock(space);
1746 } else {
1747 bits = entry->ie_bits;
1748 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1749 is_write_unlock(space);
1750 ip_release(port);
1751 }
1752 } else {
1753 is_write_unlock(space);
1754 }
1755
1756 type |= IE_BITS_TYPE(bits);
1757
1758 *typep = type;
1759 *urefsp = IE_BITS_UREFS(bits);
1760 return KERN_SUCCESS;
1761 }
1762
1763 /*
1764 * Routine: ipc_right_copyin_check
1765 * Purpose:
1766 * Check if a subsequent ipc_right_copyin would succeed.
1767 * Conditions:
1768 * The space is locked (read or write) and active.
1769 */
1770
1771 boolean_t
1772 ipc_right_copyin_check(
1773 __assert_only ipc_space_t space,
1774 __unused mach_port_name_t name,
1775 ipc_entry_t entry,
1776 mach_msg_type_name_t msgt_name)
1777 {
1778 ipc_entry_bits_t bits;
1779 ipc_port_t port;
1780
1781 bits = entry->ie_bits;
1782 assert(is_active(space));
1783
1784 switch (msgt_name) {
1785 case MACH_MSG_TYPE_MAKE_SEND:
1786 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1787 return FALSE;
1788 }
1789 break;
1790
1791 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1792 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1793 return FALSE;
1794 }
1795 break;
1796
1797 case MACH_MSG_TYPE_MOVE_RECEIVE:
1798 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1799 return FALSE;
1800 }
1801 if (io_kotype(entry->ie_object) != IKOT_NONE) {
1802 return FALSE;
1803 }
1804 port = (ipc_port_t) entry->ie_object;
1805 if (port->ip_specialreply) {
1806 return FALSE;
1807 }
1808 break;
1809
1810 case MACH_MSG_TYPE_COPY_SEND:
1811 case MACH_MSG_TYPE_MOVE_SEND:
1812 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1813 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
1814 break;
1815 }
1816
1817 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
1818 return FALSE;
1819 }
1820
1821 port = (ipc_port_t) entry->ie_object;
1822 assert(port != IP_NULL);
1823
1824 /*
1825 * active status peek to avoid checks that will be skipped
1826 * on copyin for dead ports. Lock not held, so will not be
1827 * atomic (but once dead, there's no going back).
1828 */
1829 if (!ip_active(port)) {
1830 break;
1831 }
1832
1833 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1834 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1835 return FALSE;
1836 }
1837 } else {
1838 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1839 return FALSE;
1840 }
1841 }
1842
1843 break;
1844 }
1845
1846 default:
1847 panic("ipc_right_copyin_check: strange rights");
1848 }
1849
1850 return TRUE;
1851 }
1852
1853 /*
1854 * Routine: ipc_right_copyin
1855 * Purpose:
1856 * Copyin a capability from a space.
1857 * If successful, the caller gets a ref
1858 * for the resulting object, unless it is IO_DEAD,
1859 * and possibly a send-once right which should
1860 * be used in a port-deleted notification.
1861 *
1862 * If deadok is not TRUE, the copyin operation
1863 * will fail instead of producing IO_DEAD.
1864 *
1865 * The entry is never deallocated (except
1866 * when KERN_INVALID_NAME), so the caller
1867 * should deallocate the entry if its type
1868 * is MACH_PORT_TYPE_NONE.
1869 * Conditions:
1870 * The space is write-locked and active.
1871 * Returns:
1872 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1873 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1874 */
1875
1876 kern_return_t
1877 ipc_right_copyin(
1878 ipc_space_t space,
1879 mach_port_name_t name,
1880 ipc_entry_t entry,
1881 mach_msg_type_name_t msgt_name,
1882 ipc_right_copyin_flags_t flags,
1883 ipc_object_t *objectp,
1884 ipc_port_t *sorightp,
1885 ipc_port_t *releasep,
1886 int *assertcntp)
1887 {
1888 ipc_entry_bits_t bits;
1889 ipc_port_t port;
1890
1891 *releasep = IP_NULL;
1892 *assertcntp = 0;
1893 boolean_t deadok = (flags & IPC_RIGHT_COPYIN_FLAGS_DEADOK) ? TRUE : FALSE;
1894
1895 bits = entry->ie_bits;
1896
1897 assert(is_active(space));
1898
1899 switch (msgt_name) {
1900 case MACH_MSG_TYPE_MAKE_SEND: {
1901 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1902 goto invalid_right;
1903 }
1904
1905 port = (ipc_port_t) entry->ie_object;
1906 assert(port != IP_NULL);
1907
1908 ip_lock(port);
1909 assert(ip_active(port));
1910 assert(port->ip_receiver_name == name);
1911 assert(port->ip_receiver == space);
1912
1913 port->ip_mscount++;
1914 port->ip_srights++;
1915 ip_reference(port);
1916 ip_unlock(port);
1917
1918 *objectp = (ipc_object_t) port;
1919 *sorightp = IP_NULL;
1920 break;
1921 }
1922
1923 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1924 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1925 goto invalid_right;
1926 }
1927
1928 port = (ipc_port_t) entry->ie_object;
1929 assert(port != IP_NULL);
1930
1931 ip_lock(port);
1932 assert(ip_active(port));
1933 assert(port->ip_receiver_name == name);
1934 assert(port->ip_receiver == space);
1935
1936 port->ip_sorights++;
1937 ip_reference(port);
1938 ip_unlock(port);
1939
1940 *objectp = (ipc_object_t) port;
1941 *sorightp = IP_NULL;
1942 break;
1943 }
1944
1945 case MACH_MSG_TYPE_MOVE_RECEIVE: {
1946 ipc_port_t request = IP_NULL;
1947
1948 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1949 goto invalid_right;
1950 }
1951
1952 /*
1953 * Disallow moving receive-right kobjects, e.g. mk_timer ports
1954 * The ipc_port structure uses the kdata union of kobject and
1955 * imp_task exclusively. Thus, general use of a kobject port as
1956 * a receive right can cause type confusion in the importance
1957 * code.
1958 */
1959 if (io_kotype(entry->ie_object) != IKOT_NONE) {
1960 /*
1961 * Distinguish an invalid right, e.g., trying to move
1962 * a send right as a receive right, from this
1963 * situation which is, "This is a valid receive right,
1964 * but it's also a kobject and you can't move it."
1965 */
1966 return KERN_INVALID_CAPABILITY;
1967 }
1968
1969 port = (ipc_port_t) entry->ie_object;
1970 assert(port != IP_NULL);
1971
1972 ip_lock(port);
1973 assert(ip_active(port));
1974 assert(port->ip_receiver_name == name);
1975 assert(port->ip_receiver == space);
1976
1977 if (bits & MACH_PORT_TYPE_SEND) {
1978 assert(IE_BITS_TYPE(bits) ==
1979 MACH_PORT_TYPE_SEND_RECEIVE);
1980 assert(IE_BITS_UREFS(bits) > 0);
1981 assert(port->ip_srights > 0);
1982
1983 ipc_hash_insert(space, (ipc_object_t) port,
1984 name, entry);
1985 ip_reference(port);
1986 } else {
1987 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1988 assert(IE_BITS_UREFS(bits) == 0);
1989
1990 request = ipc_right_request_cancel_macro(space, port,
1991 name, entry);
1992 entry->ie_object = IO_NULL;
1993 }
1994 entry->ie_bits = bits & ~MACH_PORT_TYPE_RECEIVE;
1995 ipc_entry_modified(space, name, entry);
1996
1997 (void)ipc_port_clear_receiver(port, FALSE); /* don't destroy the port/mqueue */
1998
1999 #if IMPORTANCE_INHERITANCE
2000 /*
2001 * Account for boosts the current task is going to lose when
2002 * copying this right in. Tempowner ports have either not
2003 * been accounting to any task (and therefore are already in
2004 * "limbo" state w.r.t. assertions) or to some other specific
2005 * task. As we have no way to drop the latter task's assertions
2006 * here, We'll deduct those when we enqueue it on its
2007 * destination port (see ipc_port_check_circularity()).
2008 */
2009 if (port->ip_tempowner == 0) {
2010 assert(IIT_NULL == port->ip_imp_task);
2011
2012 /* ports in limbo have to be tempowner */
2013 port->ip_tempowner = 1;
2014 *assertcntp = port->ip_impcount;
2015 }
2016 #endif /* IMPORTANCE_INHERITANCE */
2017
2018 ip_unlock(port);
2019
2020 *objectp = (ipc_object_t) port;
2021 *sorightp = request;
2022 break;
2023 }
2024
2025 case MACH_MSG_TYPE_COPY_SEND: {
2026 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
2027 goto copy_dead;
2028 }
2029
2030 /* allow for dead send-once rights */
2031
2032 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
2033 goto invalid_right;
2034 }
2035
2036 assert(IE_BITS_UREFS(bits) > 0);
2037
2038 port = (ipc_port_t) entry->ie_object;
2039 assert(port != IP_NULL);
2040
2041 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2042 bits = entry->ie_bits;
2043 *releasep = port;
2044 goto copy_dead;
2045 }
2046 /* port is locked and active */
2047
2048 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2049 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2050 assert(port->ip_sorights > 0);
2051
2052 ip_unlock(port);
2053 goto invalid_right;
2054 }
2055
2056 assert(port->ip_srights > 0);
2057
2058 port->ip_srights++;
2059 ip_reference(port);
2060 ip_unlock(port);
2061
2062 *objectp = (ipc_object_t) port;
2063 *sorightp = IP_NULL;
2064 break;
2065 }
2066
2067 case MACH_MSG_TYPE_MOVE_SEND: {
2068 ipc_port_t request = IP_NULL;
2069
2070 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
2071 goto move_dead;
2072 }
2073
2074 /* allow for dead send-once rights */
2075
2076 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
2077 goto invalid_right;
2078 }
2079
2080 assert(IE_BITS_UREFS(bits) > 0);
2081
2082 port = (ipc_port_t) entry->ie_object;
2083 assert(port != IP_NULL);
2084
2085 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2086 bits = entry->ie_bits;
2087 *releasep = port;
2088 goto move_dead;
2089 }
2090 /* port is locked and active */
2091
2092 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2093 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2094 assert(port->ip_sorights > 0);
2095
2096 ip_unlock(port);
2097 goto invalid_right;
2098 }
2099
2100 assert(port->ip_srights > 0);
2101
2102 if (IE_BITS_UREFS(bits) == 1) {
2103 if (bits & MACH_PORT_TYPE_RECEIVE) {
2104 assert(port->ip_receiver_name == name);
2105 assert(port->ip_receiver == space);
2106 assert(IE_BITS_TYPE(bits) ==
2107 MACH_PORT_TYPE_SEND_RECEIVE);
2108
2109 ip_reference(port);
2110 } else {
2111 assert(IE_BITS_TYPE(bits) ==
2112 MACH_PORT_TYPE_SEND);
2113
2114 request = ipc_right_request_cancel_macro(space, port,
2115 name, entry);
2116 ipc_hash_delete(space, (ipc_object_t) port,
2117 name, entry);
2118 entry->ie_object = IO_NULL;
2119 /* transfer entry's reference to caller */
2120 }
2121 entry->ie_bits = bits & ~
2122 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND);
2123 } else {
2124 port->ip_srights++;
2125 ip_reference(port);
2126 /* if urefs are pegged due to overflow, leave them pegged */
2127 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2128 entry->ie_bits = bits - 1; /* decrement urefs */
2129 }
2130 }
2131
2132 ipc_entry_modified(space, name, entry);
2133 ip_unlock(port);
2134
2135 *objectp = (ipc_object_t) port;
2136 *sorightp = request;
2137 break;
2138 }
2139
2140 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
2141 ipc_port_t request;
2142
2143 if (bits & MACH_PORT_TYPE_DEAD_NAME) {
2144 goto move_dead;
2145 }
2146
2147 /* allow for dead send rights */
2148
2149 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) {
2150 goto invalid_right;
2151 }
2152
2153 assert(IE_BITS_UREFS(bits) > 0);
2154
2155 port = (ipc_port_t) entry->ie_object;
2156 assert(port != IP_NULL);
2157
2158 if (ipc_right_check(space, port, name, entry, flags)) {
2159 bits = entry->ie_bits;
2160 *releasep = port;
2161 goto move_dead;
2162 }
2163 /*
2164 * port is locked, but may not be active:
2165 * Allow copyin of inactive ports with no dead name request and treat it
2166 * as if the copyin of the port was successful and port became inactive
2167 * later.
2168 */
2169
2170 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
2171 assert(bits & MACH_PORT_TYPE_SEND);
2172 assert(port->ip_srights > 0);
2173
2174 ip_unlock(port);
2175 goto invalid_right;
2176 }
2177
2178 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2179 assert(IE_BITS_UREFS(bits) == 1);
2180 assert(port->ip_sorights > 0);
2181
2182 request = ipc_right_request_cancel_macro(space, port, name, entry);
2183 ip_unlock(port);
2184
2185 entry->ie_object = IO_NULL;
2186 entry->ie_bits = bits & ~
2187 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
2188 ipc_entry_modified(space, name, entry);
2189 *objectp = (ipc_object_t) port;
2190 *sorightp = request;
2191 break;
2192 }
2193
2194 default:
2195 invalid_right:
2196 return KERN_INVALID_RIGHT;
2197 }
2198
2199 return KERN_SUCCESS;
2200
2201 copy_dead:
2202 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2203 assert(IE_BITS_UREFS(bits) > 0);
2204 assert(entry->ie_request == IE_REQ_NONE);
2205 assert(entry->ie_object == 0);
2206
2207 if (!deadok) {
2208 goto invalid_right;
2209 }
2210
2211 *objectp = IO_DEAD;
2212 *sorightp = IP_NULL;
2213 return KERN_SUCCESS;
2214
2215 move_dead:
2216 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2217 assert(IE_BITS_UREFS(bits) > 0);
2218 assert(entry->ie_request == IE_REQ_NONE);
2219 assert(entry->ie_object == 0);
2220
2221 if (!deadok) {
2222 goto invalid_right;
2223 }
2224
2225 if (IE_BITS_UREFS(bits) == 1) {
2226 bits &= ~MACH_PORT_TYPE_DEAD_NAME;
2227 }
2228 /* if urefs are pegged due to overflow, leave them pegged */
2229 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2230 entry->ie_bits = bits - 1; /* decrement urefs */
2231 }
2232 ipc_entry_modified(space, name, entry);
2233 *objectp = IO_DEAD;
2234 *sorightp = IP_NULL;
2235 return KERN_SUCCESS;
2236 }
2237
2238 /*
2239 * Routine: ipc_right_copyin_undo
2240 * Purpose:
2241 * Undoes the effects of an ipc_right_copyin
2242 * of a send/send-once right that is dead.
2243 * (Object is either IO_DEAD or a dead port.)
2244 * Conditions:
2245 * The space is write-locked and active.
2246 */
2247
2248 void
2249 ipc_right_copyin_undo(
2250 ipc_space_t space,
2251 mach_port_name_t name,
2252 ipc_entry_t entry,
2253 mach_msg_type_name_t msgt_name,
2254 ipc_object_t object,
2255 ipc_port_t soright)
2256 {
2257 ipc_entry_bits_t bits;
2258
2259 bits = entry->ie_bits;
2260
2261 assert(is_active(space));
2262
2263 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2264 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
2265 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2266
2267 if (soright != IP_NULL) {
2268 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2269 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2270 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2271 assert(object != IO_DEAD);
2272
2273 entry->ie_bits = ((bits & ~IE_BITS_RIGHT_MASK) |
2274 MACH_PORT_TYPE_DEAD_NAME | 2);
2275 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
2276 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2277 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2278
2279 entry->ie_bits = ((bits & ~IE_BITS_RIGHT_MASK) |
2280 MACH_PORT_TYPE_DEAD_NAME | 1);
2281 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
2282 assert(object == IO_DEAD);
2283 assert(IE_BITS_UREFS(bits) > 0);
2284
2285 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2286 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
2287 /* if urefs are pegged due to overflow, leave them pegged */
2288 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2289 entry->ie_bits = bits + 1; /* increment urefs */
2290 }
2291 }
2292 } else {
2293 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2294 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
2295 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2296 assert(object != IO_DEAD);
2297 assert(entry->ie_object == object);
2298 assert(IE_BITS_UREFS(bits) > 0);
2299
2300 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2301 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
2302 /* if urefs are pegged due to overflow, leave them pegged */
2303 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2304 entry->ie_bits = bits + 1; /* increment urefs */
2305 }
2306 }
2307
2308 /*
2309 * May as well convert the entry to a dead name.
2310 * (Or if it is a compat entry, destroy it.)
2311 */
2312
2313 (void) ipc_right_check(space, (ipc_port_t) object,
2314 name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE);
2315 /* object is dead so it is not locked */
2316 }
2317 ipc_entry_modified(space, name, entry);
2318 /* release the reference acquired by copyin */
2319
2320 if (object != IO_DEAD) {
2321 io_release(object);
2322 }
2323 }
2324
2325 /*
2326 * Routine: ipc_right_copyin_two_move_sends
2327 * Purpose:
2328 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2329 * and deadok == FALSE, except that this moves two
2330 * send rights at once.
2331 * Conditions:
2332 * The space is write-locked and active.
2333 * The object is returned with two refs/send rights.
2334 * Returns:
2335 * KERN_SUCCESS Acquired an object.
2336 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2337 */
2338 static
2339 kern_return_t
2340 ipc_right_copyin_two_move_sends(
2341 ipc_space_t space,
2342 mach_port_name_t name,
2343 ipc_entry_t entry,
2344 ipc_object_t *objectp,
2345 ipc_port_t *sorightp,
2346 ipc_port_t *releasep)
2347 {
2348 ipc_entry_bits_t bits;
2349 mach_port_urefs_t urefs;
2350 ipc_port_t port;
2351 ipc_port_t request = IP_NULL;
2352
2353 *releasep = IP_NULL;
2354
2355 assert(is_active(space));
2356
2357 bits = entry->ie_bits;
2358
2359 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2360 goto invalid_right;
2361 }
2362
2363 urefs = IE_BITS_UREFS(bits);
2364 if (urefs < 2) {
2365 goto invalid_right;
2366 }
2367
2368 port = (ipc_port_t) entry->ie_object;
2369 assert(port != IP_NULL);
2370
2371 if (ipc_right_check(space, port, name, entry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2372 *releasep = port;
2373 goto invalid_right;
2374 }
2375 /* port is locked and active */
2376
2377 assert(port->ip_srights > 0);
2378
2379 if (urefs == 2) {
2380 if (bits & MACH_PORT_TYPE_RECEIVE) {
2381 assert(port->ip_receiver_name == name);
2382 assert(port->ip_receiver == space);
2383 assert(IE_BITS_TYPE(bits) ==
2384 MACH_PORT_TYPE_SEND_RECEIVE);
2385
2386 port->ip_srights++;
2387 ip_reference(port);
2388 ip_reference(port);
2389 } else {
2390 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2391
2392 request = ipc_right_request_cancel_macro(space, port,
2393 name, entry);
2394
2395 port->ip_srights++;
2396 ip_reference(port);
2397 ipc_hash_delete(space, (ipc_object_t) port,
2398 name, entry);
2399 entry->ie_object = IO_NULL;
2400 }
2401 entry->ie_bits = bits & ~(IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND);
2402 } else {
2403 port->ip_srights += 2;
2404 ip_reference(port);
2405 ip_reference(port);
2406 /* if urefs are pegged due to overflow, leave them pegged */
2407 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
2408 entry->ie_bits = bits - 2; /* decrement urefs */
2409 }
2410 }
2411 ipc_entry_modified(space, name, entry);
2412
2413 ip_unlock(port);
2414
2415 *objectp = (ipc_object_t) port;
2416 *sorightp = request;
2417 return KERN_SUCCESS;
2418
2419 invalid_right:
2420 return KERN_INVALID_RIGHT;
2421 }
2422
2423
2424 /*
2425 * Routine: ipc_right_copyin_two
2426 * Purpose:
2427 * Like ipc_right_copyin with two dispositions,
2428 * each of which results in a send or send-once right,
2429 * and deadok = FALSE.
2430 * Conditions:
2431 * The space is write-locked and active.
2432 * The object is returned with two refs/rights.
2433 * Returns:
2434 * KERN_SUCCESS Acquired an object.
2435 * KERN_INVALID_RIGHT Name doesn't denote correct right(s).
2436 * KERN_INVALID_CAPABILITY Name doesn't denote correct right for msgt_two.
2437 */
2438 kern_return_t
2439 ipc_right_copyin_two(
2440 ipc_space_t space,
2441 mach_port_name_t name,
2442 ipc_entry_t entry,
2443 mach_msg_type_name_t msgt_one,
2444 mach_msg_type_name_t msgt_two,
2445 ipc_object_t *objectp,
2446 ipc_port_t *sorightp,
2447 ipc_port_t *releasep)
2448 {
2449 kern_return_t kr;
2450 int assertcnt = 0;
2451
2452 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one));
2453 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two));
2454
2455
2456 /*
2457 * Pre-validate the second disposition is possible all by itself.
2458 */
2459 if (!ipc_right_copyin_check(space, name, entry, msgt_two)) {
2460 return KERN_INVALID_CAPABILITY;
2461 }
2462
2463 /*
2464 * This is a little tedious to make atomic, because
2465 * there are 25 combinations of valid dispositions.
2466 * However, most are easy.
2467 */
2468
2469 /*
2470 * If either is move-sonce, then there must be an error.
2471 */
2472 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND_ONCE ||
2473 msgt_two == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
2474 return KERN_INVALID_RIGHT;
2475 }
2476
2477 if ((msgt_one == MACH_MSG_TYPE_MAKE_SEND) ||
2478 (msgt_one == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
2479 (msgt_two == MACH_MSG_TYPE_MAKE_SEND) ||
2480 (msgt_two == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
2481 /*
2482 * One of the dispositions needs a receive right.
2483 *
2484 * If the copyin below succeeds, we know the receive
2485 * right is there (because the pre-validation of
2486 * the second disposition already succeeded in our
2487 * caller).
2488 *
2489 * Hence the port is not in danger of dying.
2490 */
2491 ipc_object_t object_two;
2492
2493 kr = ipc_right_copyin(space, name, entry,
2494 msgt_one, IPC_RIGHT_COPYIN_FLAGS_NONE,
2495 objectp, sorightp, releasep,
2496 &assertcnt);
2497 assert(assertcnt == 0);
2498 if (kr != KERN_SUCCESS) {
2499 return kr;
2500 }
2501
2502 assert(IO_VALID(*objectp));
2503 assert(*sorightp == IP_NULL);
2504 assert(*releasep == IP_NULL);
2505
2506 /*
2507 * Now copyin the second (previously validated)
2508 * disposition. The result can't be a dead port,
2509 * as no valid disposition can make us lose our
2510 * receive right.
2511 */
2512 kr = ipc_right_copyin(space, name, entry,
2513 msgt_two, IPC_RIGHT_COPYIN_FLAGS_NONE,
2514 &object_two, sorightp, releasep,
2515 &assertcnt);
2516 assert(assertcnt == 0);
2517 assert(kr == KERN_SUCCESS);
2518 assert(*sorightp == IP_NULL);
2519 assert(*releasep == IP_NULL);
2520 assert(object_two == *objectp);
2521 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
2522 } else if ((msgt_one == MACH_MSG_TYPE_MOVE_SEND) &&
2523 (msgt_two == MACH_MSG_TYPE_MOVE_SEND)) {
2524 /*
2525 * This is an easy case. Just use our
2526 * handy-dandy special-purpose copyin call
2527 * to get two send rights for the price of one.
2528 */
2529 kr = ipc_right_copyin_two_move_sends(space, name, entry,
2530 objectp, sorightp,
2531 releasep);
2532 if (kr != KERN_SUCCESS) {
2533 return kr;
2534 }
2535 } else {
2536 mach_msg_type_name_t msgt_name;
2537
2538 /*
2539 * Must be either a single move-send and a
2540 * copy-send, or two copy-send dispositions.
2541 * Use the disposition with the greatest side
2542 * effects for the actual copyin - then just
2543 * duplicate the send right you get back.
2544 */
2545 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND ||
2546 msgt_two == MACH_MSG_TYPE_MOVE_SEND) {
2547 msgt_name = MACH_MSG_TYPE_MOVE_SEND;
2548 } else {
2549 msgt_name = MACH_MSG_TYPE_COPY_SEND;
2550 }
2551
2552 kr = ipc_right_copyin(space, name, entry,
2553 msgt_name, IPC_RIGHT_COPYIN_FLAGS_NONE,
2554 objectp, sorightp, releasep,
2555 &assertcnt);
2556 assert(assertcnt == 0);
2557 if (kr != KERN_SUCCESS) {
2558 return kr;
2559 }
2560
2561 /*
2562 * Copy the right we got back. If it is dead now,
2563 * that's OK. Neither right will be usable to send
2564 * a message anyway.
2565 */
2566 (void)ipc_port_copy_send((ipc_port_t)*objectp);
2567 }
2568
2569 return KERN_SUCCESS;
2570 }
2571
2572
2573 /*
2574 * Routine: ipc_right_copyout
2575 * Purpose:
2576 * Copyout a capability to a space.
2577 * If successful, consumes a ref for the object.
2578 *
2579 * Always succeeds when given a newly-allocated entry,
2580 * because user-reference overflow isn't a possibility.
2581 *
2582 * If copying out the object would cause the user-reference
2583 * count in the entry to overflow, and overflow is TRUE,
2584 * then instead the user-reference count is left pegged
2585 * to its maximum value and the copyout succeeds anyway.
2586 * Conditions:
2587 * The space is write-locked and active.
2588 * The object is locked and active.
2589 * The object is unlocked; the space isn't.
2590 * Returns:
2591 * KERN_SUCCESS Copied out capability.
2592 */
2593
2594 kern_return_t
2595 ipc_right_copyout(
2596 ipc_space_t space,
2597 mach_port_name_t name,
2598 ipc_entry_t entry,
2599 mach_msg_type_name_t msgt_name,
2600 __unused boolean_t overflow,
2601 ipc_object_t object)
2602 {
2603 ipc_entry_bits_t bits;
2604 ipc_port_t port;
2605
2606 bits = entry->ie_bits;
2607
2608 assert(IO_VALID(object));
2609 assert(io_otype(object) == IOT_PORT);
2610 assert(io_active(object));
2611 assert(entry->ie_object == object);
2612
2613 port = (ipc_port_t) object;
2614
2615 switch (msgt_name) {
2616 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2617
2618 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2619 assert(IE_BITS_UREFS(bits) == 0);
2620 assert(port->ip_sorights > 0);
2621
2622 if (port->ip_specialreply) {
2623 ipc_port_adjust_special_reply_port_locked(port,
2624 current_thread()->ith_knote, IPC_PORT_ADJUST_SR_LINK_WORKLOOP, FALSE);
2625 /* port unlocked on return */
2626 } else {
2627 ip_unlock(port);
2628 }
2629
2630 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1); /* set urefs to 1 */
2631 ipc_entry_modified(space, name, entry);
2632 break;
2633
2634 case MACH_MSG_TYPE_PORT_SEND:
2635 assert(port->ip_srights > 0);
2636
2637 if (bits & MACH_PORT_TYPE_SEND) {
2638 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2639
2640 assert(port->ip_srights > 1);
2641 assert(urefs > 0);
2642 assert(urefs <= MACH_PORT_UREFS_MAX);
2643
2644 if (urefs == MACH_PORT_UREFS_MAX) {
2645 /*
2646 * leave urefs pegged to maximum,
2647 * consume send right and ref
2648 */
2649
2650 port->ip_srights--;
2651 ip_unlock(port);
2652 ip_release(port);
2653 return KERN_SUCCESS;
2654 }
2655
2656 /* consume send right and ref */
2657 port->ip_srights--;
2658 ip_unlock(port);
2659 ip_release(port);
2660 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2661 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2662 assert(IE_BITS_UREFS(bits) == 0);
2663
2664 /* transfer send right to entry, consume ref */
2665 ip_unlock(port);
2666 ip_release(port);
2667 } else {
2668 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2669 assert(IE_BITS_UREFS(bits) == 0);
2670
2671 /* transfer send right and ref to entry */
2672 ip_unlock(port);
2673
2674 /* entry is locked holding ref, so can use port */
2675
2676 ipc_hash_insert(space, (ipc_object_t) port,
2677 name, entry);
2678 }
2679
2680 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; /* increment urefs */
2681 ipc_entry_modified(space, name, entry);
2682 break;
2683
2684 case MACH_MSG_TYPE_PORT_RECEIVE: {
2685 ipc_port_t dest;
2686 turnstile_inheritor_t inheritor = TURNSTILE_INHERITOR_NULL;
2687 struct turnstile *ts = TURNSTILE_NULL;
2688
2689 #if IMPORTANCE_INHERITANCE
2690 natural_t assertcnt = port->ip_impcount;
2691 #endif /* IMPORTANCE_INHERITANCE */
2692
2693 assert(port->ip_mscount == 0);
2694 assert(port->ip_receiver_name == MACH_PORT_NULL);
2695
2696 imq_lock(&port->ip_messages);
2697 dest = port->ip_destination;
2698
2699 port->ip_receiver_name = name;
2700 port->ip_receiver = space;
2701
2702 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2703
2704 /* Update the port's turnstile linkage to WL turnstile */
2705 ts = port_send_turnstile(port);
2706 if (ts) {
2707 struct knote *kn = current_thread()->ith_knote;
2708 if (ITH_KNOTE_VALID(kn, MACH_MSG_TYPE_PORT_RECEIVE)) {
2709 inheritor = filt_machport_stash_port(kn, port, NULL);
2710 if (inheritor) {
2711 turnstile_reference(inheritor);
2712 IMQ_SET_INHERITOR(&port->ip_messages, inheritor);
2713 }
2714 }
2715 turnstile_reference(ts);
2716 turnstile_update_inheritor(ts, inheritor,
2717 (TURNSTILE_IMMEDIATE_UPDATE | TURNSTILE_INHERITOR_TURNSTILE));
2718 }
2719
2720 imq_unlock(&port->ip_messages);
2721
2722 if (bits & MACH_PORT_TYPE_SEND) {
2723 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2724 assert(IE_BITS_UREFS(bits) > 0);
2725 assert(port->ip_srights > 0);
2726
2727 ip_unlock(port);
2728 ip_release(port);
2729
2730 /* entry is locked holding ref, so can use port */
2731 ipc_hash_delete(space, (ipc_object_t) port, name, entry);
2732 } else {
2733 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2734 assert(IE_BITS_UREFS(bits) == 0);
2735
2736 /* transfer ref to entry */
2737 ip_unlock(port);
2738 }
2739 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2740 ipc_entry_modified(space, name, entry);
2741
2742 if (ts) {
2743 turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
2744 turnstile_deallocate_safe(ts);
2745 }
2746
2747 if (dest != IP_NULL) {
2748 #if IMPORTANCE_INHERITANCE
2749 /*
2750 * Deduct the assertion counts we contributed to
2751 * the old destination port. They've already
2752 * been reflected into the task as a result of
2753 * getting enqueued.
2754 */
2755 ip_lock(dest);
2756 ipc_port_impcount_delta(dest, 0 - assertcnt, IP_NULL);
2757 ip_unlock(dest);
2758 #endif /* IMPORTANCE_INHERITANCE */
2759
2760 /* Drop turnstile ref on dest */
2761 ipc_port_send_turnstile_complete(dest);
2762 ip_release(dest);
2763 }
2764 break;
2765 }
2766
2767 default:
2768 panic("ipc_right_copyout: strange rights");
2769 }
2770 return KERN_SUCCESS;
2771 }
2772
2773 /*
2774 * Routine: ipc_right_rename
2775 * Purpose:
2776 * Transfer an entry from one name to another.
2777 * The old entry is deallocated.
2778 * Conditions:
2779 * The space is write-locked and active.
2780 * The new entry is unused. Upon return,
2781 * the space is unlocked.
2782 * Returns:
2783 * KERN_SUCCESS Moved entry to new name.
2784 */
2785
2786 kern_return_t
2787 ipc_right_rename(
2788 ipc_space_t space,
2789 mach_port_name_t oname,
2790 ipc_entry_t oentry,
2791 mach_port_name_t nname,
2792 ipc_entry_t nentry)
2793 {
2794 ipc_port_request_index_t request = oentry->ie_request;
2795 ipc_entry_bits_t bits = oentry->ie_bits;
2796 ipc_object_t object = oentry->ie_object;
2797 ipc_port_t release_port = IP_NULL;
2798
2799 assert(is_active(space));
2800 assert(oname != nname);
2801
2802 /*
2803 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2804 * if the port is dead. (This would foil ipc_port_destroy.)
2805 * Instead we should fail because oentry shouldn't exist.
2806 * Note IE_BITS_COMPAT implies ie_request != 0.
2807 */
2808
2809 if (request != IE_REQ_NONE) {
2810 ipc_port_t port;
2811
2812 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2813 port = (ipc_port_t) object;
2814 assert(port != IP_NULL);
2815
2816 if (ipc_right_check(space, port, oname, oentry, IPC_RIGHT_COPYIN_FLAGS_NONE)) {
2817 request = IE_REQ_NONE;
2818 object = IO_NULL;
2819 bits = oentry->ie_bits;
2820 release_port = port;
2821 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2822 assert(oentry->ie_request == IE_REQ_NONE);
2823 } else {
2824 /* port is locked and active */
2825
2826 ipc_port_request_rename(port, request, oname, nname);
2827 ip_unlock(port);
2828 oentry->ie_request = IE_REQ_NONE;
2829 }
2830 }
2831
2832 /* initialize nentry before letting ipc_hash_insert see it */
2833
2834 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2835 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2836 nentry->ie_request = request;
2837 nentry->ie_object = object;
2838
2839 switch (IE_BITS_TYPE(bits)) {
2840 case MACH_PORT_TYPE_SEND: {
2841 ipc_port_t port;
2842
2843 port = (ipc_port_t) object;
2844 assert(port != IP_NULL);
2845
2846 /* remember, there are no other share entries possible */
2847 /* or we can't do the rename. Therefore we do not need */
2848 /* to check the other subspaces */
2849 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2850 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2851 break;
2852 }
2853
2854 case MACH_PORT_TYPE_RECEIVE:
2855 case MACH_PORT_TYPE_SEND_RECEIVE: {
2856 ipc_port_t port;
2857
2858 port = (ipc_port_t) object;
2859 assert(port != IP_NULL);
2860
2861 ip_lock(port);
2862 imq_lock(&port->ip_messages);
2863 assert(ip_active(port));
2864 assert(port->ip_receiver_name == oname);
2865 assert(port->ip_receiver == space);
2866
2867 port->ip_receiver_name = nname;
2868 imq_unlock(&port->ip_messages);
2869 ip_unlock(port);
2870 break;
2871 }
2872
2873 case MACH_PORT_TYPE_PORT_SET: {
2874 ipc_pset_t pset;
2875
2876 pset = (ipc_pset_t) object;
2877 assert(pset != IPS_NULL);
2878
2879 ips_lock(pset);
2880 assert(ips_active(pset));
2881
2882 ips_unlock(pset);
2883 break;
2884 }
2885
2886 case MACH_PORT_TYPE_SEND_ONCE:
2887 case MACH_PORT_TYPE_DEAD_NAME:
2888 break;
2889
2890 default:
2891 panic("ipc_right_rename: strange rights");
2892 }
2893
2894 assert(oentry->ie_request == IE_REQ_NONE);
2895 oentry->ie_object = IO_NULL;
2896 ipc_entry_dealloc(space, oname, oentry);
2897 ipc_entry_modified(space, nname, nentry);
2898 is_write_unlock(space);
2899
2900 if (release_port != IP_NULL) {
2901 ip_release(release_port);
2902 }
2903
2904 return KERN_SUCCESS;
2905 }