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