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