FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_right.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_right.c,v $
29 * Revision 2.9 93/11/17 17:01:15 dbg
30 * Added ANSI function prototypes.
31 * [93/09/23 dbg]
32 *
33 * Revision 2.8 92/08/03 17:35:25 jfriedl
34 * removed silly prototypes
35 * [92/08/02 jfriedl]
36 *
37 * Revision 2.7 92/05/21 17:11:29 jfriedl
38 * Added a few things to shut up gcc warnings.
39 * Also make correct case when assert is off.
40 * [92/05/16 jfriedl]
41 *
42 * Revision 2.6 91/05/14 16:36:12 mrt
43 * Correcting copyright
44 *
45 * Revision 2.5 91/02/14 14:08:29 mrt
46 * Fixed bug in ipc_right_copyin_check, following rchen's report.
47 * [91/01/26 rpd]
48 *
49 * Revision 2.4 91/02/05 17:23:26 mrt
50 * Changed to new Mach copyright
51 * [91/02/01 15:50:46 mrt]
52 *
53 * Revision 2.3 90/11/05 14:30:05 rpd
54 * Changed io_release to ipc_object_release.
55 * Changed ip_release to ipc_port_release.
56 * Use new ip_reference and ip_release.
57 * [90/10/29 rpd]
58 *
59 * Revision 2.2 90/06/02 14:51:28 rpd
60 * Created for new IPC.
61 * [90/03/26 21:02:31 rpd]
62 *
63 */
64 /*
65 * File: ipc/ipc_right.c
66 * Author: Rich Draves
67 * Date: 1989
68 *
69 * Functions to manipulate IPC capabilities.
70 */
71
72 #include <mach_ipc_compat.h>
73
74 #include <mach/boolean.h>
75 #include <mach/kern_return.h>
76 #include <mach/port.h>
77 #include <mach/message.h>
78 #include <kern/assert.h>
79 #include <ipc/port.h>
80 #include <ipc/ipc_entry.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_object.h>
83 #include <ipc/ipc_hash.h>
84 #include <ipc/ipc_port.h>
85 #include <ipc/ipc_pset.h>
86 #include <ipc/ipc_marequest.h>
87 #include <ipc/ipc_right.h>
88 #include <ipc/ipc_notify.h>
89
90
91
92 /*
93 * Routine: ipc_right_lookup_write
94 * Purpose:
95 * Finds an entry in a space, given the name.
96 * Conditions:
97 * Nothing locked. If successful, the space is write-locked.
98 * Returns:
99 * KERN_SUCCESS Found an entry.
100 * KERN_INVALID_TASK The space is dead.
101 * KERN_INVALID_NAME Name doesn't exist in space.
102 */
103
104 kern_return_t
105 ipc_right_lookup_write(
106 ipc_space_t space,
107 mach_port_t name,
108 ipc_entry_t *entryp)
109 {
110 ipc_entry_t entry;
111
112 assert(space != IS_NULL);
113
114 is_write_lock(space);
115
116 if (!space->is_active) {
117 is_write_unlock(space);
118 return KERN_INVALID_TASK;
119 }
120
121 if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
122 is_write_unlock(space);
123 return KERN_INVALID_NAME;
124 }
125
126 *entryp = entry;
127 return KERN_SUCCESS;
128 }
129
130 /*
131 * Routine: ipc_right_reverse
132 * Purpose:
133 * Translate (space, object) -> (name, entry).
134 * Only finds send/receive rights.
135 * Returns TRUE if an entry is found; if so,
136 * the object is locked and active.
137 * Conditions:
138 * The space must be locked (read or write) and active.
139 * Nothing else locked.
140 */
141
142 boolean_t
143 ipc_right_reverse(
144 ipc_space_t space,
145 ipc_object_t object,
146 mach_port_t *namep,
147 ipc_entry_t *entryp)
148 {
149 ipc_port_t port;
150 mach_port_t name;
151 ipc_entry_t entry;
152
153 /* would switch on io_otype to handle multiple types of object */
154
155 assert(space->is_active);
156 assert(io_otype(object) == IOT_PORT);
157
158 port = (ipc_port_t) object;
159
160 ip_lock(port);
161 if (!ip_active(port)) {
162 ip_unlock(port);
163
164 return FALSE;
165 }
166
167 if (port->ip_receiver == space) {
168 name = port->ip_receiver_name;
169 assert(name != MACH_PORT_NULL);
170
171 entry = ipc_entry_lookup(space, name);
172
173 assert(entry != IE_NULL);
174 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
175 assert(port == (ipc_port_t) entry->ie_object);
176
177 *namep = name;
178 *entryp = entry;
179 return TRUE;
180 }
181
182 if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
183 assert((entry = *entryp) != IE_NULL);
184 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
185 assert(port == (ipc_port_t) entry->ie_object);
186
187 return TRUE;
188 }
189
190 ip_unlock(port);
191 return FALSE;
192 }
193
194 /*
195 * Routine: ipc_right_dnrequest
196 * Purpose:
197 * Make a dead-name request, returning the previously
198 * registered send-once right. If notify is IP_NULL,
199 * just cancels the previously registered request.
200 *
201 * This interacts with the IE_BITS_COMPAT, because they
202 * both use ie_request. If this is a compat entry, then
203 * previous always gets IP_NULL. If notify is IP_NULL,
204 * then the entry remains a compat entry. Otherwise
205 * the real dead-name request is registered and the entry
206 * is no longer a compat entry.
207 * Conditions:
208 * Nothing locked. May allocate memory.
209 * Only consumes/returns refs if successful.
210 * Returns:
211 * KERN_SUCCESS Made/canceled dead-name request.
212 * KERN_INVALID_TASK The space is dead.
213 * KERN_INVALID_NAME Name doesn't exist in space.
214 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights.
215 * KERN_INVALID_ARGUMENT Name denotes dead name, but
216 * immediate is FALSE or notify is IP_NULL.
217 * KERN_UREFS_OVERFLOW Name denotes dead name, but
218 * generating immediate notif. would overflow urefs.
219 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
220 */
221
222 kern_return_t
223 ipc_right_dnrequest(
224 ipc_space_t space,
225 mach_port_t name,
226 boolean_t immediate,
227 ipc_port_t notify,
228 ipc_port_t *previousp)
229 {
230 ipc_port_t previous;
231
232 for (;;) {
233 ipc_entry_t entry;
234 ipc_entry_bits_t bits;
235 kern_return_t kr;
236
237 kr = ipc_right_lookup_write(space, name, &entry);
238 if (kr != KERN_SUCCESS)
239 return kr;
240 /* space is write-locked and active */
241
242 bits = entry->ie_bits;
243 if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
244 ipc_port_t port;
245 ipc_port_request_index_t request;
246
247 port = (ipc_port_t) entry->ie_object;
248 assert(port != IP_NULL);
249
250 if (!ipc_right_check(space, port, name, entry)) {
251 /* port is locked and active */
252
253 if (notify == IP_NULL) {
254 #if MACH_IPC_COMPAT
255 if (bits & IE_BITS_COMPAT) {
256 assert(entry->ie_request != 0);
257
258 previous = IP_NULL;
259 } else
260 #endif /* MACH_IPC_COMPAT */
261 previous = ipc_right_dncancel_macro(
262 space, port, name, entry);
263
264 ip_unlock(port);
265 is_write_unlock(space);
266 break;
267 }
268
269 /*
270 * If a registered soright exists,
271 * want to atomically switch with it.
272 * If ipc_port_dncancel finds us a
273 * soright, then the following
274 * ipc_port_dnrequest will reuse
275 * that slot, so we are guaranteed
276 * not to unlock and retry.
277 */
278
279 previous = ipc_right_dncancel_macro(space,
280 port, name, entry);
281
282 kr = ipc_port_dnrequest(port, name, notify,
283 &request);
284 if (kr != KERN_SUCCESS) {
285 assert(previous == IP_NULL);
286 is_write_unlock(space);
287
288 kr = ipc_port_dngrow(port);
289 /* port is unlocked */
290 if (kr != KERN_SUCCESS)
291 return kr;
292
293 continue;
294 }
295
296 assert(request != 0);
297 ip_unlock(port);
298
299 entry->ie_request = request;
300 #if MACH_IPC_COMPAT
301 entry->ie_bits = bits &~ IE_BITS_COMPAT;
302 #endif /* MACH_IPC_COMPAT */
303 is_write_unlock(space);
304 break;
305 }
306
307 #if MACH_IPC_COMPAT
308 if (bits & IE_BITS_COMPAT) {
309 is_write_unlock(space);
310 return KERN_INVALID_NAME;
311 }
312 #endif /* MACH_IPC_COMPAT */
313
314 bits = entry->ie_bits;
315 assert(bits & MACH_PORT_TYPE_DEAD_NAME);
316 }
317
318 if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
319 immediate && (notify != IP_NULL)) {
320 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
321
322 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
323 assert(urefs > 0);
324
325 if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
326 is_write_unlock(space);
327 return KERN_UREFS_OVERFLOW;
328 }
329
330 entry->ie_bits = bits + 1; /* increment urefs */
331 is_write_unlock(space);
332
333 ipc_notify_dead_name(notify, name);
334 previous = IP_NULL;
335 break;
336 }
337
338 is_write_unlock(space);
339 if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
340 return KERN_INVALID_ARGUMENT;
341 else
342 return KERN_INVALID_RIGHT;
343 }
344
345 *previousp = previous;
346 return KERN_SUCCESS;
347 }
348
349 /*
350 * Routine: ipc_right_dncancel
351 * Purpose:
352 * Cancel a dead-name request and return the send-once right.
353 * Afterwards, entry->ie_request == 0.
354 * Conditions:
355 * The space must be write-locked; the port must be locked.
356 * The port must be active; the space doesn't have to be.
357 */
358
359 ipc_port_t
360 ipc_right_dncancel(
361 ipc_space_t space,
362 ipc_port_t port,
363 mach_port_t name,
364 ipc_entry_t entry)
365 {
366 ipc_port_t dnrequest;
367
368 assert(ip_active(port));
369 assert(port == (ipc_port_t) entry->ie_object);
370
371 dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
372 entry->ie_request = 0;
373
374 #if MACH_IPC_COMPAT
375 assert(!ipr_spacep(dnrequest) == !(entry->ie_bits & IE_BITS_COMPAT));
376
377 /* if this is actually a space ptr, just release the ref */
378
379 if (entry->ie_bits & IE_BITS_COMPAT) {
380 assert(space == ipr_space(dnrequest));
381
382 is_release(space);
383 dnrequest = IP_NULL;
384 }
385 #endif /* MACH_IPC_COMPAT */
386
387 return dnrequest;
388 }
389
390 /*
391 * Routine: ipc_right_inuse
392 * Purpose:
393 * Check if an entry is being used.
394 * Returns TRUE if it is.
395 * Conditions:
396 * The space is write-locked and active.
397 * It is unlocked if the entry is inuse.
398 */
399
400 boolean_t
401 ipc_right_inuse(
402 ipc_space_t space,
403 mach_port_t name,
404 ipc_entry_t entry)
405 {
406 ipc_entry_bits_t bits = entry->ie_bits;
407
408 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
409 #if MACH_IPC_COMPAT
410 mach_port_type_t type = IE_BITS_TYPE(bits);
411
412 /*
413 * There is yet hope. If the port has died, we
414 * must clean up the entry so it's as good as new.
415 */
416
417 if ((bits & IE_BITS_COMPAT) &&
418 ((type == MACH_PORT_TYPE_SEND) ||
419 (type == MACH_PORT_TYPE_SEND_ONCE))) {
420 ipc_port_t port;
421 boolean_t active;
422
423 assert(IE_BITS_UREFS(bits) > 0);
424 assert(entry->ie_request != 0);
425
426 port = (ipc_port_t) entry->ie_object;
427 assert(port != IP_NULL);
428
429 ip_lock(port);
430 active = ip_active(port);
431 ip_unlock(port);
432
433 if (!active) {
434 if (type == MACH_PORT_TYPE_SEND) {
435 /* clean up msg-accepted request */
436
437 if (bits & IE_BITS_MAREQUEST)
438 ipc_marequest_cancel(
439 space, name);
440
441 ipc_hash_delete(
442 space, (ipc_object_t) port,
443 name, entry);
444 } else {
445 assert(IE_BITS_UREFS(bits) == 1);
446 assert(!(bits & IE_BITS_MAREQUEST));
447 }
448
449 ipc_port_release(port);
450
451 entry->ie_request = 0;
452 entry->ie_object = IO_NULL;
453 entry->ie_bits &= ~IE_BITS_RIGHT_MASK;
454
455 return FALSE;
456 }
457 }
458 #endif /* MACH_IPC_COMPAT */
459
460 is_write_unlock(space);
461 return TRUE;
462 }
463
464 return FALSE;
465 }
466
467 /*
468 * Routine: ipc_right_check
469 * Purpose:
470 * Check if the port has died. If it has,
471 * clean up the entry and return TRUE.
472 * Conditions:
473 * The space is write-locked; the port is not locked.
474 * If returns FALSE, the port is also locked and active.
475 * Otherwise, entry is converted to a dead name, freeing
476 * a reference to port.
477 *
478 * [MACH_IPC_COMPAT] If the port is dead, and this is a
479 * compat mode entry, then the port reference is released
480 * and the entry is destroyed. The call returns TRUE,
481 * and the space is left locked.
482 */
483
484 boolean_t
485 ipc_right_check(
486 ipc_space_t space,
487 ipc_port_t port,
488 mach_port_t name,
489 ipc_entry_t entry)
490 {
491 ipc_entry_bits_t bits;
492
493 assert(space->is_active);
494 assert(port == (ipc_port_t) entry->ie_object);
495
496 ip_lock(port);
497 if (ip_active(port))
498 return FALSE;
499 ip_unlock(port);
500
501 /* this was either a pure send right or a send-once right */
502
503 bits = entry->ie_bits;
504 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
505 assert(IE_BITS_UREFS(bits) > 0);
506
507 if (bits & MACH_PORT_TYPE_SEND) {
508 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
509
510 /* clean up msg-accepted request */
511
512 if (bits & IE_BITS_MAREQUEST) {
513 bits &= ~IE_BITS_MAREQUEST;
514
515 ipc_marequest_cancel(space, name);
516 }
517
518 ipc_hash_delete(space, (ipc_object_t) port, name, entry);
519 } else {
520 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
521 assert(IE_BITS_UREFS(bits) == 1);
522 assert((bits & IE_BITS_MAREQUEST) == 0);
523 }
524
525 ipc_port_release(port);
526
527 #if MACH_IPC_COMPAT
528 if (bits & IE_BITS_COMPAT) {
529 assert(entry->ie_request != 0);
530 entry->ie_request = 0;
531
532 entry->ie_object = IO_NULL;
533 ipc_entry_dealloc(space, name, entry);
534
535 return TRUE;
536 }
537 #endif /* MACH_IPC_COMPAT */
538
539 /* convert entry to dead name */
540
541 bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
542
543 if (entry->ie_request != 0) {
544 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
545
546 entry->ie_request = 0;
547 bits++; /* increment urefs */
548 }
549
550 entry->ie_bits = bits;
551 entry->ie_object = IO_NULL;
552 return TRUE;
553 }
554
555 /*
556 * Routine: ipc_right_clean
557 * Purpose:
558 * Cleans up an entry in a dead space.
559 * The entry isn't deallocated or removed
560 * from reverse hash tables.
561 * Conditions:
562 * The space is dead and unlocked.
563 */
564
565 void
566 ipc_right_clean(
567 ipc_space_t space,
568 mach_port_t name,
569 ipc_entry_t entry)
570 {
571 ipc_entry_bits_t bits = entry->ie_bits;
572 mach_port_type_t type = IE_BITS_TYPE(bits);
573
574 assert(!space->is_active);
575
576 /*
577 * We can't clean up IE_BITS_MAREQUEST when the space is dead.
578 * This is because ipc_marequest_destroy can't turn off
579 * the bit if the space is dead. Hence, it might be on
580 * even though the marequest has been destroyed. It's OK
581 * not to cancel the marequest, because ipc_marequest_destroy
582 * cancels for us if the space is dead.
583 *
584 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
585 * problem, because we check that the port is active. If
586 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
587 * would still work, but dead space refs would accumulate
588 * in ip_dnrequests. They would use up slots in
589 * ip_dnrequests and keep the spaces from being freed.
590 */
591
592 switch (type) {
593 case MACH_PORT_TYPE_DEAD_NAME:
594 assert(entry->ie_request == 0);
595 assert(entry->ie_object == IO_NULL);
596 assert((bits & IE_BITS_MAREQUEST) == 0);
597 break;
598
599 case MACH_PORT_TYPE_PORT_SET: {
600 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
601
602 assert(entry->ie_request == 0);
603 assert((bits & IE_BITS_MAREQUEST) == 0);
604 assert(pset != IPS_NULL);
605
606 ips_lock(pset);
607 assert(ips_active(pset));
608
609 ipc_pset_destroy(pset); /* consumes ref, unlocks */
610 break;
611 }
612
613 case MACH_PORT_TYPE_SEND:
614 case MACH_PORT_TYPE_RECEIVE:
615 case MACH_PORT_TYPE_SEND_RECEIVE:
616 case MACH_PORT_TYPE_SEND_ONCE: {
617 ipc_port_t port = (ipc_port_t) entry->ie_object;
618 ipc_port_t dnrequest;
619 ipc_port_t nsrequest = IP_NULL;
620 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
621
622 assert(port != IP_NULL);
623 ip_lock(port);
624
625 if (!ip_active(port)) {
626 ip_release(port);
627 ip_check_unlock(port);
628 break;
629 }
630
631 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
632
633 if (type & MACH_PORT_TYPE_SEND) {
634 assert(port->ip_srights > 0);
635 if (--port->ip_srights == 0) {
636 nsrequest = port->ip_nsrequest;
637 if (nsrequest != IP_NULL) {
638 port->ip_nsrequest = IP_NULL;
639 mscount = port->ip_mscount;
640 }
641 }
642 }
643
644 if (type & MACH_PORT_TYPE_RECEIVE) {
645 assert(port->ip_receiver_name == name);
646 assert(port->ip_receiver == space);
647
648 ipc_port_clear_receiver(port);
649 ipc_port_destroy(port); /* consumes our ref, unlocks */
650 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
651 assert(port->ip_sorights > 0);
652 ip_unlock(port);
653
654 ipc_notify_send_once(port); /* consumes our ref */
655 } else {
656 assert(port->ip_receiver != space);
657
658 ip_release(port);
659 ip_unlock(port); /* port is active */
660 }
661
662 if (nsrequest != IP_NULL)
663 ipc_notify_no_senders(nsrequest, mscount);
664
665 if (dnrequest != IP_NULL)
666 ipc_notify_port_deleted(dnrequest, name);
667 break;
668 }
669
670 default:
671 #if MACH_ASSERT
672 assert(!"ipc_right_clean: strange type");
673 #else
674 panic("ipc_right_clean: strange type");
675 #endif
676 }
677 }
678
679 /*
680 * Routine: ipc_right_destroy
681 * Purpose:
682 * Destroys an entry in a space.
683 * Conditions:
684 * The space is write-locked, and is unlocked upon return.
685 * The space must be active.
686 * Returns:
687 * KERN_SUCCESS The entry was destroyed.
688 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
689 * Caller should pretend lookup of entry failed.
690 */
691
692 kern_return_t
693 ipc_right_destroy(
694 ipc_space_t space,
695 mach_port_t name,
696 ipc_entry_t entry)
697 {
698 ipc_entry_bits_t bits = entry->ie_bits;
699 mach_port_type_t type = IE_BITS_TYPE(bits);
700
701 assert(space->is_active);
702
703 switch (type) {
704 case MACH_PORT_TYPE_DEAD_NAME:
705 assert(entry->ie_request == 0);
706 assert(entry->ie_object == IO_NULL);
707 assert((bits & IE_BITS_MAREQUEST) == 0);
708
709 ipc_entry_dealloc(space, name, entry);
710 is_write_unlock(space);
711 break;
712
713 case MACH_PORT_TYPE_PORT_SET: {
714 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
715
716 assert(entry->ie_request == 0);
717 assert(pset != IPS_NULL);
718
719 entry->ie_object = IO_NULL;
720 ipc_entry_dealloc(space, name, entry);
721
722 ips_lock(pset);
723 assert(ips_active(pset));
724 is_write_unlock(space);
725
726 ipc_pset_destroy(pset); /* consumes ref, unlocks */
727 break;
728 }
729
730 case MACH_PORT_TYPE_SEND:
731 case MACH_PORT_TYPE_RECEIVE:
732 case MACH_PORT_TYPE_SEND_RECEIVE:
733 case MACH_PORT_TYPE_SEND_ONCE: {
734 ipc_port_t port = (ipc_port_t) entry->ie_object;
735 ipc_port_t nsrequest = IP_NULL;
736 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
737 ipc_port_t dnrequest;
738
739 assert(port != IP_NULL);
740
741 if (bits & IE_BITS_MAREQUEST) {
742 assert(type & MACH_PORT_TYPE_SEND_RECEIVE);
743
744 ipc_marequest_cancel(space, name);
745 }
746
747 if (type == MACH_PORT_TYPE_SEND)
748 ipc_hash_delete(space, (ipc_object_t) port,
749 name, entry);
750
751 ip_lock(port);
752
753 if (!ip_active(port)) {
754 assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
755
756 ip_release(port);
757 ip_check_unlock(port);
758
759 entry->ie_request = 0;
760 entry->ie_object = IO_NULL;
761 ipc_entry_dealloc(space, name, entry);
762 is_write_unlock(space);
763
764 #if MACH_IPC_COMPAT
765 if (bits & IE_BITS_COMPAT)
766 return KERN_INVALID_NAME;
767 #endif /* MACH_IPC_COMPAT */
768 break;
769 }
770
771 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
772
773 entry->ie_object = IO_NULL;
774 ipc_entry_dealloc(space, name, entry);
775 is_write_unlock(space);
776
777 if (type & MACH_PORT_TYPE_SEND) {
778 assert(port->ip_srights > 0);
779 if (--port->ip_srights == 0) {
780 nsrequest = port->ip_nsrequest;
781 if (nsrequest != IP_NULL) {
782 port->ip_nsrequest = IP_NULL;
783 mscount = port->ip_mscount;
784 }
785 }
786 }
787
788 if (type & MACH_PORT_TYPE_RECEIVE) {
789 assert(ip_active(port));
790 assert(port->ip_receiver == space);
791
792 ipc_port_clear_receiver(port);
793 ipc_port_destroy(port); /* consumes our ref, unlocks */
794 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
795 assert(port->ip_sorights > 0);
796 ip_unlock(port);
797
798 ipc_notify_send_once(port); /* consumes our ref */
799 } else {
800 assert(port->ip_receiver != space);
801
802 ip_release(port);
803 ip_unlock(port);
804 }
805
806 if (nsrequest != IP_NULL)
807 ipc_notify_no_senders(nsrequest, mscount);
808
809 if (dnrequest != IP_NULL)
810 ipc_notify_port_deleted(dnrequest, name);
811 break;
812 }
813
814 default:
815 #if MACH_ASSERT
816 assert(!"ipc_right_destroy: strange type");
817 #else
818 panic("ipc_right_destroy: strange type");
819 #endif
820 }
821
822 return KERN_SUCCESS;
823 }
824
825 /*
826 * Routine: ipc_right_dealloc
827 * Purpose:
828 * Releases a send/send-once/dead-name user ref.
829 * Like ipc_right_delta with a delta of -1,
830 * but looks at the entry to determine the right.
831 * Conditions:
832 * The space is write-locked, and is unlocked upon return.
833 * The space must be active.
834 * Returns:
835 * KERN_SUCCESS A user ref was released.
836 * KERN_INVALID_RIGHT Entry has wrong type.
837 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
838 * Caller should pretend lookup of entry failed.
839 */
840
841 kern_return_t
842 ipc_right_dealloc(
843 ipc_space_t space,
844 mach_port_t name,
845 ipc_entry_t entry)
846 {
847 ipc_entry_bits_t bits = entry->ie_bits;
848 mach_port_type_t type = IE_BITS_TYPE(bits);
849
850 assert(space->is_active);
851
852 switch (type) {
853 case MACH_PORT_TYPE_DEAD_NAME: {
854 dead_name:
855
856 assert(IE_BITS_UREFS(bits) > 0);
857 assert(entry->ie_request == 0);
858 assert(entry->ie_object == IO_NULL);
859 assert((bits & IE_BITS_MAREQUEST) == 0);
860
861 if (IE_BITS_UREFS(bits) == 1)
862 ipc_entry_dealloc(space, name, entry);
863 else
864 entry->ie_bits = bits-1; /* decrement urefs */
865
866 is_write_unlock(space);
867 break;
868 }
869
870 case MACH_PORT_TYPE_SEND_ONCE: {
871 ipc_port_t port, dnrequest;
872
873 assert(IE_BITS_UREFS(bits) == 1);
874 assert((bits & IE_BITS_MAREQUEST) == 0);
875
876 port = (ipc_port_t) entry->ie_object;
877 assert(port != IP_NULL);
878
879 if (ipc_right_check(space, port, name, entry)) {
880 #if MACH_IPC_COMPAT
881 if (bits & IE_BITS_COMPAT)
882 goto invalid_name;
883 #endif /* MACH_IPC_COMPAT */
884
885 bits = entry->ie_bits;
886 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
887 goto dead_name;
888 }
889 /* port is locked and active */
890
891 assert(port->ip_sorights > 0);
892
893 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
894 ip_unlock(port);
895
896 entry->ie_object = IO_NULL;
897 ipc_entry_dealloc(space, name, entry);
898 is_write_unlock(space);
899
900 ipc_notify_send_once(port);
901
902 if (dnrequest != IP_NULL)
903 ipc_notify_port_deleted(dnrequest, name);
904 break;
905 }
906
907 case MACH_PORT_TYPE_SEND: {
908 ipc_port_t port;
909 ipc_port_t dnrequest = IP_NULL;
910 ipc_port_t nsrequest = IP_NULL;
911 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
912
913 assert(IE_BITS_UREFS(bits) > 0);
914
915 port = (ipc_port_t) entry->ie_object;
916 assert(port != IP_NULL);
917
918 if (ipc_right_check(space, port, name, entry)) {
919 #if MACH_IPC_COMPAT
920 if (bits & IE_BITS_COMPAT)
921 goto invalid_name;
922 #endif /* MACH_IPC_COMPAT */
923
924 bits = entry->ie_bits;
925 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
926 goto dead_name;
927 }
928 /* port is locked and active */
929
930 assert(port->ip_srights > 0);
931
932 if (IE_BITS_UREFS(bits) == 1) {
933 if (--port->ip_srights == 0) {
934 nsrequest = port->ip_nsrequest;
935 if (nsrequest != IP_NULL) {
936 port->ip_nsrequest = IP_NULL;
937 mscount = port->ip_mscount;
938 }
939 }
940
941 dnrequest = ipc_right_dncancel_macro(space, port,
942 name, entry);
943
944 ipc_hash_delete(space, (ipc_object_t) port,
945 name, entry);
946
947 if (bits & IE_BITS_MAREQUEST)
948 ipc_marequest_cancel(space, name);
949
950 ip_release(port);
951 entry->ie_object = IO_NULL;
952 ipc_entry_dealloc(space, name, entry);
953 } else
954 entry->ie_bits = bits-1; /* decrement urefs */
955
956 ip_unlock(port); /* even if dropped a ref, port is active */
957 is_write_unlock(space);
958
959 if (nsrequest != IP_NULL)
960 ipc_notify_no_senders(nsrequest, mscount);
961
962 if (dnrequest != IP_NULL)
963 ipc_notify_port_deleted(dnrequest, name);
964 break;
965 }
966
967 case MACH_PORT_TYPE_SEND_RECEIVE: {
968 ipc_port_t port;
969 ipc_port_t nsrequest = IP_NULL;
970 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
971
972 assert(IE_BITS_UREFS(bits) > 0);
973
974 port = (ipc_port_t) entry->ie_object;
975 assert(port != IP_NULL);
976
977 ip_lock(port);
978 assert(ip_active(port));
979 assert(port->ip_receiver_name == name);
980 assert(port->ip_receiver == space);
981 assert(port->ip_srights > 0);
982
983 if (IE_BITS_UREFS(bits) == 1) {
984 if (--port->ip_srights == 0) {
985 nsrequest = port->ip_nsrequest;
986 if (nsrequest != IP_NULL) {
987 port->ip_nsrequest = IP_NULL;
988 mscount = port->ip_mscount;
989 }
990 }
991
992 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
993 MACH_PORT_TYPE_SEND);
994 } else
995 entry->ie_bits = bits-1; /* decrement urefs */
996
997 ip_unlock(port);
998 is_write_unlock(space);
999
1000 if (nsrequest != IP_NULL)
1001 ipc_notify_no_senders(nsrequest, mscount);
1002 break;
1003 }
1004
1005 default:
1006 is_write_unlock(space);
1007 return KERN_INVALID_RIGHT;
1008 }
1009
1010 return KERN_SUCCESS;
1011
1012 #if MACH_IPC_COMPAT
1013 invalid_name:
1014 is_write_unlock(space);
1015 return KERN_INVALID_NAME;
1016 #endif /* MACH_IPC_COMPAT */
1017 }
1018
1019 /*
1020 * Routine: ipc_right_delta
1021 * Purpose:
1022 * Modifies the user-reference count for a right.
1023 * May deallocate the right, if the count goes to zero.
1024 * Conditions:
1025 * The space is write-locked, and is unlocked upon return.
1026 * The space must be active.
1027 * Returns:
1028 * KERN_SUCCESS Count was modified.
1029 * KERN_INVALID_RIGHT Entry has wrong type.
1030 * KERN_INVALID_VALUE Bad delta for the right.
1031 * KERN_UREFS_OVERFLOW OK delta, except would overflow.
1032 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
1033 * Caller should pretend lookup of entry failed.
1034 */
1035
1036 kern_return_t
1037 ipc_right_delta(
1038 ipc_space_t space,
1039 mach_port_t name,
1040 ipc_entry_t entry,
1041 mach_port_right_t right,
1042 mach_port_delta_t delta)
1043 {
1044 ipc_entry_bits_t bits = entry->ie_bits;
1045
1046 assert(space->is_active);
1047 assert(right < MACH_PORT_RIGHT_NUMBER);
1048
1049 /* Rights-specific restrictions and operations. */
1050
1051 switch (right) {
1052 case MACH_PORT_RIGHT_PORT_SET: {
1053 ipc_pset_t pset;
1054
1055 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
1056 goto invalid_right;
1057
1058 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
1059 assert(IE_BITS_UREFS(bits) == 0);
1060 assert((bits & IE_BITS_MAREQUEST) == 0);
1061 assert(entry->ie_request == 0);
1062
1063 if (delta == 0)
1064 goto success;
1065
1066 if (delta != -1)
1067 goto invalid_value;
1068
1069 pset = (ipc_pset_t) entry->ie_object;
1070 assert(pset != IPS_NULL);
1071
1072 entry->ie_object = IO_NULL;
1073 ipc_entry_dealloc(space, name, entry);
1074
1075 ips_lock(pset);
1076 assert(ips_active(pset));
1077 is_write_unlock(space);
1078
1079 ipc_pset_destroy(pset); /* consumes ref, unlocks */
1080 break;
1081 }
1082
1083 case MACH_PORT_RIGHT_RECEIVE: {
1084 ipc_port_t port;
1085 ipc_port_t dnrequest = IP_NULL;
1086
1087 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1088 goto invalid_right;
1089
1090 if (delta == 0)
1091 goto success;
1092
1093 if (delta != -1)
1094 goto invalid_value;
1095
1096 if (bits & IE_BITS_MAREQUEST) {
1097 bits &= ~IE_BITS_MAREQUEST;
1098
1099 ipc_marequest_cancel(space, name);
1100 }
1101
1102 port = (ipc_port_t) entry->ie_object;
1103 assert(port != IP_NULL);
1104
1105 /*
1106 * The port lock is needed for ipc_right_dncancel;
1107 * otherwise, we wouldn't have to take the lock
1108 * until just before dropping the space lock.
1109 */
1110
1111 ip_lock(port);
1112 assert(ip_active(port));
1113 assert(port->ip_receiver_name == name);
1114 assert(port->ip_receiver == space);
1115
1116 #if MACH_IPC_COMPAT
1117 if (bits & IE_BITS_COMPAT) {
1118 assert(entry->ie_request != 0);
1119 dnrequest = ipc_right_dncancel(space, port,
1120 name, entry);
1121 assert(dnrequest == IP_NULL);
1122
1123 entry->ie_object = IO_NULL;
1124 ipc_entry_dealloc(space, name, entry);
1125 } else
1126 #endif /* MACH_IPC_COMPAT */
1127 if (bits & MACH_PORT_TYPE_SEND) {
1128 assert(IE_BITS_TYPE(bits) ==
1129 MACH_PORT_TYPE_SEND_RECEIVE);
1130 assert(IE_BITS_UREFS(bits) > 0);
1131 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1132 assert(port->ip_srights > 0);
1133
1134 /*
1135 * The remaining send right turns into a
1136 * dead name. Notice we don't decrement
1137 * ip_srights, generate a no-senders notif,
1138 * or use ipc_right_dncancel, because the
1139 * port is destroyed "first".
1140 */
1141
1142 bits &= ~IE_BITS_TYPE_MASK;
1143 bits |= MACH_PORT_TYPE_DEAD_NAME;
1144
1145 if (entry->ie_request != 0) {
1146 entry->ie_request = 0;
1147 bits++; /* increment urefs */
1148 }
1149
1150 entry->ie_bits = bits;
1151 entry->ie_object = IO_NULL;
1152 } else {
1153 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1154 assert(IE_BITS_UREFS(bits) == 0);
1155
1156 dnrequest = ipc_right_dncancel_macro(space, port,
1157 name, entry);
1158
1159 entry->ie_object = IO_NULL;
1160 ipc_entry_dealloc(space, name, entry);
1161 }
1162 is_write_unlock(space);
1163
1164 ipc_port_clear_receiver(port);
1165 ipc_port_destroy(port); /* consumes ref, unlocks */
1166
1167 if (dnrequest != IP_NULL)
1168 ipc_notify_port_deleted(dnrequest, name);
1169 break;
1170 }
1171
1172 case MACH_PORT_RIGHT_SEND_ONCE: {
1173 ipc_port_t port, dnrequest;
1174
1175 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1176 goto invalid_right;
1177
1178 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1179 assert(IE_BITS_UREFS(bits) == 1);
1180 assert((bits & IE_BITS_MAREQUEST) == 0);
1181
1182 if ((delta > 0) || (delta < -1))
1183 goto invalid_value;
1184
1185 port = (ipc_port_t) entry->ie_object;
1186 assert(port != IP_NULL);
1187
1188 if (ipc_right_check(space, port, name, entry)) {
1189 #if MACH_IPC_COMPAT
1190 if (bits & IE_BITS_COMPAT)
1191 goto invalid_name;
1192 #endif /* MACH_IPC_COMPAT */
1193
1194 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1195 goto invalid_right;
1196 }
1197 /* port is locked and active */
1198
1199 assert(port->ip_sorights > 0);
1200
1201 if (delta == 0) {
1202 ip_unlock(port);
1203 goto success;
1204 }
1205
1206 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1207 ip_unlock(port);
1208
1209 entry->ie_object = IO_NULL;
1210 ipc_entry_dealloc(space, name, entry);
1211 is_write_unlock(space);
1212
1213 ipc_notify_send_once(port);
1214
1215 if (dnrequest != IP_NULL)
1216 ipc_notify_port_deleted(dnrequest, name);
1217 break;
1218 }
1219
1220 case MACH_PORT_RIGHT_DEAD_NAME: {
1221 mach_port_urefs_t urefs;
1222
1223 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1224 ipc_port_t port;
1225
1226 port = (ipc_port_t) entry->ie_object;
1227 assert(port != IP_NULL);
1228
1229 if (!ipc_right_check(space, port, name, entry)) {
1230 /* port is locked and active */
1231 ip_unlock(port);
1232 goto invalid_right;
1233 }
1234
1235 #if MACH_IPC_COMPAT
1236 if (bits & IE_BITS_COMPAT)
1237 goto invalid_name;
1238 #endif /* MACH_IPC_COMPAT */
1239
1240 bits = entry->ie_bits;
1241 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1242 goto invalid_right;
1243
1244 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1245 assert(IE_BITS_UREFS(bits) > 0);
1246 assert((bits & IE_BITS_MAREQUEST) == 0);
1247 assert(entry->ie_object == IO_NULL);
1248 assert(entry->ie_request == 0);
1249
1250 urefs = IE_BITS_UREFS(bits);
1251 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1252 goto invalid_value;
1253 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1254 goto urefs_overflow;
1255
1256 if ((urefs + delta) == 0)
1257 ipc_entry_dealloc(space, name, entry);
1258 else
1259 entry->ie_bits = bits + delta;
1260
1261 is_write_unlock(space);
1262 break;
1263 }
1264
1265 case MACH_PORT_RIGHT_SEND: {
1266 mach_port_urefs_t urefs;
1267 ipc_port_t port;
1268 ipc_port_t dnrequest = IP_NULL;
1269 ipc_port_t nsrequest = IP_NULL;
1270 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
1271
1272 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1273 goto invalid_right;
1274
1275 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1276
1277 urefs = IE_BITS_UREFS(bits);
1278 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1279 goto invalid_value;
1280 if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta))
1281 goto urefs_overflow;
1282
1283 port = (ipc_port_t) entry->ie_object;
1284 assert(port != IP_NULL);
1285
1286 if (ipc_right_check(space, port, name, entry)) {
1287 #if MACH_IPC_COMPAT
1288 if (bits & IE_BITS_COMPAT)
1289 goto invalid_name;
1290 #endif /* MACH_IPC_COMPAT */
1291
1292 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1293 goto invalid_right;
1294 }
1295 /* port is locked and active */
1296
1297 assert(port->ip_srights > 0);
1298
1299 if ((urefs + delta) == 0) {
1300 if (--port->ip_srights == 0) {
1301 nsrequest = port->ip_nsrequest;
1302 if (nsrequest != IP_NULL) {
1303 port->ip_nsrequest = IP_NULL;
1304 mscount = port->ip_mscount;
1305 }
1306 }
1307
1308 if (bits & MACH_PORT_TYPE_RECEIVE) {
1309 assert(port->ip_receiver_name == name);
1310 assert(port->ip_receiver == space);
1311 assert(IE_BITS_TYPE(bits) ==
1312 MACH_PORT_TYPE_SEND_RECEIVE);
1313
1314 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1315 MACH_PORT_TYPE_SEND);
1316 } else {
1317 assert(IE_BITS_TYPE(bits) ==
1318 MACH_PORT_TYPE_SEND);
1319
1320 dnrequest = ipc_right_dncancel_macro(
1321 space, port, name, entry);
1322
1323 ipc_hash_delete(space, (ipc_object_t) port,
1324 name, entry);
1325
1326 if (bits & IE_BITS_MAREQUEST)
1327 ipc_marequest_cancel(space, name);
1328
1329 ip_release(port);
1330 entry->ie_object = IO_NULL;
1331 ipc_entry_dealloc(space, name, entry);
1332 }
1333 } else
1334 entry->ie_bits = bits + delta;
1335
1336 ip_unlock(port); /* even if dropped a ref, port is active */
1337 is_write_unlock(space);
1338
1339 if (nsrequest != IP_NULL)
1340 ipc_notify_no_senders(nsrequest, mscount);
1341
1342 if (dnrequest != IP_NULL)
1343 ipc_notify_port_deleted(dnrequest, name);
1344 break;
1345 }
1346
1347 default:
1348 #if MACH_ASSERT
1349 assert(!"ipc_right_delta: strange right");
1350 #else
1351 panic("ipc_right_delta: strange right");
1352 #endif
1353 }
1354
1355 return KERN_SUCCESS;
1356
1357 success:
1358 is_write_unlock(space);
1359 return KERN_SUCCESS;
1360
1361 invalid_right:
1362 is_write_unlock(space);
1363 return KERN_INVALID_RIGHT;
1364
1365 invalid_value:
1366 is_write_unlock(space);
1367 return KERN_INVALID_VALUE;
1368
1369 urefs_overflow:
1370 is_write_unlock(space);
1371 return KERN_UREFS_OVERFLOW;
1372
1373 #if MACH_IPC_COMPAT
1374 invalid_name:
1375 is_write_unlock(space);
1376 return KERN_INVALID_NAME;
1377 #endif /* MACH_IPC_COMPAT */
1378 }
1379
1380 /*
1381 * Routine: ipc_right_info
1382 * Purpose:
1383 * Retrieves information about the right.
1384 * Conditions:
1385 * The space is write-locked, and is unlocked upon return
1386 * if the call is unsuccessful. The space must be active.
1387 * Returns:
1388 * KERN_SUCCESS Retrieved info; space still locked.
1389 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
1390 * Caller should pretend lookup of entry failed.
1391 */
1392
1393 kern_return_t
1394 ipc_right_info(
1395 ipc_space_t space,
1396 mach_port_t name,
1397 ipc_entry_t entry,
1398 mach_port_type_t *typep,
1399 mach_port_urefs_t *urefsp)
1400 {
1401 ipc_entry_bits_t bits = entry->ie_bits;
1402 ipc_port_request_index_t request;
1403 mach_port_type_t type;
1404
1405 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1406 ipc_port_t port = (ipc_port_t) entry->ie_object;
1407
1408 if (ipc_right_check(space, port, name, entry)) {
1409 #if MACH_IPC_COMPAT
1410 if (bits & IE_BITS_COMPAT) {
1411 is_write_unlock(space);
1412 return KERN_INVALID_NAME;
1413 }
1414 #endif /* MACH_IPC_COMPAT */
1415
1416 bits = entry->ie_bits;
1417 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1418 } else
1419 ip_unlock(port);
1420 }
1421
1422 type = IE_BITS_TYPE(bits);
1423 request = entry->ie_request;
1424
1425 #if MACH_IPC_COMPAT
1426 if (bits & IE_BITS_COMPAT)
1427 type |= MACH_PORT_TYPE_COMPAT;
1428 else
1429 #endif /* MACH_IPC_COMPAT */
1430 if (request != 0)
1431 type |= MACH_PORT_TYPE_DNREQUEST;
1432 if (bits & IE_BITS_MAREQUEST)
1433 type |= MACH_PORT_TYPE_MAREQUEST;
1434
1435 *typep = type;
1436 *urefsp = IE_BITS_UREFS(bits);
1437 return KERN_SUCCESS;
1438 }
1439
1440 /*
1441 * Routine: ipc_right_copyin_check
1442 * Purpose:
1443 * Check if a subsequent ipc_right_copyin would succeed.
1444 * Conditions:
1445 * The space is locked (read or write) and active.
1446 */
1447
1448 boolean_t
1449 ipc_right_copyin_check(
1450 ipc_space_t space,
1451 mach_port_t name,
1452 ipc_entry_t entry,
1453 mach_msg_type_name_t msgt_name)
1454 {
1455 ipc_entry_bits_t bits = entry->ie_bits;
1456
1457 assert(space->is_active);
1458
1459 switch (msgt_name) {
1460 case MACH_MSG_TYPE_MAKE_SEND:
1461 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1462 case MACH_MSG_TYPE_MOVE_RECEIVE:
1463 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1464 return FALSE;
1465
1466 break;
1467
1468 case MACH_MSG_TYPE_COPY_SEND:
1469 case MACH_MSG_TYPE_MOVE_SEND:
1470 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1471 ipc_port_t port;
1472 boolean_t active;
1473
1474 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1475 break;
1476
1477 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1478 return FALSE;
1479
1480 port = (ipc_port_t) entry->ie_object;
1481 assert(port != IP_NULL);
1482
1483 ip_lock(port);
1484 active = ip_active(port);
1485 ip_unlock(port);
1486
1487 if (!active) {
1488 #if MACH_IPC_COMPAT
1489 if (bits & IE_BITS_COMPAT)
1490 return FALSE;
1491 #endif /* MACH_IPC_COMPAT */
1492
1493 break;
1494 }
1495
1496 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1497 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1498 return FALSE;
1499 } else {
1500 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1501 return FALSE;
1502 }
1503
1504 break;
1505 }
1506
1507 default:
1508 #if MACH_ASSERT
1509 assert(!"ipc_right_copyin_check: strange rights");
1510 #else
1511 panic("ipc_right_copyin_check: strange rights");
1512 #endif
1513 }
1514
1515 return TRUE;
1516 }
1517
1518 /*
1519 * Routine: ipc_right_copyin
1520 * Purpose:
1521 * Copyin a capability from a space.
1522 * If successful, the caller gets a ref
1523 * for the resulting object, unless it is IO_DEAD,
1524 * and possibly a send-once right which should
1525 * be used in a port-deleted notification.
1526 *
1527 * If deadok is not TRUE, the copyin operation
1528 * will fail instead of producing IO_DEAD.
1529 *
1530 * The entry is never deallocated (except
1531 * when KERN_INVALID_NAME), so the caller
1532 * should deallocate the entry if its type
1533 * is MACH_PORT_TYPE_NONE.
1534 * Conditions:
1535 * The space is write-locked and active.
1536 * Returns:
1537 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1538 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1539 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
1540 * Caller should pretend lookup of entry failed.
1541 */
1542
1543 kern_return_t
1544 ipc_right_copyin(
1545 ipc_space_t space,
1546 mach_port_t name,
1547 ipc_entry_t entry,
1548 mach_msg_type_name_t msgt_name,
1549 boolean_t deadok,
1550 ipc_object_t *objectp,
1551 ipc_port_t *sorightp)
1552 {
1553 ipc_entry_bits_t bits = entry->ie_bits;
1554
1555 assert(space->is_active);
1556
1557 switch (msgt_name) {
1558 case MACH_MSG_TYPE_MAKE_SEND: {
1559 ipc_port_t port;
1560
1561 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1562 goto invalid_right;
1563
1564 port = (ipc_port_t) entry->ie_object;
1565 assert(port != IP_NULL);
1566
1567 ip_lock(port);
1568 assert(ip_active(port));
1569 assert(port->ip_receiver_name == name);
1570 assert(port->ip_receiver == space);
1571
1572 port->ip_mscount++;
1573 port->ip_srights++;
1574 ip_reference(port);
1575 ip_unlock(port);
1576
1577 *objectp = (ipc_object_t) port;
1578 *sorightp = IP_NULL;
1579 break;
1580 }
1581
1582 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1583 ipc_port_t port;
1584
1585 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1586 goto invalid_right;
1587
1588 port = (ipc_port_t) entry->ie_object;
1589 assert(port != IP_NULL);
1590
1591 ip_lock(port);
1592 assert(ip_active(port));
1593 assert(port->ip_receiver_name == name);
1594 assert(port->ip_receiver == space);
1595
1596 port->ip_sorights++;
1597 ip_reference(port);
1598 ip_unlock(port);
1599
1600 *objectp = (ipc_object_t) port;
1601 *sorightp = IP_NULL;
1602 break;
1603 }
1604
1605 case MACH_MSG_TYPE_MOVE_RECEIVE: {
1606 ipc_port_t port;
1607 ipc_port_t dnrequest = IP_NULL;
1608
1609 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1610 goto invalid_right;
1611
1612 port = (ipc_port_t) entry->ie_object;
1613 assert(port != IP_NULL);
1614
1615 ip_lock(port);
1616 assert(ip_active(port));
1617 assert(port->ip_receiver_name == name);
1618 assert(port->ip_receiver == space);
1619
1620 if (bits & MACH_PORT_TYPE_SEND) {
1621 assert(IE_BITS_TYPE(bits) ==
1622 MACH_PORT_TYPE_SEND_RECEIVE);
1623 assert(IE_BITS_UREFS(bits) > 0);
1624 assert(port->ip_srights > 0);
1625
1626 ipc_hash_insert(space, (ipc_object_t) port,
1627 name, entry);
1628
1629 ip_reference(port);
1630 } else {
1631 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1632 assert(IE_BITS_UREFS(bits) == 0);
1633
1634 dnrequest = ipc_right_dncancel_macro(space, port,
1635 name, entry);
1636
1637 if (bits & IE_BITS_MAREQUEST)
1638 ipc_marequest_cancel(space, name);
1639
1640 entry->ie_object = IO_NULL;
1641 }
1642 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1643
1644 ipc_port_clear_receiver(port);
1645
1646 port->ip_receiver_name = MACH_PORT_NULL;
1647 port->ip_destination = IP_NULL;
1648 ip_unlock(port);
1649
1650 *objectp = (ipc_object_t) port;
1651 *sorightp = dnrequest;
1652 break;
1653 }
1654
1655 case MACH_MSG_TYPE_COPY_SEND: {
1656 ipc_port_t port;
1657
1658 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1659 goto copy_dead;
1660
1661 /* allow for dead send-once rights */
1662
1663 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1664 goto invalid_right;
1665
1666 assert(IE_BITS_UREFS(bits) > 0);
1667
1668 port = (ipc_port_t) entry->ie_object;
1669 assert(port != IP_NULL);
1670
1671 if (ipc_right_check(space, port, name, entry)) {
1672 #if MACH_IPC_COMPAT
1673 if (bits & IE_BITS_COMPAT)
1674 goto invalid_name;
1675 #endif /* MACH_IPC_COMPAT */
1676
1677 bits = entry->ie_bits;
1678 goto copy_dead;
1679 }
1680 /* port is locked and active */
1681
1682 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1683 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1684 assert(port->ip_sorights > 0);
1685
1686 ip_unlock(port);
1687 goto invalid_right;
1688 }
1689
1690 assert(port->ip_srights > 0);
1691
1692 port->ip_srights++;
1693 ip_reference(port);
1694 ip_unlock(port);
1695
1696 *objectp = (ipc_object_t) port;
1697 *sorightp = IP_NULL;
1698 break;
1699 }
1700
1701 case MACH_MSG_TYPE_MOVE_SEND: {
1702 ipc_port_t port;
1703 ipc_port_t dnrequest = IP_NULL;
1704
1705 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1706 goto move_dead;
1707
1708 /* allow for dead send-once rights */
1709
1710 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1711 goto invalid_right;
1712
1713 assert(IE_BITS_UREFS(bits) > 0);
1714
1715 port = (ipc_port_t) entry->ie_object;
1716 assert(port != IP_NULL);
1717
1718 if (ipc_right_check(space, port, name, entry)) {
1719 #if MACH_IPC_COMPAT
1720 if (bits & IE_BITS_COMPAT)
1721 goto invalid_name;
1722 #endif /* MACH_IPC_COMPAT */
1723
1724 bits = entry->ie_bits;
1725 goto move_dead;
1726 }
1727 /* port is locked and active */
1728
1729 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1730 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1731 assert(port->ip_sorights > 0);
1732
1733 ip_unlock(port);
1734 goto invalid_right;
1735 }
1736
1737 assert(port->ip_srights > 0);
1738
1739 if (IE_BITS_UREFS(bits) == 1) {
1740 if (bits & MACH_PORT_TYPE_RECEIVE) {
1741 assert(port->ip_receiver_name == name);
1742 assert(port->ip_receiver == space);
1743 assert(IE_BITS_TYPE(bits) ==
1744 MACH_PORT_TYPE_SEND_RECEIVE);
1745
1746 ip_reference(port);
1747 } else {
1748 assert(IE_BITS_TYPE(bits) ==
1749 MACH_PORT_TYPE_SEND);
1750
1751 dnrequest = ipc_right_dncancel_macro(
1752 space, port, name, entry);
1753
1754 ipc_hash_delete(space, (ipc_object_t) port,
1755 name, entry);
1756
1757 if (bits & IE_BITS_MAREQUEST)
1758 ipc_marequest_cancel(space, name);
1759
1760 entry->ie_object = IO_NULL;
1761 }
1762 entry->ie_bits = bits &~
1763 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1764 } else {
1765 port->ip_srights++;
1766 ip_reference(port);
1767 entry->ie_bits = bits-1; /* decrement urefs */
1768 }
1769
1770 ip_unlock(port);
1771
1772 *objectp = (ipc_object_t) port;
1773 *sorightp = dnrequest;
1774 break;
1775 }
1776
1777 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1778 ipc_port_t port;
1779 ipc_port_t dnrequest;
1780
1781 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1782 goto move_dead;
1783
1784 /* allow for dead send rights */
1785
1786 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1787 goto invalid_right;
1788
1789 assert(IE_BITS_UREFS(bits) > 0);
1790
1791 port = (ipc_port_t) entry->ie_object;
1792 assert(port != IP_NULL);
1793
1794 if (ipc_right_check(space, port, name, entry)) {
1795 #if MACH_IPC_COMPAT
1796 if (bits & IE_BITS_COMPAT)
1797 goto invalid_name;
1798 #endif /* MACH_IPC_COMPAT */
1799
1800 bits = entry->ie_bits;
1801 goto move_dead;
1802 }
1803 /* port is locked and active */
1804
1805 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1806 assert(bits & MACH_PORT_TYPE_SEND);
1807 assert(port->ip_srights > 0);
1808
1809 ip_unlock(port);
1810 goto invalid_right;
1811 }
1812
1813 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1814 assert(IE_BITS_UREFS(bits) == 1);
1815 assert((bits & IE_BITS_MAREQUEST) == 0);
1816 assert(port->ip_sorights > 0);
1817
1818 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
1819 ip_unlock(port);
1820
1821 entry->ie_object = IO_NULL;
1822 entry->ie_bits = bits &~ MACH_PORT_TYPE_SEND_ONCE;
1823
1824 *objectp = (ipc_object_t) port;
1825 *sorightp = dnrequest;
1826 break;
1827 }
1828
1829 default:
1830 #if MACH_ASSERT
1831 assert(!"ipc_right_copyin: strange rights");
1832 #else
1833 panic("ipc_right_copyin: strange rights");
1834 #endif
1835 }
1836
1837 return KERN_SUCCESS;
1838
1839 copy_dead:
1840 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1841 assert(IE_BITS_UREFS(bits) > 0);
1842 assert((bits & IE_BITS_MAREQUEST) == 0);
1843 assert(entry->ie_request == 0);
1844 assert(entry->ie_object == 0);
1845
1846 if (!deadok)
1847 goto invalid_right;
1848
1849 *objectp = IO_DEAD;
1850 *sorightp = IP_NULL;
1851 return KERN_SUCCESS;
1852
1853 move_dead:
1854 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1855 assert(IE_BITS_UREFS(bits) > 0);
1856 assert((bits & IE_BITS_MAREQUEST) == 0);
1857 assert(entry->ie_request == 0);
1858 assert(entry->ie_object == 0);
1859
1860 if (!deadok)
1861 goto invalid_right;
1862
1863 if (IE_BITS_UREFS(bits) == 1)
1864 entry->ie_bits = bits &~ MACH_PORT_TYPE_DEAD_NAME;
1865 else
1866 entry->ie_bits = bits-1; /* decrement urefs */
1867
1868 *objectp = IO_DEAD;
1869 *sorightp = IP_NULL;
1870 return KERN_SUCCESS;
1871
1872 invalid_right:
1873 return KERN_INVALID_RIGHT;
1874
1875 #if MACH_IPC_COMPAT
1876 invalid_name:
1877 return KERN_INVALID_NAME;
1878 #endif /* MACH_IPC_COMPAT */
1879 }
1880
1881 /*
1882 * Routine: ipc_right_copyin_undo
1883 * Purpose:
1884 * Undoes the effects of an ipc_right_copyin
1885 * of a send/send-once right that is dead.
1886 * (Object is either IO_DEAD or a dead port.)
1887 * Conditions:
1888 * The space is write-locked and active.
1889 */
1890
1891 void
1892 ipc_right_copyin_undo(
1893 ipc_space_t space,
1894 mach_port_t name,
1895 ipc_entry_t entry,
1896 mach_msg_type_name_t msgt_name,
1897 ipc_object_t object,
1898 ipc_port_t soright)
1899 {
1900 ipc_entry_bits_t bits = entry->ie_bits;
1901
1902 assert(space->is_active);
1903
1904 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1905 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
1906 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1907
1908 if (soright != IP_NULL) {
1909 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1910 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1911 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
1912 assert(entry->ie_object == IO_NULL);
1913 assert(object != IO_DEAD);
1914
1915 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1916 MACH_PORT_TYPE_DEAD_NAME | 2);
1917 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
1918 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1919 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
1920 assert(entry->ie_object == IO_NULL);
1921
1922 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
1923 MACH_PORT_TYPE_DEAD_NAME | 1);
1924 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
1925 assert(entry->ie_object == IO_NULL);
1926 assert(object == IO_DEAD);
1927 assert(IE_BITS_UREFS(bits) > 0);
1928
1929 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1930 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1931
1932 entry->ie_bits = bits+1; /* increment urefs */
1933 }
1934 } else {
1935 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
1936 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
1937 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
1938 assert(object != IO_DEAD);
1939 assert(entry->ie_object == object);
1940 assert(IE_BITS_UREFS(bits) > 0);
1941
1942 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
1943 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
1944
1945 entry->ie_bits = bits+1; /* increment urefs */
1946 }
1947
1948 /*
1949 * May as well convert the entry to a dead name.
1950 * (Or if it is a compat entry, destroy it.)
1951 */
1952
1953 (void) ipc_right_check(space, (ipc_port_t) object,
1954 name, entry);
1955 /* object is dead so it is not locked */
1956 }
1957
1958 /* release the reference acquired by copyin */
1959
1960 if (object != IO_DEAD)
1961 ipc_object_release(object);
1962 }
1963
1964 /*
1965 * Routine: ipc_right_copyin_two
1966 * Purpose:
1967 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
1968 * and deadok == FALSE, except that this moves two
1969 * send rights at once.
1970 * Conditions:
1971 * The space is write-locked and active.
1972 * The object is returned with two refs/send rights.
1973 * Returns:
1974 * KERN_SUCCESS Acquired an object.
1975 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1976 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
1977 * Caller should pretend lookup of entry failed.
1978 */
1979
1980 kern_return_t
1981 ipc_right_copyin_two(
1982 ipc_space_t space,
1983 mach_port_t name,
1984 ipc_entry_t entry,
1985 ipc_object_t *objectp,
1986 ipc_port_t *sorightp)
1987 {
1988 ipc_entry_bits_t bits = entry->ie_bits;
1989 mach_port_urefs_t urefs;
1990 ipc_port_t port;
1991 ipc_port_t dnrequest = IP_NULL;
1992
1993 assert(space->is_active);
1994
1995 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1996 goto invalid_right;
1997
1998 urefs = IE_BITS_UREFS(bits);
1999 if (urefs < 2)
2000 goto invalid_right;
2001
2002 port = (ipc_port_t) entry->ie_object;
2003 assert(port != IP_NULL);
2004
2005 if (ipc_right_check(space, port, name, entry)) {
2006 #if MACH_IPC_COMPAT
2007 if (bits & IE_BITS_COMPAT)
2008 goto invalid_name;
2009 #endif /* MACH_IPC_COMPAT */
2010
2011 goto invalid_right;
2012 }
2013 /* port is locked and active */
2014
2015 assert(port->ip_srights > 0);
2016
2017 if (urefs == 2) {
2018 if (bits & MACH_PORT_TYPE_RECEIVE) {
2019 assert(port->ip_receiver_name == name);
2020 assert(port->ip_receiver == space);
2021 assert(IE_BITS_TYPE(bits) ==
2022 MACH_PORT_TYPE_SEND_RECEIVE);
2023
2024 port->ip_srights++;
2025 ip_reference(port);
2026 ip_reference(port);
2027 } else {
2028 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2029
2030 dnrequest = ipc_right_dncancel_macro(space, port,
2031 name, entry);
2032
2033 ipc_hash_delete(space, (ipc_object_t) port,
2034 name, entry);
2035
2036 if (bits & IE_BITS_MAREQUEST)
2037 ipc_marequest_cancel(space, name);
2038
2039 port->ip_srights++;
2040 ip_reference(port);
2041 entry->ie_object = IO_NULL;
2042 }
2043 entry->ie_bits = bits &~
2044 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2045 } else {
2046 port->ip_srights += 2;
2047 ip_reference(port);
2048 ip_reference(port);
2049 entry->ie_bits = bits-2; /* decrement urefs */
2050 }
2051 ip_unlock(port);
2052
2053 *objectp = (ipc_object_t) port;
2054 *sorightp = dnrequest;
2055 return KERN_SUCCESS;
2056
2057 invalid_right:
2058 return KERN_INVALID_RIGHT;
2059
2060 #if MACH_IPC_COMPAT
2061 invalid_name:
2062 return KERN_INVALID_NAME;
2063 #endif /* MACH_IPC_COMPAT */
2064 }
2065
2066 /*
2067 * Routine: ipc_right_copyout
2068 * Purpose:
2069 * Copyout a capability to a space.
2070 * If successful, consumes a ref for the object.
2071 *
2072 * Always succeeds when given a newly-allocated entry,
2073 * because user-reference overflow isn't a possibility.
2074 *
2075 * If copying out the object would cause the user-reference
2076 * count in the entry to overflow, and overflow is TRUE,
2077 * then instead the user-reference count is left pegged
2078 * to its maximum value and the copyout succeeds anyway.
2079 * Conditions:
2080 * The space is write-locked and active.
2081 * The object is locked and active.
2082 * The object is unlocked; the space isn't.
2083 * Returns:
2084 * KERN_SUCCESS Copied out capability.
2085 * KERN_UREFS_OVERFLOW User-refs would overflow;
2086 * guaranteed not to happen with a fresh entry
2087 * or if overflow=TRUE was specified.
2088 */
2089
2090 kern_return_t
2091 ipc_right_copyout(
2092 ipc_space_t space,
2093 mach_port_t name,
2094 ipc_entry_t entry,
2095 mach_msg_type_name_t msgt_name,
2096 boolean_t overflow,
2097 ipc_object_t object)
2098 {
2099 ipc_entry_bits_t bits = entry->ie_bits;
2100 ipc_port_t port;
2101
2102 assert(IO_VALID(object));
2103 assert(io_otype(object) == IOT_PORT);
2104 assert(io_active(object));
2105 assert(entry->ie_object == object);
2106
2107 port = (ipc_port_t) object;
2108
2109 switch (msgt_name) {
2110 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2111 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2112 assert(port->ip_sorights > 0);
2113
2114 /* transfer send-once right and ref to entry */
2115 ip_unlock(port);
2116
2117 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
2118 break;
2119
2120 case MACH_MSG_TYPE_PORT_SEND:
2121 assert(port->ip_srights > 0);
2122
2123 if (bits & MACH_PORT_TYPE_SEND) {
2124 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2125
2126 assert(port->ip_srights > 1);
2127 assert(urefs > 0);
2128 assert(urefs < MACH_PORT_UREFS_MAX);
2129
2130 if (urefs+1 == MACH_PORT_UREFS_MAX) {
2131 if (overflow) {
2132 /* leave urefs pegged to maximum */
2133
2134 port->ip_srights--;
2135 ip_release(port);
2136 ip_unlock(port);
2137 return KERN_SUCCESS;
2138 }
2139
2140 ip_unlock(port);
2141 return KERN_UREFS_OVERFLOW;
2142 }
2143
2144 port->ip_srights--;
2145 ip_release(port);
2146 ip_unlock(port);
2147 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2148 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2149 assert(IE_BITS_UREFS(bits) == 0);
2150
2151 /* transfer send right to entry */
2152 ip_release(port);
2153 ip_unlock(port);
2154 } else {
2155 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2156 assert(IE_BITS_UREFS(bits) == 0);
2157
2158 /* transfer send right and ref to entry */
2159 ip_unlock(port);
2160
2161 /* entry is locked holding ref, so can use port */
2162
2163 ipc_hash_insert(space, (ipc_object_t) port,
2164 name, entry);
2165 }
2166
2167 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
2168 break;
2169
2170 case MACH_MSG_TYPE_PORT_RECEIVE: {
2171 ipc_port_t dest;
2172
2173 assert(port->ip_mscount == 0);
2174 assert(port->ip_receiver_name == MACH_PORT_NULL);
2175 dest = port->ip_destination;
2176
2177 port->ip_receiver_name = name;
2178 port->ip_receiver = space;
2179
2180 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2181
2182 if (bits & MACH_PORT_TYPE_SEND) {
2183 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2184 assert(IE_BITS_UREFS(bits) > 0);
2185 assert(port->ip_srights > 0);
2186
2187 ip_release(port);
2188 ip_unlock(port);
2189
2190 /* entry is locked holding ref, so can use port */
2191
2192 ipc_hash_delete(space, (ipc_object_t) port,
2193 name, entry);
2194 } else {
2195 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2196 assert(IE_BITS_UREFS(bits) == 0);
2197
2198 /* transfer ref to entry */
2199 ip_unlock(port);
2200 }
2201
2202 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2203
2204 if (dest != IP_NULL)
2205 ipc_port_release(dest);
2206 break;
2207 }
2208
2209 default:
2210 #if MACH_ASSERT
2211 assert(!"ipc_right_copyout: strange rights");
2212 #else
2213 panic("ipc_right_copyout: strange rights");
2214 #endif
2215 }
2216
2217 return KERN_SUCCESS;
2218 }
2219
2220 /*
2221 * Routine: ipc_right_rename
2222 * Purpose:
2223 * Transfer an entry from one name to another.
2224 * The old entry is deallocated.
2225 * Conditions:
2226 * The space is write-locked and active.
2227 * The new entry is unused. Upon return,
2228 * the space is unlocked.
2229 * Returns:
2230 * KERN_SUCCESS Moved entry to new name.
2231 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
2232 * Caller should pretend old entry wasn't found.
2233 * New entry was deallocated.
2234 */
2235
2236 kern_return_t
2237 ipc_right_rename(
2238 ipc_space_t space,
2239 mach_port_t oname,
2240 ipc_entry_t oentry,
2241 mach_port_t nname,
2242 ipc_entry_t nentry)
2243 {
2244 ipc_entry_bits_t bits = oentry->ie_bits;
2245 ipc_port_request_index_t request = oentry->ie_request;
2246 ipc_object_t object = oentry->ie_object;
2247
2248 assert(space->is_active);
2249 assert(oname != nname);
2250
2251 /*
2252 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2253 * if the port is dead. (This would foil ipc_port_destroy.)
2254 * Instead we should fail because oentry shouldn't exist.
2255 * Note IE_BITS_COMPAT implies ie_request != 0.
2256 */
2257
2258 if (request != 0) {
2259 ipc_port_t port;
2260
2261 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2262 port = (ipc_port_t) object;
2263 assert(port != IP_NULL);
2264
2265 if (ipc_right_check(space, port, oname, oentry)) {
2266 #if MACH_IPC_COMPAT
2267 if (bits & IE_BITS_COMPAT) {
2268 ipc_entry_dealloc(space, nname, nentry);
2269 is_write_unlock(space);
2270 return KERN_INVALID_NAME;
2271 }
2272 #endif /* MACH_IPC_COMPAT */
2273
2274 bits = oentry->ie_bits;
2275 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2276 assert(oentry->ie_request == 0);
2277 request = 0;
2278 assert(oentry->ie_object == IO_NULL);
2279 object = IO_NULL;
2280 } else {
2281 /* port is locked and active */
2282
2283 ipc_port_dnrename(port, request, oname, nname);
2284 ip_unlock(port);
2285 oentry->ie_request = 0;
2286 }
2287 }
2288
2289 if (bits & IE_BITS_MAREQUEST) {
2290 assert(bits & MACH_PORT_TYPE_SEND_RECEIVE);
2291
2292 ipc_marequest_rename(space, oname, nname);
2293 }
2294
2295 /* initialize nentry before letting ipc_hash_insert see it */
2296
2297 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2298 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2299 nentry->ie_request = request;
2300 nentry->ie_object = object;
2301
2302 switch (IE_BITS_TYPE(bits)) {
2303 case MACH_PORT_TYPE_SEND: {
2304 ipc_port_t port;
2305
2306 port = (ipc_port_t) object;
2307 assert(port != IP_NULL);
2308
2309 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2310 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2311 break;
2312 }
2313
2314 case MACH_PORT_TYPE_RECEIVE:
2315 case MACH_PORT_TYPE_SEND_RECEIVE: {
2316 ipc_port_t port;
2317
2318 port = (ipc_port_t) object;
2319 assert(port != IP_NULL);
2320
2321 ip_lock(port);
2322 assert(ip_active(port));
2323 assert(port->ip_receiver_name == oname);
2324 assert(port->ip_receiver == space);
2325
2326 port->ip_receiver_name = nname;
2327 ip_unlock(port);
2328 break;
2329 }
2330
2331 case MACH_PORT_TYPE_PORT_SET: {
2332 ipc_pset_t pset;
2333
2334 pset = (ipc_pset_t) object;
2335 assert(pset != IPS_NULL);
2336
2337 ips_lock(pset);
2338 assert(ips_active(pset));
2339 assert(pset->ips_local_name == oname);
2340
2341 pset->ips_local_name = nname;
2342 ips_unlock(pset);
2343 break;
2344 }
2345
2346 case MACH_PORT_TYPE_SEND_ONCE:
2347 case MACH_PORT_TYPE_DEAD_NAME:
2348 break;
2349
2350 default:
2351 #if MACH_ASSERT
2352 assert(!"ipc_right_rename: strange rights");
2353 #else
2354 panic("ipc_right_rename: strange rights");
2355 #endif
2356 }
2357
2358 assert(oentry->ie_request == 0);
2359 oentry->ie_object = IO_NULL;
2360 ipc_entry_dealloc(space, oname, oentry);
2361 is_write_unlock(space);
2362
2363 return KERN_SUCCESS;
2364 }
2365
2366 #if MACH_IPC_COMPAT
2367
2368 /*
2369 * Routine: ipc_right_copyin_compat
2370 * Purpose:
2371 * Copyin a capability from a space.
2372 * If successful, the caller gets a ref
2373 * for the resulting object, which is always valid.
2374 * Conditions:
2375 * The space is write-locked, and is unlocked upon return.
2376 * The space must be active.
2377 * Returns:
2378 * KERN_SUCCESS Acquired a valid object.
2379 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2380 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
2381 * Caller should pretend lookup of entry failed.
2382 */
2383
2384 kern_return_t
2385 ipc_right_copyin_compat(
2386 ipc_space_t space,
2387 mach_port_t name,
2388 ipc_entry_t entry,
2389 mach_msg_type_name_t msgt_name,
2390 boolean_t dealloc,
2391 ipc_object_t *objectp)
2392 {
2393 ipc_entry_bits_t bits = entry->ie_bits;
2394
2395 assert(space->is_active);
2396
2397 switch (msgt_name) {
2398 case MSG_TYPE_PORT:
2399 if (dealloc) {
2400 ipc_port_t port;
2401 ipc_port_t dnrequest;
2402
2403 /*
2404 * Pulls a send right out of the space,
2405 * leaving the space with no rights.
2406 * Not allowed to destroy the port,
2407 * so the space can't have receive rights.
2408 * Doesn't operate on dead names.
2409 */
2410
2411 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_SEND)
2412 goto invalid_right;
2413
2414 port = (ipc_port_t) entry->ie_object;
2415 assert(port != IP_NULL);
2416
2417 if (ipc_right_check(space, port, name, entry)) {
2418 if (bits & IE_BITS_COMPAT)
2419 goto invalid_name;
2420
2421 goto invalid_right;
2422 }
2423 /* port is locked and active */
2424
2425 dnrequest = ipc_right_dncancel_macro(space, port,
2426 name, entry);
2427
2428 assert(port->ip_srights > 0);
2429 ip_unlock(port);
2430
2431 if (bits & IE_BITS_MAREQUEST)
2432 ipc_marequest_cancel(space, name);
2433
2434 entry->ie_object = IO_NULL;
2435 ipc_entry_dealloc(space, name, entry);
2436 is_write_unlock(space);
2437
2438 if (dnrequest != IP_NULL)
2439 ipc_notify_port_deleted(dnrequest, name);
2440
2441 *objectp = (ipc_object_t) port;
2442 break;
2443 } else {
2444 ipc_port_t port;
2445
2446 /*
2447 * Pulls a send right out of the space,
2448 * making a send right if necessary.
2449 * Doesn't operate on dead names.
2450 */
2451
2452 if ((bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0)
2453 goto invalid_right;
2454
2455 port = (ipc_port_t) entry->ie_object;
2456 assert(port != IP_NULL);
2457
2458 if (ipc_right_check(space, port, name, entry)) {
2459 if (bits & IE_BITS_COMPAT)
2460 goto invalid_name;
2461
2462 goto invalid_right;
2463 }
2464 /* port is locked and active */
2465
2466 is_write_unlock(space);
2467
2468 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2469 assert(IE_BITS_TYPE(bits) ==
2470 MACH_PORT_TYPE_RECEIVE);
2471 assert(IE_BITS_UREFS(bits) == 0);
2472
2473 port->ip_mscount++;
2474 }
2475
2476 port->ip_srights++;
2477 ip_reference(port);
2478 ip_unlock(port);
2479
2480 *objectp = (ipc_object_t) port;
2481 break;
2482 }
2483
2484 case MSG_TYPE_PORT_ALL:
2485 if (dealloc) {
2486 ipc_port_t port;
2487 ipc_port_t dnrequest = IP_NULL;
2488 ipc_port_t nsrequest = IP_NULL;
2489 mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
2490
2491 /*
2492 * Like MACH_MSG_TYPE_MOVE_RECEIVE, except that
2493 * the space is always left without rights,
2494 * so we kill send rights if necessary.
2495 */
2496
2497 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
2498 goto invalid_right;
2499
2500 port = (ipc_port_t) entry->ie_object;
2501 assert(port != IP_NULL);
2502
2503 ip_lock(port);
2504 assert(ip_active(port));
2505 assert(port->ip_receiver_name == name);
2506 assert(port->ip_receiver == space);
2507
2508 dnrequest = ipc_right_dncancel_macro(space, port,
2509 name, entry);
2510
2511 if (bits & IE_BITS_MAREQUEST)
2512 ipc_marequest_cancel(space, name);
2513
2514 entry->ie_object = IO_NULL;
2515 ipc_entry_dealloc(space, name, entry);
2516 is_write_unlock(space);
2517
2518 if (bits & MACH_PORT_TYPE_SEND) {
2519 assert(IE_BITS_TYPE(bits) ==
2520 MACH_PORT_TYPE_SEND_RECEIVE);
2521 assert(IE_BITS_UREFS(bits) > 0);
2522 assert(port->ip_srights > 0);
2523
2524 if (--port->ip_srights == 0) {
2525 nsrequest = port->ip_nsrequest;
2526 if (nsrequest != IP_NULL) {
2527 port->ip_nsrequest = IP_NULL;
2528 mscount = port->ip_mscount;
2529 }
2530 }
2531 }
2532
2533 ipc_port_clear_receiver(port);
2534
2535 port->ip_receiver_name = MACH_PORT_NULL;
2536 port->ip_destination = IP_NULL;
2537 ip_unlock(port);
2538
2539 if (nsrequest != IP_NULL)
2540 ipc_notify_no_senders(nsrequest, mscount);
2541
2542 if (dnrequest != IP_NULL)
2543 ipc_notify_port_deleted(dnrequest, name);
2544
2545 *objectp = (ipc_object_t) port;
2546 break;
2547 } else {
2548 ipc_port_t port;
2549
2550 /*
2551 * Like MACH_MSG_TYPE_MOVE_RECEIVE, except that
2552 * the space is always left with send rights,
2553 * so we make a send right if necessary.
2554 */
2555
2556 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
2557 goto invalid_right;
2558
2559 port = (ipc_port_t) entry->ie_object;
2560 assert(port != IP_NULL);
2561
2562 ip_lock(port);
2563 assert(ip_active(port));
2564 assert(port->ip_receiver_name == name);
2565 assert(port->ip_receiver == space);
2566
2567 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
2568 assert(IE_BITS_TYPE(bits) ==
2569 MACH_PORT_TYPE_RECEIVE);
2570 assert(IE_BITS_UREFS(bits) == 0);
2571
2572 /* ip_mscount will be cleared below */
2573 port->ip_srights++;
2574 bits |= MACH_PORT_TYPE_SEND | 1;
2575 }
2576
2577 ipc_hash_insert(space, (ipc_object_t) port,
2578 name, entry);
2579
2580 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
2581 is_write_unlock(space);
2582
2583 ipc_port_clear_receiver(port); /* clears ip_mscount */
2584
2585 port->ip_receiver_name = MACH_PORT_NULL;
2586 port->ip_destination = IP_NULL;
2587 ip_reference(port);
2588 ip_unlock(port);
2589
2590 *objectp = (ipc_object_t) port;
2591 break;
2592 }
2593
2594 default:
2595 #if MACH_ASSERT
2596 assert(!"ipc_right_copyin_compat: strange rights");
2597 #else
2598 panic("ipc_right_copyin_compat: strange rights");
2599 #endif
2600 }
2601
2602 return KERN_SUCCESS;
2603
2604 invalid_right:
2605 is_write_unlock(space);
2606 return KERN_INVALID_RIGHT;
2607
2608 invalid_name:
2609 is_write_unlock(space);
2610 return KERN_INVALID_NAME;
2611 }
2612
2613 /*
2614 * Routine: ipc_right_copyin_header
2615 * Purpose:
2616 * Copyin a capability from a space.
2617 * If successful, the caller gets a ref
2618 * for the resulting object, which is always valid.
2619 * The type of the acquired capability is returned.
2620 * Conditions:
2621 * The space is write-locked, and is unlocked upon return.
2622 * The space must be active.
2623 * Returns:
2624 * KERN_SUCCESS Acquired a valid object.
2625 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2626 * KERN_INVALID_NAME [MACH_IPC_COMPAT]
2627 * Caller should pretend lookup of entry failed.
2628 */
2629
2630 kern_return_t
2631 ipc_right_copyin_header(
2632 ipc_space_t space,
2633 mach_port_t name,
2634 ipc_entry_t entry,
2635 ipc_object_t *objectp,
2636 mach_msg_type_name_t *msgt_namep)
2637 {
2638 ipc_entry_bits_t bits = entry->ie_bits;
2639 mach_port_type_t type = IE_BITS_TYPE(bits);
2640
2641 assert(space->is_active);
2642
2643 switch (type) {
2644 case MACH_PORT_TYPE_PORT_SET:
2645 case MACH_PORT_TYPE_DEAD_NAME:
2646 goto invalid_right;
2647
2648 case MACH_PORT_TYPE_RECEIVE: {
2649 ipc_port_t port;
2650
2651 /*
2652 * Like MACH_MSG_TYPE_MAKE_SEND.
2653 */
2654
2655 port = (ipc_port_t) entry->ie_object;
2656 assert(port != IP_NULL);
2657
2658 ip_lock(port);
2659 assert(ip_active(port));
2660 assert(port->ip_receiver_name == name);
2661 assert(port->ip_receiver == space);
2662 is_write_unlock(space);
2663
2664 port->ip_mscount++;
2665 port->ip_srights++;
2666 ip_reference(port);
2667 ip_unlock(port);
2668
2669 *objectp = (ipc_object_t) port;
2670 *msgt_namep = MACH_MSG_TYPE_PORT_SEND;
2671 break;
2672 }
2673
2674 case MACH_PORT_TYPE_SEND:
2675 case MACH_PORT_TYPE_SEND_RECEIVE: {
2676 ipc_port_t port;
2677
2678 /*
2679 * Like MACH_MSG_TYPE_COPY_SEND,
2680 * except that the port must be alive.
2681 */
2682
2683 assert(IE_BITS_UREFS(bits) > 0);
2684
2685 port = (ipc_port_t) entry->ie_object;
2686 assert(port != IP_NULL);
2687
2688 if (ipc_right_check(space, port, name, entry)) {
2689 if (bits & IE_BITS_COMPAT)
2690 goto invalid_name;
2691
2692 goto invalid_right;
2693 }
2694 /* port is locked and active */
2695
2696 assert(port->ip_srights > 0);
2697 is_write_unlock(space);
2698
2699 port->ip_srights++;
2700 ip_reference(port);
2701 ip_unlock(port);
2702
2703 *objectp = (ipc_object_t) port;
2704 *msgt_namep = MACH_MSG_TYPE_PORT_SEND;
2705 break;
2706 }
2707
2708 case MACH_PORT_TYPE_SEND_ONCE: {
2709 ipc_port_t port;
2710 ipc_port_t dnrequest, notify;
2711
2712 /*
2713 * Like MACH_MSG_TYPE_MOVE_SEND_ONCE,
2714 * except that the port must be alive
2715 * and a port-deleted notification is generated.
2716 */
2717
2718 assert(IE_BITS_UREFS(bits) == 1);
2719 assert((bits & IE_BITS_MAREQUEST) == 0);
2720
2721 port = (ipc_port_t) entry->ie_object;
2722 assert(port != IP_NULL);
2723
2724 if (ipc_right_check(space, port, name, entry)) {
2725 if (bits & IE_BITS_COMPAT)
2726 goto invalid_name;
2727
2728 goto invalid_right;
2729 }
2730 /* port is locked and active */
2731
2732 assert(port->ip_sorights > 0);
2733
2734 dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
2735 ip_unlock(port);
2736
2737 entry->ie_object = IO_NULL;
2738 ipc_entry_dealloc(space, name, entry);
2739
2740 notify = ipc_space_make_notify(space);
2741 is_write_unlock(space);
2742
2743 if (dnrequest != IP_NULL)
2744 ipc_notify_port_deleted(dnrequest, name);
2745
2746 if (IP_VALID(notify))
2747 ipc_notify_port_deleted_compat(notify, name);
2748
2749 *objectp = (ipc_object_t) port;
2750 *msgt_namep = MACH_MSG_TYPE_PORT_SEND_ONCE;
2751 break;
2752 }
2753
2754 default:
2755 #if MACH_ASSERT
2756 assert(!"ipc_right_copyin_header: strange rights");
2757 #else
2758 panic("ipc_right_copyin_header: strange rights");
2759 #endif
2760 }
2761
2762 return KERN_SUCCESS;
2763
2764 invalid_right:
2765 is_write_unlock(space);
2766 return KERN_INVALID_RIGHT;
2767
2768 invalid_name:
2769 is_write_unlock(space);
2770 return KERN_INVALID_NAME;
2771 }
2772
2773 #endif /* MACH_IPC_COMPAT */
Cache object: 25c48d80634ae45feb1e9ce674c4d441
|