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