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