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