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