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