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