]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_right.c
xnu-1228.3.13.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/misc_protos.h>
79 #include <ipc/port.h>
80 #include <ipc/ipc_entry.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_object.h>
83 #include <ipc/ipc_hash.h>
84 #include <ipc/ipc_port.h>
85 #include <ipc/ipc_pset.h>
86 #include <ipc/ipc_right.h>
87 #include <ipc/ipc_notify.h>
88 #include <ipc/ipc_table.h>
89 #include <security/mac_mach_internal.h>
90
91 /*
92 * Routine: ipc_right_lookup_write
93 * Purpose:
94 * Finds an entry in a space, given the name.
95 * Conditions:
96 * Nothing locked. If successful, the space is write-locked.
97 * Returns:
98 * KERN_SUCCESS Found an entry.
99 * KERN_INVALID_TASK The space is dead.
100 * KERN_INVALID_NAME Name doesn't exist in space.
101 */
102
103 kern_return_t
104 ipc_right_lookup_write(
105 ipc_space_t space,
106 mach_port_name_t name,
107 ipc_entry_t *entryp)
108 {
109 ipc_entry_t entry;
110
111 assert(space != IS_NULL);
112
113 is_write_lock(space);
114
115 if (!space->is_active) {
116 is_write_unlock(space);
117 return KERN_INVALID_TASK;
118 }
119
120 if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
121 is_write_unlock(space);
122 return KERN_INVALID_NAME;
123 }
124
125 *entryp = entry;
126 return KERN_SUCCESS;
127 }
128
129 /*
130 * Routine: ipc_right_lookup_two_write
131 * Purpose:
132 * Like ipc_right_lookup except that it returns two
133 * entries for two different names that were looked
134 * up under the same space lock.
135 * Conditions:
136 * Nothing locked. If successful, the space is write-locked.
137 * Returns:
138 * KERN_INVALID_TASK The space is dead.
139 * KERN_INVALID_NAME Name doesn't exist in space.
140 */
141
142 kern_return_t
143 ipc_right_lookup_two_write(
144 ipc_space_t space,
145 mach_port_name_t name1,
146 ipc_entry_t *entryp1,
147 mach_port_name_t name2,
148 ipc_entry_t *entryp2)
149 {
150 ipc_entry_t entry1;
151 ipc_entry_t entry2;
152
153 assert(space != IS_NULL);
154
155 is_write_lock(space);
156
157 if (!space->is_active) {
158 is_write_unlock(space);
159 return KERN_INVALID_TASK;
160 }
161
162 if ((entry1 = ipc_entry_lookup(space, name1)) == IE_NULL) {
163 is_write_unlock(space);
164 return KERN_INVALID_NAME;
165 }
166 if ((entry2 = ipc_entry_lookup(space, name2)) == IE_NULL) {
167 is_write_unlock(space);
168 return KERN_INVALID_NAME;
169 }
170 *entryp1 = entry1;
171 *entryp2 = entry2;
172 return KERN_SUCCESS;
173 }
174
175 /*
176 * Routine: ipc_right_reverse
177 * Purpose:
178 * Translate (space, object) -> (name, entry).
179 * Only finds send/receive rights.
180 * Returns TRUE if an entry is found; if so,
181 * the object is locked and active.
182 * Conditions:
183 * The space must be locked (read or write) and active.
184 * Nothing else locked.
185 */
186
187 boolean_t
188 ipc_right_reverse(
189 ipc_space_t space,
190 ipc_object_t object,
191 mach_port_name_t *namep,
192 ipc_entry_t *entryp)
193 {
194 ipc_port_t port;
195 mach_port_name_t name;
196 ipc_entry_t entry;
197
198 /* would switch on io_otype to handle multiple types of object */
199
200 assert(space->is_active);
201 assert(io_otype(object) == IOT_PORT);
202
203 port = (ipc_port_t) object;
204
205 ip_lock(port);
206 if (!ip_active(port)) {
207 ip_unlock(port);
208
209 return FALSE;
210 }
211
212 if (port->ip_receiver == space) {
213 name = port->ip_receiver_name;
214 assert(name != MACH_PORT_NULL);
215
216 entry = ipc_entry_lookup(space, name);
217
218 assert(entry != IE_NULL);
219 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
220 assert(port == (ipc_port_t) entry->ie_object);
221
222 *namep = name;
223 *entryp = entry;
224 return TRUE;
225 }
226
227 if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
228 assert((entry = *entryp) != IE_NULL);
229 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
230 assert(port == (ipc_port_t) entry->ie_object);
231
232 return TRUE;
233 }
234
235 ip_unlock(port);
236 return FALSE;
237 }
238
239 /*
240 * Routine: ipc_right_dnrequest
241 * Purpose:
242 * Make a dead-name request, returning the previously
243 * registered send-once right. If notify is IP_NULL,
244 * just cancels the previously registered request.
245 *
246 * This interacts with the IE_BITS_COMPAT, because they
247 * both use ie_request. If this is a compat entry, then
248 * previous always gets IP_NULL. If notify is IP_NULL,
249 * then the entry remains a compat entry. Otherwise
250 * the real dead-name request is registered and the entry
251 * is no longer a compat entry.
252 * Conditions:
253 * Nothing locked. May allocate memory.
254 * Only consumes/returns refs if successful.
255 * Returns:
256 * KERN_SUCCESS Made/canceled dead-name request.
257 * KERN_INVALID_TASK The space is dead.
258 * KERN_INVALID_NAME Name doesn't exist in space.
259 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
260 * KERN_INVALID_ARGUMENT Name denotes dead name, but
261 * immediate is FALSE or notify is IP_NULL.
262 * KERN_UREFS_OVERFLOW Name denotes dead name, but
263 * generating immediate notif. would overflow urefs.
264 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
265 */
266
267 kern_return_t
268 ipc_right_dnrequest(
269 ipc_space_t space,
270 mach_port_name_t name,
271 boolean_t immediate,
272 ipc_port_t notify,
273 ipc_port_t *previousp)
274 {
275 ipc_port_t previous;
276
277 for (;;) {
278 ipc_entry_t entry;
279 ipc_entry_bits_t bits;
280 kern_return_t kr;
281
282 kr = ipc_right_lookup_write(space, name, &entry);
283 if (kr != KERN_SUCCESS)
284 return kr;
285 /* space is write-locked and active */
286 bits = entry->ie_bits;
287 if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
288 ipc_port_t port;
289 ipc_port_request_index_t request;
290
291 port = (ipc_port_t) entry->ie_object;
292 assert(port != IP_NULL);
293
294 if (!ipc_right_check(space, port, name, entry)) {
295 /* port is locked and active */
296
297 if (notify == IP_NULL) {
298 previous = ipc_right_dncancel_macro(
299 space, port, name, entry);
300
301 ip_unlock(port);
302 is_write_unlock(space);
303 break;
304 }
305
306 /*
307 * If a registered soright exists,
308 * want to atomically switch with it.
309 * If ipc_port_dncancel finds us a
310 * soright, then the following
311 * ipc_port_dnrequest will reuse
312 * that slot, so we are guaranteed
313 * not to unlock and retry.
314 */
315
316 previous = ipc_right_dncancel_macro(space,
317 port, name, entry);
318
319 kr = ipc_port_dnrequest(port, name, notify,
320 &request);
321 if (kr != KERN_SUCCESS) {
322 assert(previous == IP_NULL);
323 is_write_unlock(space);
324
325 kr = ipc_port_dngrow(port,
326 ITS_SIZE_NONE);
327 /* port is unlocked */
328 if (kr != KERN_SUCCESS)
329 return kr;
330
331 continue;
332 }
333
334 assert(request != 0);
335 ip_unlock(port);
336
337 entry->ie_request = request;
338 is_write_unlock(space);
339 break;
340 } else {
341
342 /*
343 * Our capability bits were changed by ipc_right_check
344 * because it found an inactive port and removed our
345 * references to it (converting our entry into a dead
346 * one). Reload the bits (and obviously we can't use
347 * the port name anymore).
348 */
349 bits = entry->ie_bits;
350
351 }
352
353 assert(bits & MACH_PORT_TYPE_DEAD_NAME);
354 }
355
356 if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
357 immediate && (notify != IP_NULL)) {
358 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
359
360 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
361 assert(urefs > 0);
362
363 if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
364 is_write_unlock(space);
365 return KERN_UREFS_OVERFLOW;
366 }
367
368 (entry->ie_bits)++; /* increment urefs */
369 is_write_unlock(space);
370
371 ipc_notify_dead_name(notify, name);
372 previous = IP_NULL;
373 break;
374 }
375
376 is_write_unlock(space);
377 if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
378 return KERN_INVALID_ARGUMENT;
379 else
380 return KERN_INVALID_RIGHT;
381 }
382
383 *previousp = previous;
384 return KERN_SUCCESS;
385 }
386
387 /*
388 * Routine: ipc_right_dncancel
389 * Purpose:
390 * Cancel a dead-name request and return the send-once right.
391 * Afterwards, entry->ie_request == 0.
392 * Conditions:
393 * The space must be write-locked; the port must be locked.
394 * The port must be active; the space doesn't have to be.
395 */
396
397 ipc_port_t
398 ipc_right_dncancel(
399 __unused ipc_space_t space,
400 ipc_port_t port,
401 mach_port_name_t name,
402 ipc_entry_t entry)
403 {
404 ipc_port_t dnrequest;
405
406 assert(ip_active(port));
407 assert(port == (ipc_port_t) entry->ie_object);
408
409 dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
410 entry->ie_request = 0;
411
412 return dnrequest;
413 }
414
415 /*
416 * Routine: ipc_right_inuse
417 * Purpose:
418 * Check if an entry is being used.
419 * Returns TRUE if it is.
420 * Conditions:
421 * The space is write-locked and active.
422 * It is unlocked if the entry is inuse.
423 */
424
425 boolean_t
426 ipc_right_inuse(
427 ipc_space_t space,
428 __unused mach_port_name_t name,
429 ipc_entry_t entry)
430 {
431 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
432 is_write_unlock(space);
433 return TRUE;
434 }
435 return FALSE;
436 }
437
438 /*
439 * Routine: ipc_right_check
440 * Purpose:
441 * Check if the port has died. If it has,
442 * clean up the entry and return TRUE.
443 * Conditions:
444 * The space is write-locked; the port is not locked.
445 * If returns FALSE, the port is also locked and active.
446 * Otherwise, entry is converted to a dead name, freeing
447 * a reference to port.
448 */
449
450 boolean_t
451 ipc_right_check(
452 ipc_space_t space,
453 ipc_port_t port,
454 mach_port_name_t name,
455 ipc_entry_t entry)
456 {
457 ipc_entry_bits_t bits;
458
459 assert(space->is_active);
460 assert(port == (ipc_port_t) entry->ie_object);
461
462 ip_lock(port);
463 if (ip_active(port))
464 return FALSE;
465 ip_unlock(port);
466
467 /* this was either a pure send right or a send-once right */
468
469 bits = entry->ie_bits;
470 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
471 assert(IE_BITS_UREFS(bits) > 0);
472
473 if (bits & MACH_PORT_TYPE_SEND) {
474 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
475 } else {
476 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
477 assert(IE_BITS_UREFS(bits) == 1);
478 }
479
480
481 ipc_port_release(port);
482
483 /* convert entry to dead name */
484
485 if ((bits & MACH_PORT_TYPE_SEND) && !(bits & MACH_PORT_TYPE_RECEIVE))
486 ipc_hash_delete(space, (ipc_object_t)port, name, entry);
487
488 bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
489
490 /*
491 * If there was a notification request outstanding on this
492 * name, and since the port went dead, that notification
493 * must already be on its way up from the port layer. We
494 * don't need the index of the notification port anymore.
495 *
496 * JMM - We also add a reference to the entry since the
497 * notification only carries the name and NOT a reference
498 * (or right). This makes for pretty loose reference
499 * counting, since it is only happenstance that we
500 * detected the notification in progress like this.
501 * But most (all?) calls that try to deal with this entry
502 * will also come through here, so the reference gets added
503 * before the entry gets used eventually (I would rather it
504 * be explicit in the notification generation, though)
505 */
506 if (entry->ie_request != 0) {
507 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
508 entry->ie_request = 0;
509 bits++;
510 }
511 entry->ie_bits = bits;
512 entry->ie_object = IO_NULL;
513 return TRUE;
514 }
515
516 /*
517 * Routine: ipc_right_clean
518 * Purpose:
519 * Cleans up an entry in a dead space.
520 * The entry isn't deallocated or removed
521 * from reverse hash tables.
522 * Conditions:
523 * The space is dead and unlocked.
524 */
525
526 void
527 ipc_right_clean(
528 ipc_space_t space,
529 mach_port_name_t name,
530 ipc_entry_t entry)
531 {
532 ipc_entry_bits_t bits;
533 mach_port_type_t type;
534
535 bits = entry->ie_bits;
536 type = IE_BITS_TYPE(bits);
537
538 assert(!space->is_active);
539
540 /*
541 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
542 * problem, because we check that the port is active. If
543 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
544 * would still work, but dead space refs would accumulate
545 * in ip_dnrequests. They would use up slots in
546 * ip_dnrequests and keep the spaces from being freed.
547 */
548
549 switch (type) {
550 case MACH_PORT_TYPE_DEAD_NAME:
551 assert(entry->ie_request == 0);
552 assert(entry->ie_object == IO_NULL);
553 break;
554
555 case MACH_PORT_TYPE_PORT_SET: {
556 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
557
558 assert(entry->ie_request == 0);
559 assert(pset != IPS_NULL);
560
561 ips_lock(pset);
562 assert(ips_active(pset));
563
564 ipc_pset_destroy(pset); /* consumes ref, unlocks */
565 break;
566 }
567
568 case MACH_PORT_TYPE_SEND:
569 case MACH_PORT_TYPE_RECEIVE:
570 case MACH_PORT_TYPE_SEND_RECEIVE:
571 case MACH_PORT_TYPE_SEND_ONCE: {
572 ipc_port_t port = (ipc_port_t) entry->ie_object;
573 ipc_port_t dnrequest;
574 ipc_port_t nsrequest = IP_NULL;
575 mach_port_mscount_t mscount = 0;
576
577 assert(port != IP_NULL);
578 ip_lock(port);
579
580 if (!ip_active(port)) {
581 ip_release(port);
582 ip_check_unlock(port);
583 break;
584 }
585
586 dnrequest = ipc_right_dncancel_macro(space, port,
587 name, entry);
588
589 if (type & MACH_PORT_TYPE_SEND) {
590 assert(port->ip_srights > 0);
591 if (--port->ip_srights == 0
592 ) {
593 nsrequest = port->ip_nsrequest;
594 if (nsrequest != IP_NULL) {
595 port->ip_nsrequest = IP_NULL;
596 mscount = port->ip_mscount;
597 }
598 }
599 }
600
601 if (type & MACH_PORT_TYPE_RECEIVE) {
602 assert(port->ip_receiver_name == name);
603 assert(port->ip_receiver == space);
604
605 ipc_port_clear_receiver(port);
606 ipc_port_destroy(port); /* consumes our ref, unlocks */
607 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
608 assert(port->ip_sorights > 0);
609 ip_unlock(port);
610
611 ipc_notify_send_once(port); /* consumes our ref */
612 } else {
613 assert(port->ip_receiver != space);
614
615 ip_release(port);
616 ip_unlock(port); /* port is active */
617 }
618
619 if (nsrequest != IP_NULL)
620 ipc_notify_no_senders(nsrequest, mscount);
621
622 if (dnrequest != IP_NULL)
623 ipc_notify_port_deleted(dnrequest, name);
624 break;
625 }
626
627 default:
628 panic("ipc_right_clean: strange type");
629 }
630 }
631
632 /*
633 * Routine: ipc_right_destroy
634 * Purpose:
635 * Destroys an entry in a space.
636 * Conditions:
637 * The space is write-locked.
638 * The space must be active.
639 * Returns:
640 * KERN_SUCCESS The entry was destroyed.
641 */
642
643 kern_return_t
644 ipc_right_destroy(
645 ipc_space_t space,
646 mach_port_name_t name,
647 ipc_entry_t entry)
648 {
649 ipc_entry_bits_t bits;
650 mach_port_type_t type;
651
652 bits = entry->ie_bits;
653 entry->ie_bits &= ~IE_BITS_TYPE_MASK;
654 type = IE_BITS_TYPE(bits);
655
656 assert(space->is_active);
657
658 switch (type) {
659 case MACH_PORT_TYPE_DEAD_NAME:
660 assert(entry->ie_request == 0);
661 assert(entry->ie_object == IO_NULL);
662
663 ipc_entry_dealloc(space, name, entry);
664 break;
665
666 case MACH_PORT_TYPE_PORT_SET: {
667 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
668
669 assert(entry->ie_request == 0);
670 assert(pset != IPS_NULL);
671
672 entry->ie_object = IO_NULL;
673 ipc_entry_dealloc(space, name, entry);
674
675 ips_lock(pset);
676 assert(ips_active(pset));
677
678 ipc_pset_destroy(pset); /* consumes ref, unlocks */
679 break;
680 }
681
682 case MACH_PORT_TYPE_SEND:
683 case MACH_PORT_TYPE_RECEIVE:
684 case MACH_PORT_TYPE_SEND_RECEIVE:
685 case MACH_PORT_TYPE_SEND_ONCE: {
686 ipc_port_t port = (ipc_port_t) entry->ie_object;
687 ipc_port_t nsrequest = IP_NULL;
688 mach_port_mscount_t mscount = 0;
689 ipc_port_t dnrequest;
690
691 assert(port != IP_NULL);
692
693 if (type == MACH_PORT_TYPE_SEND)
694 ipc_hash_delete(space, (ipc_object_t) port,
695 name, entry);
696
697 ip_lock(port);
698
699 if (!ip_active(port)) {
700 assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
701 ip_release(port);
702 ip_check_unlock(port);
703
704 entry->ie_request = 0;
705 entry->ie_object = IO_NULL;
706 ipc_entry_dealloc(space, name, entry);
707
708 break;
709 }
710
711 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
712
713 entry->ie_object = IO_NULL;
714 ipc_entry_dealloc(space, name, entry);
715
716 if (type & MACH_PORT_TYPE_SEND) {
717 assert(port->ip_srights > 0);
718 if (--port->ip_srights == 0) {
719 nsrequest = port->ip_nsrequest;
720 if (nsrequest != IP_NULL) {
721 port->ip_nsrequest = IP_NULL;
722 mscount = port->ip_mscount;
723 }
724 }
725 }
726
727 if (type & MACH_PORT_TYPE_RECEIVE) {
728 assert(ip_active(port));
729 assert(port->ip_receiver == space);
730
731 ipc_port_clear_receiver(port);
732 ipc_port_destroy(port); /* consumes our ref, unlocks */
733 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
734 assert(port->ip_sorights > 0);
735 ip_unlock(port);
736
737 ipc_notify_send_once(port); /* consumes our ref */
738 } else {
739 assert(port->ip_receiver != space);
740
741 ip_release(port);
742 ip_unlock(port);
743 }
744
745 if (nsrequest != IP_NULL)
746 ipc_notify_no_senders(nsrequest, mscount);
747
748 if (dnrequest != IP_NULL)
749 ipc_notify_port_deleted(dnrequest, name);
750 break;
751 }
752
753 default:
754 panic("ipc_right_destroy: strange type");
755 }
756
757 return KERN_SUCCESS;
758 }
759
760 /*
761 * Routine: ipc_right_dealloc
762 * Purpose:
763 * Releases a send/send-once/dead-name user ref.
764 * Like ipc_right_delta with a delta of -1,
765 * but looks at the entry to determine the right.
766 * Conditions:
767 * The space is write-locked, and is unlocked upon return.
768 * The space must be active.
769 * Returns:
770 * KERN_SUCCESS A user ref was released.
771 * KERN_INVALID_RIGHT Entry has wrong type.
772 */
773
774 kern_return_t
775 ipc_right_dealloc(
776 ipc_space_t space,
777 mach_port_name_t name,
778 ipc_entry_t entry)
779 {
780
781 ipc_entry_bits_t bits;
782 mach_port_type_t type;
783
784 bits = entry->ie_bits;
785 type = IE_BITS_TYPE(bits);
786
787
788 assert(space->is_active);
789
790 switch (type) {
791 case MACH_PORT_TYPE_DEAD_NAME: {
792 dead_name:
793
794 assert(IE_BITS_UREFS(bits) > 0);
795 assert(entry->ie_request == 0);
796 assert(entry->ie_object == IO_NULL);
797
798 if (IE_BITS_UREFS(bits) == 1) {
799 ipc_entry_dealloc(space, name, entry);
800 }
801 else
802 entry->ie_bits = bits-1; /* decrement urefs */
803
804 is_write_unlock(space);
805 break;
806 }
807
808 case MACH_PORT_TYPE_SEND_ONCE: {
809 ipc_port_t port, dnrequest;
810
811 assert(IE_BITS_UREFS(bits) == 1);
812
813 port = (ipc_port_t) entry->ie_object;
814 assert(port != IP_NULL);
815
816 if (ipc_right_check(space, port, name, entry)) {
817
818 bits = entry->ie_bits;
819 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
820 goto dead_name;
821 }
822 /* port is locked and active */
823
824 assert(port->ip_sorights > 0);
825
826 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
827 ip_unlock(port);
828
829 entry->ie_object = IO_NULL;
830 ipc_entry_dealloc(space, name, entry);
831
832 is_write_unlock(space);
833
834 ipc_notify_send_once(port);
835
836 if (dnrequest != IP_NULL)
837 ipc_notify_port_deleted(dnrequest, name);
838 break;
839 }
840
841 case MACH_PORT_TYPE_SEND: {
842 ipc_port_t port;
843 ipc_port_t dnrequest = IP_NULL;
844 ipc_port_t nsrequest = IP_NULL;
845 mach_port_mscount_t mscount = 0;
846
847
848 assert(IE_BITS_UREFS(bits) > 0);
849
850 port = (ipc_port_t) entry->ie_object;
851 assert(port != IP_NULL);
852
853 if (ipc_right_check(space, port, name, entry)) {
854 bits = entry->ie_bits;
855 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
856 goto dead_name;
857 }
858 /* port is locked and active */
859
860 assert(port->ip_srights > 0);
861
862 if (IE_BITS_UREFS(bits) == 1) {
863 if (--port->ip_srights == 0) {
864 nsrequest = port->ip_nsrequest;
865 if (nsrequest != IP_NULL) {
866 port->ip_nsrequest = IP_NULL;
867 mscount = port->ip_mscount;
868 }
869 }
870
871 dnrequest = ipc_right_dncancel_macro(space, port,
872 name, entry);
873 ipc_hash_delete(space, (ipc_object_t) port,
874 name, entry);
875
876 ip_release(port);
877 entry->ie_object = IO_NULL;
878 ipc_entry_dealloc(space, name, entry);
879
880 } else
881 entry->ie_bits = bits-1; /* decrement urefs */
882
883 /* even if dropped a ref, port is active */
884 ip_unlock(port);
885 is_write_unlock(space);
886
887 if (nsrequest != IP_NULL)
888 ipc_notify_no_senders(nsrequest, mscount);
889
890 if (dnrequest != IP_NULL)
891 ipc_notify_port_deleted(dnrequest, name);
892 break;
893 }
894
895 case MACH_PORT_TYPE_SEND_RECEIVE: {
896 ipc_port_t port;
897 ipc_port_t nsrequest = IP_NULL;
898 mach_port_mscount_t mscount = 0;
899
900 assert(IE_BITS_UREFS(bits) > 0);
901
902 port = (ipc_port_t) entry->ie_object;
903 assert(port != IP_NULL);
904
905 ip_lock(port);
906 assert(ip_active(port));
907 assert(port->ip_receiver_name == name);
908 assert(port->ip_receiver == space);
909 assert(port->ip_srights > 0);
910
911 if (IE_BITS_UREFS(bits) == 1) {
912 if (--port->ip_srights == 0) {
913 nsrequest = port->ip_nsrequest;
914 if (nsrequest != IP_NULL) {
915 port->ip_nsrequest = IP_NULL;
916 mscount = port->ip_mscount;
917 }
918 }
919
920 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK |
921 MACH_PORT_TYPE_SEND);
922 } else
923 entry->ie_bits = bits-1; /* decrement urefs */
924
925 ip_unlock(port);
926 is_write_unlock(space);
927
928 if (nsrequest != IP_NULL)
929 ipc_notify_no_senders(nsrequest, mscount);
930 break;
931 }
932
933 default:
934 is_write_unlock(space);
935 return KERN_INVALID_RIGHT;
936 }
937
938 return KERN_SUCCESS;
939 }
940
941 /*
942 * Routine: ipc_right_delta
943 * Purpose:
944 * Modifies the user-reference count for a right.
945 * May deallocate the right, if the count goes to zero.
946 * Conditions:
947 * The space is write-locked, and is unlocked upon return.
948 * The space must be active.
949 * Returns:
950 * KERN_SUCCESS Count was modified.
951 * KERN_INVALID_RIGHT Entry has wrong type.
952 * KERN_INVALID_VALUE Bad delta for the right.
953 * KERN_UREFS_OVERFLOW OK delta, except would overflow.
954 */
955
956 kern_return_t
957 ipc_right_delta(
958 ipc_space_t space,
959 mach_port_name_t name,
960 ipc_entry_t entry,
961 mach_port_right_t right,
962 mach_port_delta_t delta)
963 {
964 ipc_entry_bits_t bits;
965
966 bits = entry->ie_bits;
967
968
969 /*
970 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
971 * switch below. It is used to keep track of those cases (in DIPC)
972 * where we have postponed the dropping of a port reference. Since
973 * the dropping of the reference could cause the port to disappear
974 * we postpone doing so when we are holding the space lock.
975 */
976
977 assert(space->is_active);
978 assert(right < MACH_PORT_RIGHT_NUMBER);
979
980 /* Rights-specific restrictions and operations. */
981
982 switch (right) {
983 case MACH_PORT_RIGHT_PORT_SET: {
984 ipc_pset_t pset;
985
986 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
987 goto invalid_right;
988
989 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
990 assert(IE_BITS_UREFS(bits) == 0);
991 assert(entry->ie_request == 0);
992
993 if (delta == 0)
994 goto success;
995
996 if (delta != -1)
997 goto invalid_value;
998
999 pset = (ipc_pset_t) entry->ie_object;
1000 assert(pset != IPS_NULL);
1001
1002
1003
1004 entry->ie_object = IO_NULL;
1005 ipc_entry_dealloc(space, name, entry);
1006
1007
1008 ips_lock(pset);
1009 assert(ips_active(pset));
1010 is_write_unlock(space);
1011
1012 ipc_pset_destroy(pset); /* consumes ref, unlocks */
1013 break;
1014 }
1015
1016 case MACH_PORT_RIGHT_RECEIVE: {
1017 ipc_port_t port;
1018 ipc_port_t dnrequest = IP_NULL;
1019
1020 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1021 goto invalid_right;
1022
1023 if (delta == 0)
1024 goto success;
1025
1026 if (delta != -1)
1027 goto invalid_value;
1028
1029 port = (ipc_port_t) entry->ie_object;
1030 assert(port != IP_NULL);
1031
1032 /*
1033 * The port lock is needed for ipc_right_dncancel;
1034 * otherwise, we wouldn't have to take the lock
1035 * until just before dropping the space lock.
1036 */
1037
1038 ip_lock(port);
1039 assert(ip_active(port));
1040 assert(port->ip_receiver_name == name);
1041 assert(port->ip_receiver == space);
1042
1043 if (bits & MACH_PORT_TYPE_SEND) {
1044 assert(IE_BITS_TYPE(bits) ==
1045 MACH_PORT_TYPE_SEND_RECEIVE);
1046 assert(IE_BITS_UREFS(bits) > 0);
1047 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1048 assert(port->ip_srights > 0);
1049
1050 /*
1051 * The remaining send right turns into a
1052 * dead name. Notice we don't decrement
1053 * ip_srights, generate a no-senders notif,
1054 * or use ipc_right_dncancel, because the
1055 * port is destroyed "first".
1056 */
1057 bits &= ~IE_BITS_TYPE_MASK;
1058 bits |= MACH_PORT_TYPE_DEAD_NAME;
1059 if (entry->ie_request) {
1060 entry->ie_request = 0;
1061 bits++;
1062 }
1063 entry->ie_bits = bits;
1064 entry->ie_object = IO_NULL;
1065 } else {
1066 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1067 assert(IE_BITS_UREFS(bits) == 0);
1068
1069 dnrequest = ipc_right_dncancel_macro(space, port,
1070 name, entry);
1071 entry->ie_object = IO_NULL;
1072 ipc_entry_dealloc(space, name, entry);
1073 }
1074 is_write_unlock(space);
1075
1076 ipc_port_clear_receiver(port);
1077 ipc_port_destroy(port); /* consumes ref, unlocks */
1078
1079 if (dnrequest != IP_NULL)
1080 ipc_notify_port_deleted(dnrequest, name);
1081 break;
1082 }
1083
1084 case MACH_PORT_RIGHT_SEND_ONCE: {
1085 ipc_port_t port, dnrequest;
1086
1087 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1088 goto invalid_right;
1089
1090 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1091 assert(IE_BITS_UREFS(bits) == 1);
1092
1093 port = (ipc_port_t) entry->ie_object;
1094 assert(port != IP_NULL);
1095
1096 if (ipc_right_check(space, port, name, entry)) {
1097 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1098 goto invalid_right;
1099 }
1100 /* port is locked and active */
1101
1102 assert(port->ip_sorights > 0);
1103
1104 if ((delta > 0) || (delta < -1)) {
1105 ip_unlock(port);
1106 goto invalid_value;
1107 }
1108
1109 if (delta == 0) {
1110 ip_unlock(port);
1111 goto success;
1112 }
1113
1114 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1115 ip_unlock(port);
1116
1117 entry->ie_object = IO_NULL;
1118 ipc_entry_dealloc(space, name, entry);
1119
1120 is_write_unlock(space);
1121
1122 ipc_notify_send_once(port);
1123
1124 if (dnrequest != IP_NULL)
1125 ipc_notify_port_deleted(dnrequest, name);
1126 break;
1127 }
1128
1129 case MACH_PORT_RIGHT_DEAD_NAME: {
1130 mach_port_urefs_t urefs;
1131
1132 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1133 ipc_port_t port;
1134
1135 port = (ipc_port_t) entry->ie_object;
1136 assert(port != IP_NULL);
1137
1138 if (!ipc_right_check(space, port, name, entry)) {
1139 /* port is locked and active */
1140 ip_unlock(port);
1141 goto invalid_right;
1142 }
1143 bits = entry->ie_bits;
1144 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1145 goto invalid_right;
1146
1147 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1148 assert(IE_BITS_UREFS(bits) > 0);
1149 assert(entry->ie_object == IO_NULL);
1150 assert(entry->ie_request == 0);
1151
1152 urefs = IE_BITS_UREFS(bits);
1153 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1154 goto invalid_value;
1155 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1156 goto urefs_overflow;
1157
1158 if ((urefs + delta) == 0) {
1159 ipc_entry_dealloc(space, name, entry);
1160 }
1161 else
1162 entry->ie_bits = bits + delta;
1163
1164 is_write_unlock(space);
1165
1166 break;
1167 }
1168
1169 case MACH_PORT_RIGHT_SEND: {
1170 mach_port_urefs_t urefs;
1171 ipc_port_t port;
1172 ipc_port_t dnrequest = IP_NULL;
1173 ipc_port_t nsrequest = IP_NULL;
1174 mach_port_mscount_t mscount = 0;
1175
1176 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1177 goto invalid_right;
1178
1179 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1180
1181 port = (ipc_port_t) entry->ie_object;
1182 assert(port != IP_NULL);
1183
1184 if (ipc_right_check(space, port, name, entry)) {
1185 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1186 goto invalid_right;
1187 }
1188 /* port is locked and active */
1189
1190 assert(port->ip_srights > 0);
1191
1192 urefs = IE_BITS_UREFS(bits);
1193 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1194 ip_unlock(port);
1195 goto invalid_value;
1196 }
1197 if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
1198 ip_unlock(port);
1199 goto urefs_overflow;
1200 }
1201
1202 if ((urefs + delta) == 0) {
1203 if (--port->ip_srights == 0) {
1204 nsrequest = port->ip_nsrequest;
1205 if (nsrequest != IP_NULL) {
1206 port->ip_nsrequest = IP_NULL;
1207 mscount = port->ip_mscount;
1208 }
1209 }
1210
1211 if (bits & MACH_PORT_TYPE_RECEIVE) {
1212 assert(port->ip_receiver_name == name);
1213 assert(port->ip_receiver == space);
1214 assert(IE_BITS_TYPE(bits) ==
1215 MACH_PORT_TYPE_SEND_RECEIVE);
1216
1217 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1218 MACH_PORT_TYPE_SEND);
1219 } else {
1220 assert(IE_BITS_TYPE(bits) ==
1221 MACH_PORT_TYPE_SEND);
1222
1223 dnrequest = ipc_right_dncancel_macro(space, port,
1224 name, entry);
1225 ipc_hash_delete(space, (ipc_object_t) port,
1226 name, entry);
1227
1228 ip_release(port);
1229
1230 entry->ie_object = IO_NULL;
1231 ipc_entry_dealloc(space, name, entry);
1232 }
1233 } else
1234 entry->ie_bits = bits + delta;
1235
1236 /* even if dropped a ref, port is active */
1237 ip_unlock(port);
1238 is_write_unlock(space);
1239
1240 if (nsrequest != IP_NULL)
1241 ipc_notify_no_senders(nsrequest, mscount);
1242
1243 if (dnrequest != IP_NULL)
1244 ipc_notify_port_deleted(dnrequest, name);
1245 break;
1246 }
1247
1248 default:
1249 panic("ipc_right_delta: strange right");
1250 }
1251
1252 return KERN_SUCCESS;
1253
1254 success:
1255 is_write_unlock(space);
1256 return KERN_SUCCESS;
1257
1258 invalid_right:
1259 is_write_unlock(space);
1260 return KERN_INVALID_RIGHT;
1261
1262 invalid_value:
1263 is_write_unlock(space);
1264 return KERN_INVALID_VALUE;
1265
1266 urefs_overflow:
1267 is_write_unlock(space);
1268 return KERN_UREFS_OVERFLOW;
1269 }
1270
1271 /*
1272 * Routine: ipc_right_info
1273 * Purpose:
1274 * Retrieves information about the right.
1275 * Conditions:
1276 * The space is write-locked, and is unlocked upon return
1277 * if the call is unsuccessful. The space must be active.
1278 * Returns:
1279 * KERN_SUCCESS Retrieved info; space still locked.
1280 */
1281
1282 kern_return_t
1283 ipc_right_info(
1284 ipc_space_t space,
1285 mach_port_name_t name,
1286 ipc_entry_t entry,
1287 mach_port_type_t *typep,
1288 mach_port_urefs_t *urefsp)
1289 {
1290 ipc_entry_bits_t bits;
1291 mach_port_type_t type;
1292 ipc_port_request_index_t request;
1293
1294 bits = entry->ie_bits;
1295
1296 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1297 ipc_port_t port = (ipc_port_t) entry->ie_object;
1298
1299 if (ipc_right_check(space, port, name, entry)) {
1300 bits = entry->ie_bits;
1301 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1302 } else
1303 ip_unlock(port);
1304 }
1305
1306 type = IE_BITS_TYPE(bits);
1307 request = entry->ie_request;
1308
1309 if (request != 0)
1310 type |= MACH_PORT_TYPE_DNREQUEST;
1311
1312 *typep = type;
1313 *urefsp = IE_BITS_UREFS(bits);
1314 return KERN_SUCCESS;
1315 }
1316
1317 /*
1318 * Routine: ipc_right_copyin_check
1319 * Purpose:
1320 * Check if a subsequent ipc_right_copyin would succeed.
1321 * Conditions:
1322 * The space is locked (read or write) and active.
1323 */
1324
1325 boolean_t
1326 ipc_right_copyin_check(
1327 __assert_only ipc_space_t space,
1328 __unused mach_port_name_t name,
1329 ipc_entry_t entry,
1330 mach_msg_type_name_t msgt_name)
1331 {
1332 ipc_entry_bits_t bits;
1333 ipc_port_t port;
1334 #if CONFIG_MACF_MACH
1335 task_t self = current_task();
1336 int rc = 0;
1337 #endif
1338
1339 bits= entry->ie_bits;
1340 assert(space->is_active);
1341
1342 switch (msgt_name) {
1343 case MACH_MSG_TYPE_MAKE_SEND:
1344 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1345 return FALSE;
1346
1347 #if CONFIG_MACF_MACH
1348 port = (ipc_port_t) entry->ie_object;
1349 ip_lock(port);
1350 tasklabel_lock(self);
1351 rc = mac_port_check_make_send(&self->maclabel, &port->ip_label); tasklabel_unlock(self);
1352 ip_unlock(port);
1353 if (rc)
1354 return FALSE;
1355 #endif
1356 break;
1357
1358 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1359 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1360 return FALSE;
1361
1362 #if CONFIG_MACF_MACH
1363 port = (ipc_port_t) entry->ie_object;
1364 ip_lock(port);
1365 tasklabel_lock(self);
1366 rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1367 tasklabel_unlock(self);
1368 ip_unlock(port);
1369 if (rc)
1370 return FALSE;
1371 #endif
1372 break;
1373
1374 case MACH_MSG_TYPE_MOVE_RECEIVE:
1375 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1376 return FALSE;
1377
1378 #if CONFIG_MACF_MACH
1379 port = (ipc_port_t) entry->ie_object;
1380 ip_lock(port);
1381 tasklabel_lock(self);
1382 rc = mac_port_check_move_receive(&self->maclabel, &port->ip_label);
1383 tasklabel_unlock(self);
1384 ip_unlock(port);
1385 if (rc)
1386 return FALSE;
1387 #endif
1388 break;
1389
1390 case MACH_MSG_TYPE_COPY_SEND:
1391 case MACH_MSG_TYPE_MOVE_SEND:
1392 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1393 boolean_t active;
1394
1395 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1396 break;
1397
1398 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1399 return FALSE;
1400
1401 port = (ipc_port_t) entry->ie_object;
1402 assert(port != IP_NULL);
1403
1404 ip_lock(port);
1405 active = ip_active(port);
1406 #if CONFIG_MACF_MACH
1407 tasklabel_lock(self);
1408 switch (msgt_name) {
1409 case MACH_MSG_TYPE_COPY_SEND:
1410 rc = mac_port_check_copy_send(&self->maclabel,
1411 &port->ip_label);
1412 break;
1413 case MACH_MSG_TYPE_MOVE_SEND:
1414 rc = mac_port_check_move_send(&self->maclabel,
1415 &port->ip_label);
1416 break;
1417 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
1418 rc = mac_port_check_move_send_once(&self->maclabel,
1419 &port->ip_label);
1420 break;
1421 default:
1422 panic("ipc_right_copyin_check: strange rights");
1423 }
1424 tasklabel_unlock(self);
1425 if (rc) {
1426 ip_unlock(port);
1427 return FALSE;
1428 }
1429 #endif
1430 ip_unlock(port);
1431
1432 if (!active) {
1433 break;
1434 }
1435
1436 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1437 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1438 return FALSE;
1439 } else {
1440 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1441 return FALSE;
1442 }
1443
1444 break;
1445 }
1446
1447 default:
1448 panic("ipc_right_copyin_check: strange rights");
1449 }
1450
1451 return TRUE;
1452 }
1453
1454 /*
1455 * Routine: ipc_right_copyin
1456 * Purpose:
1457 * Copyin a capability from a space.
1458 * If successful, the caller gets a ref
1459 * for the resulting object, unless it is IO_DEAD,
1460 * and possibly a send-once right which should
1461 * be used in a port-deleted notification.
1462 *
1463 * If deadok is not TRUE, the copyin operation
1464 * will fail instead of producing IO_DEAD.
1465 *
1466 * The entry is never deallocated (except
1467 * when KERN_INVALID_NAME), so the caller
1468 * should deallocate the entry if its type
1469 * is MACH_PORT_TYPE_NONE.
1470 * Conditions:
1471 * The space is write-locked and active.
1472 * Returns:
1473 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1474 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1475 */
1476
1477 kern_return_t
1478 ipc_right_copyin(
1479 ipc_space_t space,
1480 mach_port_name_t name,
1481 ipc_entry_t entry,
1482 mach_msg_type_name_t msgt_name,
1483 boolean_t deadok,
1484 ipc_object_t *objectp,
1485 ipc_port_t *sorightp)
1486 {
1487 ipc_entry_bits_t bits;
1488 #if CONFIG_MACF_MACH
1489 task_t self = current_task();
1490 int rc;
1491 #endif
1492
1493 bits = entry->ie_bits;
1494
1495 assert(space->is_active);
1496
1497 switch (msgt_name) {
1498 case MACH_MSG_TYPE_MAKE_SEND: {
1499 ipc_port_t port;
1500
1501 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1502 goto invalid_right;
1503
1504 port = (ipc_port_t) entry->ie_object;
1505 assert(port != IP_NULL);
1506
1507 ip_lock(port);
1508 assert(ip_active(port));
1509 assert(port->ip_receiver_name == name);
1510 assert(port->ip_receiver == space);
1511
1512 #if CONFIG_MACF_MACH
1513 tasklabel_lock(self);
1514 rc = mac_port_check_make_send(&self->maclabel, &port->ip_label);
1515 tasklabel_unlock(self);
1516 if (rc) {
1517 ip_unlock(port);
1518 return KERN_NO_ACCESS;
1519 }
1520 #endif
1521
1522 port->ip_mscount++;
1523 port->ip_srights++;
1524 ip_reference(port);
1525 ip_unlock(port);
1526
1527 *objectp = (ipc_object_t) port;
1528 *sorightp = IP_NULL;
1529 break;
1530 }
1531
1532 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1533 ipc_port_t port;
1534
1535 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1536 goto invalid_right;
1537
1538 port = (ipc_port_t) entry->ie_object;
1539 assert(port != IP_NULL);
1540
1541 ip_lock(port);
1542 assert(ip_active(port));
1543 assert(port->ip_receiver_name == name);
1544 assert(port->ip_receiver == space);
1545
1546 #if CONFIG_MACF_MACH
1547 tasklabel_lock(self);
1548 rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label);
1549 tasklabel_unlock(self);
1550 if (rc) {
1551 ip_unlock(port);
1552 return KERN_NO_ACCESS;
1553 }
1554 #endif
1555
1556 port->ip_sorights++;
1557 ip_reference(port);
1558 ip_unlock(port);
1559
1560 *objectp = (ipc_object_t) port;
1561 *sorightp = IP_NULL;
1562 break;
1563 }
1564
1565 case MACH_MSG_TYPE_MOVE_RECEIVE: {
1566 ipc_port_t port;
1567 ipc_port_t dnrequest = IP_NULL;
1568
1569 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1570 goto invalid_right;
1571
1572 port = (ipc_port_t) entry->ie_object;
1573 assert(port != IP_NULL);
1574
1575 ip_lock(port);
1576 assert(ip_active(port));
1577 assert(port->ip_receiver_name == name);
1578 assert(port->ip_receiver == space);
1579
1580 #if CONFIG_MACF_MACH
1581 tasklabel_lock(self);
1582 rc = mac_port_check_move_receive(&self->maclabel,
1583 &port->ip_label);
1584 tasklabel_unlock(self);
1585 if (rc) {
1586 ip_unlock(port);
1587 return KERN_NO_ACCESS;
1588 }
1589 #endif
1590
1591 if (bits & MACH_PORT_TYPE_SEND) {
1592 assert(IE_BITS_TYPE(bits) ==
1593 MACH_PORT_TYPE_SEND_RECEIVE);
1594 assert(IE_BITS_UREFS(bits) > 0);
1595 assert(port->ip_srights > 0);
1596
1597 ipc_hash_insert(space, (ipc_object_t) port,
1598 name, entry);
1599 ip_reference(port);
1600 } else {
1601 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1602 assert(IE_BITS_UREFS(bits) == 0);
1603
1604 dnrequest = ipc_right_dncancel_macro(space, port,
1605 name, entry);
1606 entry->ie_object = IO_NULL;
1607 }
1608 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1609
1610 ipc_port_clear_receiver(port);
1611
1612 port->ip_receiver_name = MACH_PORT_NULL;
1613 port->ip_destination = IP_NULL;
1614 ip_unlock(port);
1615
1616 *objectp = (ipc_object_t) port;
1617 *sorightp = dnrequest;
1618 break;
1619 }
1620
1621 case MACH_MSG_TYPE_COPY_SEND: {
1622 ipc_port_t port;
1623
1624 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1625 goto copy_dead;
1626
1627 /* allow for dead send-once rights */
1628
1629 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1630 goto invalid_right;
1631
1632 assert(IE_BITS_UREFS(bits) > 0);
1633
1634 port = (ipc_port_t) entry->ie_object;
1635 assert(port != IP_NULL);
1636
1637 if (ipc_right_check(space, port, name, entry)) {
1638 bits = entry->ie_bits;
1639 goto copy_dead;
1640 }
1641 /* port is locked and active */
1642
1643 #if CONFIG_MACF_MACH
1644 tasklabel_lock(self);
1645 rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
1646 tasklabel_unlock(self);
1647 if (rc) {
1648 ip_unlock(port);
1649 return KERN_NO_ACCESS;
1650 }
1651 #endif
1652
1653 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1654 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1655 assert(port->ip_sorights > 0);
1656
1657 ip_unlock(port);
1658 goto invalid_right;
1659 }
1660
1661 assert(port->ip_srights > 0);
1662
1663 port->ip_srights++;
1664 ip_reference(port);
1665 ip_unlock(port);
1666
1667 *objectp = (ipc_object_t) port;
1668 *sorightp = IP_NULL;
1669 break;
1670 }
1671
1672 case MACH_MSG_TYPE_MOVE_SEND: {
1673 ipc_port_t port;
1674 ipc_port_t dnrequest = IP_NULL;
1675
1676 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1677 goto move_dead;
1678
1679 /* allow for dead send-once rights */
1680
1681 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1682 goto invalid_right;
1683
1684 assert(IE_BITS_UREFS(bits) > 0);
1685
1686 port = (ipc_port_t) entry->ie_object;
1687 assert(port != IP_NULL);
1688
1689 if (ipc_right_check(space, port, name, entry)) {
1690 bits = entry->ie_bits;
1691 goto move_dead;
1692 }
1693 /* port is locked and active */
1694
1695 #if CONFIG_MACF_MACH
1696 tasklabel_lock (self);
1697 rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
1698 tasklabel_unlock (self);
1699 if (rc)
1700 {
1701 ip_unlock (port);
1702 return KERN_NO_ACCESS;
1703 }
1704 #endif
1705
1706 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1707 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1708 assert(port->ip_sorights > 0);
1709
1710 ip_unlock(port);
1711 goto invalid_right;
1712 }
1713
1714 assert(port->ip_srights > 0);
1715
1716 if (IE_BITS_UREFS(bits) == 1) {
1717 if (bits & MACH_PORT_TYPE_RECEIVE) {
1718 assert(port->ip_receiver_name == name);
1719 assert(port->ip_receiver == space);
1720 assert(IE_BITS_TYPE(bits) ==
1721 MACH_PORT_TYPE_SEND_RECEIVE);
1722
1723 ip_reference(port);
1724 } else {
1725 assert(IE_BITS_TYPE(bits) ==
1726 MACH_PORT_TYPE_SEND);
1727
1728 dnrequest = ipc_right_dncancel_macro(space, port,
1729 name, entry);
1730 ipc_hash_delete(space, (ipc_object_t) port,
1731 name, entry);
1732 entry->ie_object = IO_NULL;
1733 }
1734 entry->ie_bits = bits &~
1735 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1736 } else {
1737 port->ip_srights++;
1738 ip_reference(port);
1739 entry->ie_bits = bits-1; /* decrement urefs */
1740 }
1741
1742 ip_unlock(port);
1743
1744 *objectp = (ipc_object_t) port;
1745 *sorightp = dnrequest;
1746 break;
1747 }
1748
1749 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1750 ipc_port_t port;
1751 ipc_port_t dnrequest;
1752
1753 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1754 goto move_dead;
1755
1756 /* allow for dead send rights */
1757
1758 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1759 goto invalid_right;
1760
1761 assert(IE_BITS_UREFS(bits) > 0);
1762
1763 port = (ipc_port_t) entry->ie_object;
1764 assert(port != IP_NULL);
1765
1766 if (ipc_right_check(space, port, name, entry)) {
1767 bits = entry->ie_bits;
1768 goto move_dead;
1769 }
1770 /* port is locked and active */
1771
1772 #if CONFIG_MACF_MACH
1773 tasklabel_lock (self);
1774 rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label);
1775 tasklabel_unlock (self);
1776 if (rc)
1777 {
1778 ip_unlock (port);
1779 return KERN_NO_ACCESS;
1780 }
1781 #endif
1782
1783 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1784 assert(bits & MACH_PORT_TYPE_SEND);
1785 assert(port->ip_srights > 0);
1786
1787 ip_unlock(port);
1788 goto invalid_right;
1789 }
1790
1791 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1792 assert(IE_BITS_UREFS(bits) == 1);
1793 assert(port->ip_sorights > 0);
1794
1795 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1796 ip_unlock(port);
1797
1798 entry->ie_object = IO_NULL;
1799 entry->ie_bits = bits &~
1800 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
1801
1802 *objectp = (ipc_object_t) port;
1803 *sorightp = dnrequest;
1804 break;
1805 }
1806
1807 default:
1808 invalid_right:
1809 return KERN_INVALID_RIGHT;
1810 }
1811
1812 return KERN_SUCCESS;
1813
1814 copy_dead:
1815 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1816 assert(IE_BITS_UREFS(bits) > 0);
1817 assert(entry->ie_request == 0);
1818 assert(entry->ie_object == 0);
1819
1820 if (!deadok)
1821 goto invalid_right;
1822
1823 *objectp = IO_DEAD;
1824 *sorightp = IP_NULL;
1825 return KERN_SUCCESS;
1826
1827 move_dead:
1828 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1829 assert(IE_BITS_UREFS(bits) > 0);
1830 assert(entry->ie_request == 0);
1831 assert(entry->ie_object == 0);
1832
1833 if (!deadok)
1834 goto invalid_right;
1835
1836 if (IE_BITS_UREFS(bits) == 1) {
1837 bits &= ~MACH_PORT_TYPE_DEAD_NAME;
1838 }
1839 entry->ie_bits = bits-1; /* decrement urefs */
1840
1841 *objectp = IO_DEAD;
1842 *sorightp = IP_NULL;
1843 return KERN_SUCCESS;
1844
1845 }
1846
1847 /*
1848 * Routine: ipc_right_copyin_undo
1849 * Purpose:
1850 * Undoes the effects of an ipc_right_copyin
1851 * of a send/send-once right that is dead.
1852 * (Object is either IO_DEAD or a dead port.)
1853 * Conditions:
1854 * The space is write-locked and active.
1855 */
1856
1857 void
1858 ipc_right_copyin_undo(
1859 ipc_space_t space,
1860 mach_port_name_t name,
1861 ipc_entry_t entry,
1862 mach_msg_type_name_t msgt_name,
1863 ipc_object_t object,
1864 ipc_port_t soright)
1865 {
1866 ipc_entry_bits_t bits;
1867
1868 bits = entry->ie_bits;
1869
1870 assert(space->is_active);
1871
1872 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1873 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
1874 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1875
1876 if (soright != IP_NULL) {
1877 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1878 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1879 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1880 assert(object != IO_DEAD);
1881
1882 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1883 MACH_PORT_TYPE_DEAD_NAME | 2);
1884
1885 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
1886 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1887 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1888
1889 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1890 MACH_PORT_TYPE_DEAD_NAME | 1);
1891 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
1892 assert(object == IO_DEAD);
1893 assert(IE_BITS_UREFS(bits) > 0);
1894
1895 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1896 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1897 entry->ie_bits = bits+1; /* increment urefs */
1898 }
1899 } else {
1900 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1901 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
1902 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1903 assert(object != IO_DEAD);
1904 assert(entry->ie_object == object);
1905 assert(IE_BITS_UREFS(bits) > 0);
1906
1907 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1908 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
1909 entry->ie_bits = bits+1; /* increment urefs */
1910 }
1911
1912 /*
1913 * May as well convert the entry to a dead name.
1914 * (Or if it is a compat entry, destroy it.)
1915 */
1916
1917 (void) ipc_right_check(space, (ipc_port_t) object,
1918 name, entry);
1919 /* object is dead so it is not locked */
1920 }
1921
1922 /* release the reference acquired by copyin */
1923
1924 if (object != IO_DEAD)
1925 ipc_object_release(object);
1926 }
1927
1928 /*
1929 * Routine: ipc_right_copyin_two
1930 * Purpose:
1931 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
1932 * and deadok == FALSE, except that this moves two
1933 * send rights at once.
1934 * Conditions:
1935 * The space is write-locked and active.
1936 * The object is returned with two refs/send rights.
1937 * Returns:
1938 * KERN_SUCCESS Acquired an object.
1939 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1940 */
1941
1942 kern_return_t
1943 ipc_right_copyin_two(
1944 ipc_space_t space,
1945 mach_port_name_t name,
1946 ipc_entry_t entry,
1947 ipc_object_t *objectp,
1948 ipc_port_t *sorightp)
1949 {
1950 ipc_entry_bits_t bits;
1951 mach_port_urefs_t urefs;
1952 ipc_port_t port;
1953 ipc_port_t dnrequest = IP_NULL;
1954 #if CONFIG_MACF_MACH
1955 task_t self = current_task();
1956 int rc;
1957 #endif
1958
1959 assert(space->is_active);
1960
1961 bits = entry->ie_bits;
1962
1963 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1964 goto invalid_right;
1965
1966 urefs = IE_BITS_UREFS(bits);
1967 if (urefs < 2)
1968 goto invalid_right;
1969
1970 port = (ipc_port_t) entry->ie_object;
1971 assert(port != IP_NULL);
1972
1973 if (ipc_right_check(space, port, name, entry)) {
1974 goto invalid_right;
1975 }
1976 /* port is locked and active */
1977
1978 #if CONFIG_MACF_MACH
1979 tasklabel_lock(self);
1980 rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label);
1981 tasklabel_unlock(self);
1982 if (rc) {
1983 ip_unlock(port);
1984 return KERN_NO_ACCESS;
1985 }
1986 #endif
1987
1988 assert(port->ip_srights > 0);
1989
1990 if (urefs == 2) {
1991 if (bits & MACH_PORT_TYPE_RECEIVE) {
1992 assert(port->ip_receiver_name == name);
1993 assert(port->ip_receiver == space);
1994 assert(IE_BITS_TYPE(bits) ==
1995 MACH_PORT_TYPE_SEND_RECEIVE);
1996
1997 port->ip_srights++;
1998 ip_reference(port);
1999 ip_reference(port);
2000 } else {
2001 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2002
2003 dnrequest = ipc_right_dncancel_macro(space, port,
2004 name, entry);
2005
2006 port->ip_srights++;
2007 ip_reference(port);
2008 ipc_hash_delete(space, (ipc_object_t) port,
2009 name, entry);
2010 entry->ie_object = IO_NULL;
2011 }
2012 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2013 } else {
2014 port->ip_srights += 2;
2015 ip_reference(port);
2016 ip_reference(port);
2017 entry->ie_bits = bits-2; /* decrement urefs */
2018 }
2019 ip_unlock(port);
2020
2021 *objectp = (ipc_object_t) port;
2022 *sorightp = dnrequest;
2023 return KERN_SUCCESS;
2024
2025 invalid_right:
2026 return KERN_INVALID_RIGHT;
2027 }
2028
2029 /*
2030 * Routine: ipc_right_copyout
2031 * Purpose:
2032 * Copyout a capability to a space.
2033 * If successful, consumes a ref for the object.
2034 *
2035 * Always succeeds when given a newly-allocated entry,
2036 * because user-reference overflow isn't a possibility.
2037 *
2038 * If copying out the object would cause the user-reference
2039 * count in the entry to overflow, and overflow is TRUE,
2040 * then instead the user-reference count is left pegged
2041 * to its maximum value and the copyout succeeds anyway.
2042 * Conditions:
2043 * The space is write-locked and active.
2044 * The object is locked and active.
2045 * The object is unlocked; the space isn't.
2046 * Returns:
2047 * KERN_SUCCESS Copied out capability.
2048 * KERN_UREFS_OVERFLOW User-refs would overflow;
2049 * guaranteed not to happen with a fresh entry
2050 * or if overflow=TRUE was specified.
2051 */
2052
2053 kern_return_t
2054 ipc_right_copyout(
2055 ipc_space_t space,
2056 mach_port_name_t name,
2057 ipc_entry_t entry,
2058 mach_msg_type_name_t msgt_name,
2059 boolean_t overflow,
2060 ipc_object_t object)
2061 {
2062 ipc_entry_bits_t bits;
2063 ipc_port_t port;
2064 #if CONFIG_MACF_MACH
2065 int rc;
2066 #endif
2067
2068 bits = entry->ie_bits;
2069
2070 assert(IO_VALID(object));
2071 assert(io_otype(object) == IOT_PORT);
2072 assert(io_active(object));
2073 assert(entry->ie_object == object);
2074
2075 port = (ipc_port_t) object;
2076
2077 switch (msgt_name) {
2078 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2079
2080 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2081 assert(port->ip_sorights > 0);
2082
2083 #if CONFIG_MACF_MACH
2084 if (space->is_task) {
2085 tasklabel_lock(space->is_task);
2086 rc = mac_port_check_hold_send_once(&space->is_task->maclabel,
2087 &port->ip_label);
2088 tasklabel_unlock(space->is_task);
2089
2090 if (rc) {
2091 ip_unlock(port);
2092 return KERN_NO_ACCESS;
2093 }
2094 }
2095 #endif
2096 /* transfer send-once right and ref to entry */
2097 ip_unlock(port);
2098
2099 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
2100 break;
2101
2102 case MACH_MSG_TYPE_PORT_SEND:
2103 assert(port->ip_srights > 0);
2104
2105 #if CONFIG_MACF_MACH
2106 if (space->is_task) {
2107 tasklabel_lock(space->is_task);
2108 rc = mac_port_check_hold_send(&space->is_task->maclabel,
2109 &port->ip_label);
2110 tasklabel_unlock(space->is_task);
2111
2112 if (rc) {
2113 ip_unlock(port);
2114 return KERN_NO_ACCESS;
2115 }
2116 }
2117 #endif
2118
2119 if (bits & MACH_PORT_TYPE_SEND) {
2120 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2121
2122 assert(port->ip_srights > 1);
2123 assert(urefs > 0);
2124 assert(urefs < MACH_PORT_UREFS_MAX);
2125
2126 if (urefs+1 == MACH_PORT_UREFS_MAX) {
2127 if (overflow) {
2128 /* leave urefs pegged to maximum */
2129
2130 port->ip_srights--;
2131 ip_release(port);
2132 ip_unlock(port);
2133 return KERN_SUCCESS;
2134 }
2135
2136 ip_unlock(port);
2137 return KERN_UREFS_OVERFLOW;
2138 }
2139
2140 port->ip_srights--;
2141 ip_release(port);
2142 ip_unlock(port);
2143 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2144 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2145 assert(IE_BITS_UREFS(bits) == 0);
2146
2147 /* transfer send right to entry */
2148 ip_release(port);
2149 ip_unlock(port);
2150 } else {
2151 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2152 assert(IE_BITS_UREFS(bits) == 0);
2153
2154 /* transfer send right and ref to entry */
2155 ip_unlock(port);
2156
2157 /* entry is locked holding ref, so can use port */
2158
2159 ipc_hash_insert(space, (ipc_object_t) port,
2160 name, entry);
2161 }
2162
2163 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
2164 break;
2165
2166 case MACH_MSG_TYPE_PORT_RECEIVE: {
2167 ipc_port_t dest;
2168
2169 assert(port->ip_mscount == 0);
2170 assert(port->ip_receiver_name == MACH_PORT_NULL);
2171 dest = port->ip_destination;
2172
2173 #if CONFIG_MACF_MACH
2174 if (space->is_task) {
2175 tasklabel_lock(space->is_task);
2176 rc = mac_port_check_hold_receive(&space->is_task->maclabel,
2177 &port->ip_label);
2178 tasklabel_unlock(space->is_task);
2179
2180 if (rc) {
2181 ip_unlock(port);
2182 return KERN_NO_ACCESS;
2183 }
2184 }
2185 #endif
2186
2187 port->ip_receiver_name = name;
2188 port->ip_receiver = space;
2189
2190 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2191
2192 if (bits & MACH_PORT_TYPE_SEND) {
2193 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2194 assert(IE_BITS_UREFS(bits) > 0);
2195 assert(port->ip_srights > 0);
2196
2197 ip_release(port);
2198 ip_unlock(port);
2199
2200 /* entry is locked holding ref, so can use port */
2201
2202 ipc_hash_delete(space, (ipc_object_t) port,
2203 name, entry);
2204 } else {
2205 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2206 assert(IE_BITS_UREFS(bits) == 0);
2207
2208 /* transfer ref to entry */
2209 ip_unlock(port);
2210 }
2211 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2212
2213 if (dest != IP_NULL)
2214 ipc_port_release(dest);
2215 break;
2216 }
2217
2218 default:
2219 panic("ipc_right_copyout: strange rights");
2220 }
2221
2222 return KERN_SUCCESS;
2223 }
2224
2225 /*
2226 * Routine: ipc_right_rename
2227 * Purpose:
2228 * Transfer an entry from one name to another.
2229 * The old entry is deallocated.
2230 * Conditions:
2231 * The space is write-locked and active.
2232 * The new entry is unused. Upon return,
2233 * the space is unlocked.
2234 * Returns:
2235 * KERN_SUCCESS Moved entry to new name.
2236 */
2237
2238 kern_return_t
2239 ipc_right_rename(
2240 ipc_space_t space,
2241 mach_port_name_t oname,
2242 ipc_entry_t oentry,
2243 mach_port_name_t nname,
2244 ipc_entry_t nentry)
2245 {
2246 ipc_port_request_index_t request = oentry->ie_request;
2247 ipc_entry_bits_t bits = oentry->ie_bits;
2248 ipc_object_t object = oentry->ie_object;
2249
2250 assert(space->is_active);
2251 assert(oname != nname);
2252
2253 /*
2254 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2255 * if the port is dead. (This would foil ipc_port_destroy.)
2256 * Instead we should fail because oentry shouldn't exist.
2257 * Note IE_BITS_COMPAT implies ie_request != 0.
2258 */
2259
2260 if (request != 0) {
2261 ipc_port_t port;
2262
2263 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2264 port = (ipc_port_t) object;
2265 assert(port != IP_NULL);
2266
2267 if (ipc_right_check(space, port, oname, oentry)) {
2268 request = 0;
2269 object = IO_NULL;
2270 bits = oentry->ie_bits;
2271 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2272 assert(oentry->ie_request == 0);
2273 } else {
2274 /* port is locked and active */
2275
2276 ipc_port_dnrename(port, request, oname, nname);
2277 ip_unlock(port);
2278 oentry->ie_request = 0;
2279 }
2280 }
2281
2282 /* initialize nentry before letting ipc_hash_insert see it */
2283
2284 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2285 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2286 nentry->ie_request = request;
2287 nentry->ie_object = object;
2288
2289 switch (IE_BITS_TYPE(bits)) {
2290 case MACH_PORT_TYPE_SEND: {
2291 ipc_port_t port;
2292
2293 port = (ipc_port_t) object;
2294 assert(port != IP_NULL);
2295
2296 /* remember, there are no other share entries possible */
2297 /* or we can't do the rename. Therefore we do not need */
2298 /* to check the other subspaces */
2299 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2300 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2301 break;
2302 }
2303
2304 case MACH_PORT_TYPE_RECEIVE:
2305 case MACH_PORT_TYPE_SEND_RECEIVE: {
2306 ipc_port_t port;
2307
2308 port = (ipc_port_t) object;
2309 assert(port != IP_NULL);
2310
2311 ip_lock(port);
2312 assert(ip_active(port));
2313 assert(port->ip_receiver_name == oname);
2314 assert(port->ip_receiver == space);
2315
2316 port->ip_receiver_name = nname;
2317 ip_unlock(port);
2318 break;
2319 }
2320
2321 case MACH_PORT_TYPE_PORT_SET: {
2322 ipc_pset_t pset;
2323
2324 pset = (ipc_pset_t) object;
2325 assert(pset != IPS_NULL);
2326
2327 ips_lock(pset);
2328 assert(ips_active(pset));
2329 assert(pset->ips_local_name == oname);
2330
2331 pset->ips_local_name = nname;
2332 ips_unlock(pset);
2333 break;
2334 }
2335
2336 case MACH_PORT_TYPE_SEND_ONCE:
2337 case MACH_PORT_TYPE_DEAD_NAME:
2338 break;
2339
2340 default:
2341 panic("ipc_right_rename: strange rights");
2342 }
2343
2344 assert(oentry->ie_request == 0);
2345 oentry->ie_object = IO_NULL;
2346 ipc_entry_dealloc(space, oname, oentry);
2347 is_write_unlock(space);
2348
2349 return KERN_SUCCESS;
2350 }