]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_right.c
xnu-3789.21.4.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
39037602
A
419 kr = (entry->ie_bits & MACH_PORT_TYPE_PORT_OR_DEAD) ?
420 KERN_INVALID_ARGUMENT : KERN_INVALID_RIGHT;
421
1c79356b 422 is_write_unlock(space);
316670eb
A
423
424 if (port != IP_NULL)
425 ip_release(port);
426
39037602 427 return kr;
1c79356b
A
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
39037602 665 ipc_port_destroy(port); /* clears receiver, consumes our ref, unlocks */
316670eb 666
1c79356b
A
667 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
668 assert(port->ip_sorights > 0);
669 ip_unlock(port);
670
671 ipc_notify_send_once(port); /* consumes our ref */
672 } else {
673 assert(port->ip_receiver != space);
674
316670eb
A
675 ip_unlock(port);
676 ip_release(port);
1c79356b
A
677 }
678
679 if (nsrequest != IP_NULL)
680 ipc_notify_no_senders(nsrequest, mscount);
681
6d2010ae
A
682 if (request != IP_NULL)
683 ipc_notify_port_deleted(request, name);
1c79356b
A
684 break;
685 }
686
687 default:
316670eb 688 panic("ipc_right_terminate: strange type - 0x%x", type);
1c79356b
A
689 }
690}
691
692/*
693 * Routine: ipc_right_destroy
694 * Purpose:
695 * Destroys an entry in a space.
696 * Conditions:
316670eb 697 * The space is write-locked (returns unlocked).
1c79356b
A
698 * The space must be active.
699 * Returns:
700 * KERN_SUCCESS The entry was destroyed.
701 */
702
703kern_return_t
704ipc_right_destroy(
705 ipc_space_t space,
706 mach_port_name_t name,
39236c6e
A
707 ipc_entry_t entry,
708 boolean_t check_guard,
709 uint64_t guard)
1c79356b
A
710{
711 ipc_entry_bits_t bits;
712 mach_port_type_t type;
713
714 bits = entry->ie_bits;
715 entry->ie_bits &= ~IE_BITS_TYPE_MASK;
716 type = IE_BITS_TYPE(bits);
717
316670eb 718 assert(is_active(space));
1c79356b
A
719
720 switch (type) {
721 case MACH_PORT_TYPE_DEAD_NAME:
6d2010ae 722 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
723 assert(entry->ie_object == IO_NULL);
724
725 ipc_entry_dealloc(space, name, entry);
316670eb 726 is_write_unlock(space);
1c79356b
A
727 break;
728
729 case MACH_PORT_TYPE_PORT_SET: {
730 ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
731
6d2010ae 732 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
733 assert(pset != IPS_NULL);
734
735 entry->ie_object = IO_NULL;
1c79356b
A
736 ipc_entry_dealloc(space, name, entry);
737
738 ips_lock(pset);
316670eb 739 is_write_unlock(space);
1c79356b 740
316670eb 741 assert(ips_active(pset));
1c79356b
A
742 ipc_pset_destroy(pset); /* consumes ref, unlocks */
743 break;
744 }
745
746 case MACH_PORT_TYPE_SEND:
747 case MACH_PORT_TYPE_RECEIVE:
748 case MACH_PORT_TYPE_SEND_RECEIVE:
749 case MACH_PORT_TYPE_SEND_ONCE: {
750 ipc_port_t port = (ipc_port_t) entry->ie_object;
751 ipc_port_t nsrequest = IP_NULL;
91447636 752 mach_port_mscount_t mscount = 0;
6d2010ae 753 ipc_port_t request;
1c79356b
A
754
755 assert(port != IP_NULL);
756
757 if (type == MACH_PORT_TYPE_SEND)
758 ipc_hash_delete(space, (ipc_object_t) port,
759 name, entry);
760
761 ip_lock(port);
762
763 if (!ip_active(port)) {
764 assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
316670eb 765 ip_unlock(port);
6d2010ae 766 entry->ie_request = IE_REQ_NONE;
1c79356b
A
767 entry->ie_object = IO_NULL;
768 ipc_entry_dealloc(space, name, entry);
316670eb
A
769 is_write_unlock(space);
770 ip_release(port);
1c79356b
A
771 break;
772 }
773
39236c6e
A
774 /* For receive rights, check for guarding */
775 if ((type & MACH_PORT_TYPE_RECEIVE) &&
776 (check_guard) && (port->ip_guarded) &&
777 (guard != port->ip_context)) {
778 /* Guard Violation */
779 uint64_t portguard = port->ip_context;
780 ip_unlock(port);
781 is_write_unlock(space);
782 /* Raise mach port guard exception */
783 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
784 return KERN_INVALID_RIGHT;
785 }
786
787
6d2010ae 788 request = ipc_right_request_cancel_macro(space, port, name, entry);
1c79356b
A
789
790 entry->ie_object = IO_NULL;
791 ipc_entry_dealloc(space, name, entry);
316670eb 792 is_write_unlock(space);
1c79356b
A
793
794 if (type & MACH_PORT_TYPE_SEND) {
795 assert(port->ip_srights > 0);
796 if (--port->ip_srights == 0) {
797 nsrequest = port->ip_nsrequest;
798 if (nsrequest != IP_NULL) {
799 port->ip_nsrequest = IP_NULL;
800 mscount = port->ip_mscount;
801 }
802 }
803 }
804
805 if (type & MACH_PORT_TYPE_RECEIVE) {
806 assert(ip_active(port));
807 assert(port->ip_receiver == space);
808
39037602 809 ipc_port_destroy(port); /* clears receiver, consumes our ref, unlocks */
39236c6e 810
1c79356b
A
811 } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
812 assert(port->ip_sorights > 0);
813 ip_unlock(port);
814
815 ipc_notify_send_once(port); /* consumes our ref */
816 } else {
817 assert(port->ip_receiver != space);
818
1c79356b 819 ip_unlock(port);
316670eb 820 ip_release(port);
1c79356b
A
821 }
822
823 if (nsrequest != IP_NULL)
824 ipc_notify_no_senders(nsrequest, mscount);
825
6d2010ae
A
826 if (request != IP_NULL)
827 ipc_notify_port_deleted(request, name);
39236c6e
A
828
829
1c79356b
A
830 break;
831 }
832
833 default:
834 panic("ipc_right_destroy: strange type");
835 }
836
837 return KERN_SUCCESS;
838}
839
840/*
841 * Routine: ipc_right_dealloc
842 * Purpose:
843 * Releases a send/send-once/dead-name user ref.
844 * Like ipc_right_delta with a delta of -1,
845 * but looks at the entry to determine the right.
846 * Conditions:
847 * The space is write-locked, and is unlocked upon return.
848 * The space must be active.
849 * Returns:
850 * KERN_SUCCESS A user ref was released.
851 * KERN_INVALID_RIGHT Entry has wrong type.
852 */
853
854kern_return_t
855ipc_right_dealloc(
856 ipc_space_t space,
857 mach_port_name_t name,
858 ipc_entry_t entry)
859{
316670eb 860 ipc_port_t port = IP_NULL;
1c79356b
A
861 ipc_entry_bits_t bits;
862 mach_port_type_t type;
863
864 bits = entry->ie_bits;
865 type = IE_BITS_TYPE(bits);
866
867
316670eb 868 assert(is_active(space));
1c79356b
A
869
870 switch (type) {
871 case MACH_PORT_TYPE_DEAD_NAME: {
872 dead_name:
873
874 assert(IE_BITS_UREFS(bits) > 0);
6d2010ae 875 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
876 assert(entry->ie_object == IO_NULL);
877
878 if (IE_BITS_UREFS(bits) == 1) {
879 ipc_entry_dealloc(space, name, entry);
316670eb 880 } else {
1c79356b 881 entry->ie_bits = bits-1; /* decrement urefs */
316670eb
A
882 ipc_entry_modified(space, name, entry);
883 }
1c79356b 884 is_write_unlock(space);
316670eb
A
885
886 /* release any port that got converted to dead name below */
887 if (port != IP_NULL)
888 ip_release(port);
1c79356b
A
889 break;
890 }
891
892 case MACH_PORT_TYPE_SEND_ONCE: {
316670eb 893 ipc_port_t request;
1c79356b
A
894
895 assert(IE_BITS_UREFS(bits) == 1);
896
897 port = (ipc_port_t) entry->ie_object;
898 assert(port != IP_NULL);
899
900 if (ipc_right_check(space, port, name, entry)) {
901
902 bits = entry->ie_bits;
903 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
316670eb 904 goto dead_name; /* it will release port */
1c79356b
A
905 }
906 /* port is locked and active */
907
908 assert(port->ip_sorights > 0);
909
6d2010ae 910 request = ipc_right_request_cancel_macro(space, port, name, entry);
1c79356b
A
911 ip_unlock(port);
912
913 entry->ie_object = IO_NULL;
914 ipc_entry_dealloc(space, name, entry);
915
916 is_write_unlock(space);
917
918 ipc_notify_send_once(port);
919
6d2010ae
A
920 if (request != IP_NULL)
921 ipc_notify_port_deleted(request, name);
1c79356b
A
922 break;
923 }
924
925 case MACH_PORT_TYPE_SEND: {
6d2010ae 926 ipc_port_t request = IP_NULL;
1c79356b 927 ipc_port_t nsrequest = IP_NULL;
91447636 928 mach_port_mscount_t mscount = 0;
1c79356b
A
929
930
931 assert(IE_BITS_UREFS(bits) > 0);
932
933 port = (ipc_port_t) entry->ie_object;
934 assert(port != IP_NULL);
935
936 if (ipc_right_check(space, port, name, entry)) {
937 bits = entry->ie_bits;
938 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
316670eb 939 goto dead_name; /* it will release port */
1c79356b
A
940 }
941 /* port is locked and active */
942
943 assert(port->ip_srights > 0);
944
945 if (IE_BITS_UREFS(bits) == 1) {
946 if (--port->ip_srights == 0) {
947 nsrequest = port->ip_nsrequest;
948 if (nsrequest != IP_NULL) {
949 port->ip_nsrequest = IP_NULL;
950 mscount = port->ip_mscount;
951 }
952 }
953
6d2010ae 954 request = ipc_right_request_cancel_macro(space, port,
1c79356b
A
955 name, entry);
956 ipc_hash_delete(space, (ipc_object_t) port,
957 name, entry);
958
316670eb 959 ip_unlock(port);
1c79356b
A
960 entry->ie_object = IO_NULL;
961 ipc_entry_dealloc(space, name, entry);
316670eb
A
962 is_write_unlock(space);
963 ip_release(port);
1c79356b 964
316670eb
A
965 } else {
966 ip_unlock(port);
1c79356b 967 entry->ie_bits = bits-1; /* decrement urefs */
316670eb
A
968 ipc_entry_modified(space, name, entry);
969 is_write_unlock(space);
970 }
971
1c79356b
A
972
973 if (nsrequest != IP_NULL)
974 ipc_notify_no_senders(nsrequest, mscount);
975
6d2010ae
A
976 if (request != IP_NULL)
977 ipc_notify_port_deleted(request, name);
1c79356b
A
978 break;
979 }
980
981 case MACH_PORT_TYPE_SEND_RECEIVE: {
1c79356b 982 ipc_port_t nsrequest = IP_NULL;
91447636 983 mach_port_mscount_t mscount = 0;
1c79356b
A
984
985 assert(IE_BITS_UREFS(bits) > 0);
986
987 port = (ipc_port_t) entry->ie_object;
988 assert(port != IP_NULL);
989
990 ip_lock(port);
991 assert(ip_active(port));
992 assert(port->ip_receiver_name == name);
993 assert(port->ip_receiver == space);
994 assert(port->ip_srights > 0);
995
996 if (IE_BITS_UREFS(bits) == 1) {
997 if (--port->ip_srights == 0) {
998 nsrequest = port->ip_nsrequest;
999 if (nsrequest != IP_NULL) {
1000 port->ip_nsrequest = IP_NULL;
1001 mscount = port->ip_mscount;
1002 }
1003 }
1004
1005 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK |
1006 MACH_PORT_TYPE_SEND);
1007 } else
1008 entry->ie_bits = bits-1; /* decrement urefs */
1009
1010 ip_unlock(port);
316670eb
A
1011
1012 ipc_entry_modified(space, name, entry);
1c79356b
A
1013 is_write_unlock(space);
1014
1015 if (nsrequest != IP_NULL)
1016 ipc_notify_no_senders(nsrequest, mscount);
1017 break;
1018 }
1019
1020 default:
1021 is_write_unlock(space);
1022 return KERN_INVALID_RIGHT;
1023 }
1024
1025 return KERN_SUCCESS;
1026}
1027
1028/*
1029 * Routine: ipc_right_delta
1030 * Purpose:
1031 * Modifies the user-reference count for a right.
1032 * May deallocate the right, if the count goes to zero.
1033 * Conditions:
1034 * The space is write-locked, and is unlocked upon return.
1035 * The space must be active.
1036 * Returns:
1037 * KERN_SUCCESS Count was modified.
1038 * KERN_INVALID_RIGHT Entry has wrong type.
1039 * KERN_INVALID_VALUE Bad delta for the right.
1040 * KERN_UREFS_OVERFLOW OK delta, except would overflow.
1041 */
1042
1043kern_return_t
1044ipc_right_delta(
1045 ipc_space_t space,
1046 mach_port_name_t name,
1047 ipc_entry_t entry,
1048 mach_port_right_t right,
1049 mach_port_delta_t delta)
1050{
316670eb 1051 ipc_port_t port = IP_NULL;
1c79356b 1052 ipc_entry_bits_t bits;
39236c6e 1053
1c79356b
A
1054 bits = entry->ie_bits;
1055
1056
1057/*
1058 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
1059 * switch below. It is used to keep track of those cases (in DIPC)
1060 * where we have postponed the dropping of a port reference. Since
1061 * the dropping of the reference could cause the port to disappear
1062 * we postpone doing so when we are holding the space lock.
1063 */
1064
316670eb 1065 assert(is_active(space));
1c79356b
A
1066 assert(right < MACH_PORT_RIGHT_NUMBER);
1067
1068 /* Rights-specific restrictions and operations. */
1069
1070 switch (right) {
1071 case MACH_PORT_RIGHT_PORT_SET: {
1072 ipc_pset_t pset;
1073
1074 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
1075 goto invalid_right;
1076
1077 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
1078 assert(IE_BITS_UREFS(bits) == 0);
6d2010ae 1079 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
1080
1081 if (delta == 0)
1082 goto success;
1083
1084 if (delta != -1)
1085 goto invalid_value;
1086
1087 pset = (ipc_pset_t) entry->ie_object;
1088 assert(pset != IPS_NULL);
1089
1c79356b
A
1090 entry->ie_object = IO_NULL;
1091 ipc_entry_dealloc(space, name, entry);
1092
1c79356b
A
1093 ips_lock(pset);
1094 assert(ips_active(pset));
1095 is_write_unlock(space);
1096
1097 ipc_pset_destroy(pset); /* consumes ref, unlocks */
1098 break;
1099 }
1100
1101 case MACH_PORT_RIGHT_RECEIVE: {
6d2010ae 1102 ipc_port_t request = IP_NULL;
1c79356b
A
1103
1104 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1105 goto invalid_right;
1106
1107 if (delta == 0)
1108 goto success;
1109
1110 if (delta != -1)
1111 goto invalid_value;
1112
1113 port = (ipc_port_t) entry->ie_object;
1114 assert(port != IP_NULL);
1115
1116 /*
1117 * The port lock is needed for ipc_right_dncancel;
1118 * otherwise, we wouldn't have to take the lock
1119 * until just before dropping the space lock.
1120 */
1121
1122 ip_lock(port);
1123 assert(ip_active(port));
1124 assert(port->ip_receiver_name == name);
1125 assert(port->ip_receiver == space);
39236c6e
A
1126
1127 /* Mach Port Guard Checking */
1128 if(port->ip_guarded) {
1129 uint64_t portguard = port->ip_context;
1130 ip_unlock(port);
1131 is_write_unlock(space);
1132 /* Raise mach port guard exception */
1133 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_MOD_REFS);
1134 goto guard_failure;
1135 }
1136
1c79356b
A
1137 if (bits & MACH_PORT_TYPE_SEND) {
1138 assert(IE_BITS_TYPE(bits) ==
1139 MACH_PORT_TYPE_SEND_RECEIVE);
1140 assert(IE_BITS_UREFS(bits) > 0);
1141 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1142 assert(port->ip_srights > 0);
1143
6d2010ae
A
1144 if (port->ip_pdrequest != NULL) {
1145 /*
1146 * Since another task has requested a
1147 * destroy notification for this port, it
1148 * isn't actually being destroyed - the receive
1149 * right is just being moved to another task.
1150 * Since we still have one or more send rights,
1151 * we need to record the loss of the receive
1152 * right and enter the remaining send right
1153 * into the hash table.
1154 */
316670eb 1155 ipc_entry_modified(space, name, entry);
6d2010ae
A
1156 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1157 ipc_hash_insert(space, (ipc_object_t) port,
1158 name, entry);
1159 ip_reference(port);
1160 } else {
1161 /*
1162 * The remaining send right turns into a
1163 * dead name. Notice we don't decrement
1164 * ip_srights, generate a no-senders notif,
1165 * or use ipc_right_dncancel, because the
1166 * port is destroyed "first".
1167 */
1168 bits &= ~IE_BITS_TYPE_MASK;
1169 bits |= MACH_PORT_TYPE_DEAD_NAME;
1170 if (entry->ie_request) {
1171 entry->ie_request = IE_REQ_NONE;
1172 bits++;
1173 }
1174 entry->ie_bits = bits;
1175 entry->ie_object = IO_NULL;
316670eb 1176 ipc_entry_modified(space, name, entry);
1c79356b 1177 }
1c79356b
A
1178 } else {
1179 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1180 assert(IE_BITS_UREFS(bits) == 0);
1181
6d2010ae 1182 request = ipc_right_request_cancel_macro(space, port,
1c79356b
A
1183 name, entry);
1184 entry->ie_object = IO_NULL;
1185 ipc_entry_dealloc(space, name, entry);
1186 }
1187 is_write_unlock(space);
1188
39037602 1189 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
39236c6e 1190
6d2010ae
A
1191 if (request != IP_NULL)
1192 ipc_notify_port_deleted(request, name);
1c79356b
A
1193 break;
1194 }
1195
1196 case MACH_PORT_RIGHT_SEND_ONCE: {
316670eb 1197 ipc_port_t request;
1c79356b
A
1198
1199 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1200 goto invalid_right;
1201
1202 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1203 assert(IE_BITS_UREFS(bits) == 1);
1204
1205 port = (ipc_port_t) entry->ie_object;
1206 assert(port != IP_NULL);
1207
1208 if (ipc_right_check(space, port, name, entry)) {
1209 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
1210 goto invalid_right;
1211 }
1212 /* port is locked and active */
1213
1214 assert(port->ip_sorights > 0);
1215
1216 if ((delta > 0) || (delta < -1)) {
1217 ip_unlock(port);
1218 goto invalid_value;
1219 }
1220
1221 if (delta == 0) {
1222 ip_unlock(port);
1223 goto success;
1224 }
1225
6d2010ae 1226 request = ipc_right_request_cancel_macro(space, port, name, entry);
1c79356b
A
1227 ip_unlock(port);
1228
1229 entry->ie_object = IO_NULL;
1230 ipc_entry_dealloc(space, name, entry);
1231
1232 is_write_unlock(space);
1233
1234 ipc_notify_send_once(port);
1235
6d2010ae
A
1236 if (request != IP_NULL)
1237 ipc_notify_port_deleted(request, name);
1c79356b
A
1238 break;
1239 }
1240
1241 case MACH_PORT_RIGHT_DEAD_NAME: {
39236c6e 1242 ipc_port_t relport = IP_NULL;
1c79356b
A
1243 mach_port_urefs_t urefs;
1244
1245 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1c79356b
A
1246
1247 port = (ipc_port_t) entry->ie_object;
1248 assert(port != IP_NULL);
1249
1250 if (!ipc_right_check(space, port, name, entry)) {
1251 /* port is locked and active */
1252 ip_unlock(port);
316670eb 1253 port = IP_NULL;
1c79356b
A
1254 goto invalid_right;
1255 }
1256 bits = entry->ie_bits;
39236c6e
A
1257 relport = port;
1258 port = IP_NULL;
1c79356b
A
1259 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
1260 goto invalid_right;
1261
1262 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1263 assert(IE_BITS_UREFS(bits) > 0);
1264 assert(entry->ie_object == IO_NULL);
6d2010ae 1265 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
1266
1267 urefs = IE_BITS_UREFS(bits);
1268 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
1269 goto invalid_value;
1270 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
1271 goto urefs_overflow;
1272
1273 if ((urefs + delta) == 0) {
1274 ipc_entry_dealloc(space, name, entry);
316670eb 1275 } else {
1c79356b 1276 entry->ie_bits = bits + delta;
316670eb
A
1277 ipc_entry_modified(space, name, entry);
1278 }
1c79356b
A
1279 is_write_unlock(space);
1280
39236c6e
A
1281 if (relport != IP_NULL)
1282 ip_release(relport);
1283
1c79356b
A
1284 break;
1285 }
1286
1287 case MACH_PORT_RIGHT_SEND: {
1288 mach_port_urefs_t urefs;
6d2010ae 1289 ipc_port_t request = IP_NULL;
1c79356b 1290 ipc_port_t nsrequest = IP_NULL;
91447636 1291 mach_port_mscount_t mscount = 0;
1c79356b
A
1292
1293 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1294 goto invalid_right;
1295
1296 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
1297
1298 port = (ipc_port_t) entry->ie_object;
1299 assert(port != IP_NULL);
1300
1301 if (ipc_right_check(space, port, name, entry)) {
1302 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1303 goto invalid_right;
1304 }
1305 /* port is locked and active */
1306
1307 assert(port->ip_srights > 0);
1308
1309 urefs = IE_BITS_UREFS(bits);
1310 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1311 ip_unlock(port);
1312 goto invalid_value;
1313 }
1314 if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
1315 ip_unlock(port);
1316 goto urefs_overflow;
1317 }
1318
1319 if ((urefs + delta) == 0) {
1320 if (--port->ip_srights == 0) {
1321 nsrequest = port->ip_nsrequest;
1322 if (nsrequest != IP_NULL) {
1323 port->ip_nsrequest = IP_NULL;
1324 mscount = port->ip_mscount;
1325 }
1326 }
1327
1328 if (bits & MACH_PORT_TYPE_RECEIVE) {
1329 assert(port->ip_receiver_name == name);
1330 assert(port->ip_receiver == space);
316670eb 1331 ip_unlock(port);
1c79356b
A
1332 assert(IE_BITS_TYPE(bits) ==
1333 MACH_PORT_TYPE_SEND_RECEIVE);
1334
1335 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1336 MACH_PORT_TYPE_SEND);
316670eb 1337 ipc_entry_modified(space, name, entry);
1c79356b
A
1338 } else {
1339 assert(IE_BITS_TYPE(bits) ==
1340 MACH_PORT_TYPE_SEND);
1341
6d2010ae 1342 request = ipc_right_request_cancel_macro(space, port,
1c79356b
A
1343 name, entry);
1344 ipc_hash_delete(space, (ipc_object_t) port,
1345 name, entry);
1346
316670eb 1347 ip_unlock(port);
1c79356b
A
1348 ip_release(port);
1349
1350 entry->ie_object = IO_NULL;
1351 ipc_entry_dealloc(space, name, entry);
1352 }
316670eb
A
1353 } else {
1354 ip_unlock(port);
1c79356b 1355 entry->ie_bits = bits + delta;
316670eb
A
1356 ipc_entry_modified(space, name, entry);
1357 }
1c79356b 1358
1c79356b
A
1359 is_write_unlock(space);
1360
1361 if (nsrequest != IP_NULL)
1362 ipc_notify_no_senders(nsrequest, mscount);
1363
6d2010ae
A
1364 if (request != IP_NULL)
1365 ipc_notify_port_deleted(request, name);
1c79356b
A
1366 break;
1367 }
1368
1369 default:
1370 panic("ipc_right_delta: strange right");
1371 }
1372
1373 return KERN_SUCCESS;
1374
1375 success:
1376 is_write_unlock(space);
1377 return KERN_SUCCESS;
1378
1379 invalid_right:
1380 is_write_unlock(space);
316670eb
A
1381 if (port != IP_NULL)
1382 ip_release(port);
1c79356b
A
1383 return KERN_INVALID_RIGHT;
1384
1385 invalid_value:
1386 is_write_unlock(space);
1387 return KERN_INVALID_VALUE;
1388
1389 urefs_overflow:
1390 is_write_unlock(space);
1391 return KERN_UREFS_OVERFLOW;
39236c6e
A
1392
1393 guard_failure:
1394 return KERN_INVALID_RIGHT;
1c79356b
A
1395}
1396
39236c6e
A
1397/*
1398 * Routine: ipc_right_destruct
1399 * Purpose:
1400 * Deallocates the receive right and modifies the
1401 * user-reference count for the send rights as requested.
1402 * Conditions:
1403 * The space is write-locked, and is unlocked upon return.
1404 * The space must be active.
1405 * Returns:
1406 * KERN_SUCCESS Count was modified.
1407 * KERN_INVALID_RIGHT Entry has wrong type.
1408 * KERN_INVALID_VALUE Bad delta for the right.
1409 */
1410
1411kern_return_t
1412ipc_right_destruct(
1413 ipc_space_t space,
1414 mach_port_name_t name,
1415 ipc_entry_t entry,
1416 mach_port_delta_t srdelta,
1417 uint64_t guard)
1418{
1419 ipc_port_t port = IP_NULL;
1420 ipc_entry_bits_t bits;
1421
39236c6e
A
1422 mach_port_urefs_t urefs;
1423 ipc_port_t request = IP_NULL;
1424 ipc_port_t nsrequest = IP_NULL;
1425 mach_port_mscount_t mscount = 0;
1426
1427 bits = entry->ie_bits;
1428
1429 assert(is_active(space));
1430
1431 if (((bits & MACH_PORT_TYPE_RECEIVE) == 0) ||
1432 (srdelta && ((bits & MACH_PORT_TYPE_SEND) == 0))) {
1433 is_write_unlock(space);
1434 return KERN_INVALID_RIGHT;
1435 }
1436
1437 if (srdelta > 0)
1438 goto invalid_value;
1439
1440 port = (ipc_port_t) entry->ie_object;
1441 assert(port != IP_NULL);
1442
1443 ip_lock(port);
1444 assert(ip_active(port));
1445 assert(port->ip_receiver_name == name);
1446 assert(port->ip_receiver == space);
1447
1448 /* Mach Port Guard Checking */
1449 if(port->ip_guarded && (guard != port->ip_context)) {
1450 uint64_t portguard = port->ip_context;
1451 ip_unlock(port);
1452 is_write_unlock(space);
1453 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
1454 return KERN_INVALID_ARGUMENT;
1455 }
1456
1457 /*
1458 * First reduce the send rights as requested and
1459 * adjust the entry->ie_bits accordingly. The
1460 * ipc_entry_modified() call is made once the receive
1461 * right is destroyed too.
1462 */
1463
1464 if (srdelta) {
1465
1466 assert(port->ip_srights > 0);
1467
1468 urefs = IE_BITS_UREFS(bits);
1469 /*
1470 * Since we made sure that srdelta is negative,
1471 * the check for urefs overflow is not required.
1472 */
1473 if (MACH_PORT_UREFS_UNDERFLOW(urefs, srdelta)) {
1474 ip_unlock(port);
1475 goto invalid_value;
1476 }
1477 if ((urefs + srdelta) == 0) {
1478 if (--port->ip_srights == 0) {
1479 nsrequest = port->ip_nsrequest;
1480 if (nsrequest != IP_NULL) {
1481 port->ip_nsrequest = IP_NULL;
1482 mscount = port->ip_mscount;
1483 }
1484 }
1485 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_RECEIVE);
1486 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1487 MACH_PORT_TYPE_SEND);
1488 } else {
1489 entry->ie_bits = bits + srdelta;
1490 }
1491 }
1492
1493 /*
1494 * Now destroy the receive right. Update space and
1495 * entry accordingly.
1496 */
1497
1498 bits = entry->ie_bits;
1499 if (bits & MACH_PORT_TYPE_SEND) {
1500 assert(IE_BITS_UREFS(bits) > 0);
1501 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
1502
1503 if (port->ip_pdrequest != NULL) {
1504 /*
1505 * Since another task has requested a
1506 * destroy notification for this port, it
1507 * isn't actually being destroyed - the receive
1508 * right is just being moved to another task.
1509 * Since we still have one or more send rights,
1510 * we need to record the loss of the receive
1511 * right and enter the remaining send right
1512 * into the hash table.
1513 */
1514 ipc_entry_modified(space, name, entry);
1515 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1516 ipc_hash_insert(space, (ipc_object_t) port,
1517 name, entry);
1518 ip_reference(port);
1519 } else {
1520 /*
1521 * The remaining send right turns into a
1522 * dead name. Notice we don't decrement
1523 * ip_srights, generate a no-senders notif,
1524 * or use ipc_right_dncancel, because the
1525 * port is destroyed "first".
1526 */
1527 bits &= ~IE_BITS_TYPE_MASK;
1528 bits |= MACH_PORT_TYPE_DEAD_NAME;
1529 if (entry->ie_request) {
1530 entry->ie_request = IE_REQ_NONE;
1531 bits++;
1532 }
1533 entry->ie_bits = bits;
1534 entry->ie_object = IO_NULL;
1535 ipc_entry_modified(space, name, entry);
1536 }
1537 } else {
1538 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1539 assert(IE_BITS_UREFS(bits) == 0);
1540 request = ipc_right_request_cancel_macro(space, port,
1541 name, entry);
1542 entry->ie_object = IO_NULL;
1543 ipc_entry_dealloc(space, name, entry);
1544 }
1545
1546 /* Unlock space */
1547 is_write_unlock(space);
1548
1549 if (nsrequest != IP_NULL)
1550 ipc_notify_no_senders(nsrequest, mscount);
1551
39037602 1552 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
39236c6e 1553
39236c6e
A
1554 if (request != IP_NULL)
1555 ipc_notify_port_deleted(request, name);
1556
1557 return KERN_SUCCESS;
1558
1559 invalid_value:
1560 is_write_unlock(space);
1561 return KERN_INVALID_VALUE;
1562
1563}
1564
1565
1c79356b
A
1566/*
1567 * Routine: ipc_right_info
1568 * Purpose:
1569 * Retrieves information about the right.
1570 * Conditions:
316670eb
A
1571 * The space is active and write-locked.
1572 * The space is unlocked upon return.
1c79356b 1573 * Returns:
316670eb 1574 * KERN_SUCCESS Retrieved info
1c79356b
A
1575 */
1576
1577kern_return_t
1578ipc_right_info(
1579 ipc_space_t space,
1580 mach_port_name_t name,
1581 ipc_entry_t entry,
1582 mach_port_type_t *typep,
1583 mach_port_urefs_t *urefsp)
1584{
6d2010ae 1585 ipc_port_t port;
1c79356b 1586 ipc_entry_bits_t bits;
6d2010ae 1587 mach_port_type_t type = 0;
1c79356b
A
1588 ipc_port_request_index_t request;
1589
1590 bits = entry->ie_bits;
6d2010ae
A
1591 request = entry->ie_request;
1592 port = (ipc_port_t) entry->ie_object;
1c79356b 1593
6d2010ae
A
1594 if (bits & MACH_PORT_TYPE_RECEIVE) {
1595 assert(IP_VALID(port));
1c79356b 1596
6d2010ae
A
1597 if (request != IE_REQ_NONE) {
1598 ip_lock(port);
1599 assert(ip_active(port));
1600 type |= ipc_port_request_type(port, name, request);
1601 ip_unlock(port);
1602 }
316670eb 1603 is_write_unlock(space);
6d2010ae
A
1604
1605 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1606 /*
1607 * validate port is still alive - if so, get request
1608 * types while we still have it locked. Otherwise,
1609 * recapture the (now dead) bits.
1610 */
1611 if (!ipc_right_check(space, port, name, entry)) {
1612 if (request != IE_REQ_NONE)
1613 type |= ipc_port_request_type(port, name, request);
1614 ip_unlock(port);
316670eb 1615 is_write_unlock(space);
6d2010ae 1616 } else {
1c79356b
A
1617 bits = entry->ie_bits;
1618 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
316670eb
A
1619 is_write_unlock(space);
1620 ip_release(port);
6d2010ae 1621 }
316670eb
A
1622 } else {
1623 is_write_unlock(space);
1c79356b
A
1624 }
1625
6d2010ae 1626 type |= IE_BITS_TYPE(bits);
1c79356b
A
1627
1628 *typep = type;
1629 *urefsp = IE_BITS_UREFS(bits);
1630 return KERN_SUCCESS;
1631}
1632
1633/*
1634 * Routine: ipc_right_copyin_check
1635 * Purpose:
1636 * Check if a subsequent ipc_right_copyin would succeed.
1637 * Conditions:
1638 * The space is locked (read or write) and active.
1639 */
1640
1641boolean_t
1642ipc_right_copyin_check(
91447636
A
1643 __assert_only ipc_space_t space,
1644 __unused mach_port_name_t name,
1645 ipc_entry_t entry,
1646 mach_msg_type_name_t msgt_name)
1c79356b
A
1647{
1648 ipc_entry_bits_t bits;
2d21ac55 1649 ipc_port_t port;
1c79356b
A
1650
1651 bits= entry->ie_bits;
316670eb 1652 assert(is_active(space));
1c79356b
A
1653
1654 switch (msgt_name) {
1655 case MACH_MSG_TYPE_MAKE_SEND:
2d21ac55
A
1656 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1657 return FALSE;
2d21ac55
A
1658 break;
1659
1c79356b 1660 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
2d21ac55
A
1661 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1662 return FALSE;
2d21ac55
A
1663 break;
1664
1c79356b
A
1665 case MACH_MSG_TYPE_MOVE_RECEIVE:
1666 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1667 return FALSE;
1c79356b
A
1668 break;
1669
1670 case MACH_MSG_TYPE_COPY_SEND:
1671 case MACH_MSG_TYPE_MOVE_SEND:
1672 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1c79356b
A
1673
1674 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1675 break;
1676
1677 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1678 return FALSE;
1679
1680 port = (ipc_port_t) entry->ie_object;
1681 assert(port != IP_NULL);
1682
fe8ab488
A
1683 /*
1684 * active status peek to avoid checks that will be skipped
1685 * on copyin for dead ports. Lock not held, so will not be
1686 * atomic (but once dead, there's no going back).
1687 */
1688 if (!ip_active(port)) {
1c79356b
A
1689 break;
1690 }
1691
1692 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1693 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1694 return FALSE;
1695 } else {
1696 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1697 return FALSE;
1698 }
1699
1700 break;
1701 }
1702
1703 default:
1704 panic("ipc_right_copyin_check: strange rights");
1705 }
1706
1707 return TRUE;
1708}
1709
1710/*
1711 * Routine: ipc_right_copyin
1712 * Purpose:
1713 * Copyin a capability from a space.
1714 * If successful, the caller gets a ref
1715 * for the resulting object, unless it is IO_DEAD,
1716 * and possibly a send-once right which should
1717 * be used in a port-deleted notification.
1718 *
1719 * If deadok is not TRUE, the copyin operation
1720 * will fail instead of producing IO_DEAD.
1721 *
1722 * The entry is never deallocated (except
1723 * when KERN_INVALID_NAME), so the caller
1724 * should deallocate the entry if its type
1725 * is MACH_PORT_TYPE_NONE.
1726 * Conditions:
1727 * The space is write-locked and active.
1728 * Returns:
1729 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1730 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1731 */
1732
1733kern_return_t
1734ipc_right_copyin(
1735 ipc_space_t space,
1736 mach_port_name_t name,
1737 ipc_entry_t entry,
1738 mach_msg_type_name_t msgt_name,
1739 boolean_t deadok,
1740 ipc_object_t *objectp,
316670eb
A
1741 ipc_port_t *sorightp,
1742 ipc_port_t *releasep,
3e170ce0 1743 int *assertcntp)
1c79356b
A
1744{
1745 ipc_entry_bits_t bits;
316670eb 1746 ipc_port_t port;
fe8ab488 1747
316670eb 1748 *releasep = IP_NULL;
39236c6e 1749 *assertcntp = 0;
39236c6e 1750
1c79356b
A
1751 bits = entry->ie_bits;
1752
316670eb 1753 assert(is_active(space));
1c79356b
A
1754
1755 switch (msgt_name) {
1756 case MACH_MSG_TYPE_MAKE_SEND: {
1c79356b
A
1757
1758 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1759 goto invalid_right;
1760
1761 port = (ipc_port_t) entry->ie_object;
1762 assert(port != IP_NULL);
1763
1764 ip_lock(port);
1765 assert(ip_active(port));
1766 assert(port->ip_receiver_name == name);
1767 assert(port->ip_receiver == space);
1768
1769 port->ip_mscount++;
1770 port->ip_srights++;
1771 ip_reference(port);
1772 ip_unlock(port);
1773
1774 *objectp = (ipc_object_t) port;
1775 *sorightp = IP_NULL;
1776 break;
1777 }
1778
1779 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1c79356b
A
1780
1781 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1782 goto invalid_right;
1783
1784 port = (ipc_port_t) entry->ie_object;
1785 assert(port != IP_NULL);
1786
1787 ip_lock(port);
1788 assert(ip_active(port));
1789 assert(port->ip_receiver_name == name);
1790 assert(port->ip_receiver == space);
1791
1792 port->ip_sorights++;
1793 ip_reference(port);
1794 ip_unlock(port);
1795
1796 *objectp = (ipc_object_t) port;
1797 *sorightp = IP_NULL;
1798 break;
1799 }
1800
1801 case MACH_MSG_TYPE_MOVE_RECEIVE: {
6d2010ae 1802 ipc_port_t request = IP_NULL;
1c79356b
A
1803
1804 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1805 goto invalid_right;
1806
1807 port = (ipc_port_t) entry->ie_object;
1808 assert(port != IP_NULL);
1809
1810 ip_lock(port);
1811 assert(ip_active(port));
1812 assert(port->ip_receiver_name == name);
1813 assert(port->ip_receiver == space);
1814
1815 if (bits & MACH_PORT_TYPE_SEND) {
1816 assert(IE_BITS_TYPE(bits) ==
1817 MACH_PORT_TYPE_SEND_RECEIVE);
1818 assert(IE_BITS_UREFS(bits) > 0);
1819 assert(port->ip_srights > 0);
1820
1821 ipc_hash_insert(space, (ipc_object_t) port,
1822 name, entry);
1823 ip_reference(port);
1824 } else {
1825 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1826 assert(IE_BITS_UREFS(bits) == 0);
1827
6d2010ae 1828 request = ipc_right_request_cancel_macro(space, port,
1c79356b
A
1829 name, entry);
1830 entry->ie_object = IO_NULL;
1831 }
1832 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
316670eb 1833 ipc_entry_modified(space, name, entry);
1c79356b 1834
39037602 1835 (void)ipc_port_clear_receiver(port, FALSE); /* don't destroy the port/mqueue */
1c79356b
A
1836 port->ip_receiver_name = MACH_PORT_NULL;
1837 port->ip_destination = IP_NULL;
39236c6e
A
1838
1839#if IMPORTANCE_INHERITANCE
1840 /*
1841 * Account for boosts the current task is going to lose when
1842 * copying this right in. Tempowner ports have either not
1843 * been accounting to any task (and therefore are already in
1844 * "limbo" state w.r.t. assertions) or to some other specific
1845 * task. As we have no way to drop the latter task's assertions
1846 * here, We'll deduct those when we enqueue it on its
1847 * destination port (see ipc_port_check_circularity()).
1848 */
1849 if (port->ip_tempowner == 0) {
fe8ab488 1850 assert(IIT_NULL == port->ip_imp_task);
39236c6e
A
1851
1852 /* ports in limbo have to be tempowner */
1853 port->ip_tempowner = 1;
1854 *assertcntp = port->ip_impcount;
1855 }
1856#endif /* IMPORTANCE_INHERITANCE */
1857
1c79356b
A
1858 ip_unlock(port);
1859
1860 *objectp = (ipc_object_t) port;
6d2010ae 1861 *sorightp = request;
1c79356b
A
1862 break;
1863 }
1864
1865 case MACH_MSG_TYPE_COPY_SEND: {
1c79356b
A
1866
1867 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1868 goto copy_dead;
1869
1870 /* allow for dead send-once rights */
1871
1872 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1873 goto invalid_right;
1874
1875 assert(IE_BITS_UREFS(bits) > 0);
1876
1877 port = (ipc_port_t) entry->ie_object;
1878 assert(port != IP_NULL);
1879
1880 if (ipc_right_check(space, port, name, entry)) {
1881 bits = entry->ie_bits;
316670eb 1882 *releasep = port;
1c79356b
A
1883 goto copy_dead;
1884 }
1885 /* port is locked and active */
1886
1887 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1888 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1889 assert(port->ip_sorights > 0);
1890
1891 ip_unlock(port);
1892 goto invalid_right;
1893 }
1894
1895 assert(port->ip_srights > 0);
1896
1897 port->ip_srights++;
1898 ip_reference(port);
1899 ip_unlock(port);
1900
1901 *objectp = (ipc_object_t) port;
1902 *sorightp = IP_NULL;
1903 break;
1904 }
1905
1906 case MACH_MSG_TYPE_MOVE_SEND: {
6d2010ae 1907 ipc_port_t request = IP_NULL;
1c79356b
A
1908
1909 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1910 goto move_dead;
1911
1912 /* allow for dead send-once rights */
1913
1914 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1915 goto invalid_right;
1916
1917 assert(IE_BITS_UREFS(bits) > 0);
1918
1919 port = (ipc_port_t) entry->ie_object;
1920 assert(port != IP_NULL);
1921
1922 if (ipc_right_check(space, port, name, entry)) {
1923 bits = entry->ie_bits;
316670eb 1924 *releasep = port;
1c79356b
A
1925 goto move_dead;
1926 }
1927 /* port is locked and active */
1928
1929 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1930 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1931 assert(port->ip_sorights > 0);
1932
1933 ip_unlock(port);
1934 goto invalid_right;
1935 }
1936
1937 assert(port->ip_srights > 0);
1938
1939 if (IE_BITS_UREFS(bits) == 1) {
1940 if (bits & MACH_PORT_TYPE_RECEIVE) {
1941 assert(port->ip_receiver_name == name);
1942 assert(port->ip_receiver == space);
1943 assert(IE_BITS_TYPE(bits) ==
1944 MACH_PORT_TYPE_SEND_RECEIVE);
1945
1946 ip_reference(port);
1947 } else {
1948 assert(IE_BITS_TYPE(bits) ==
1949 MACH_PORT_TYPE_SEND);
1950
6d2010ae 1951 request = ipc_right_request_cancel_macro(space, port,
1c79356b
A
1952 name, entry);
1953 ipc_hash_delete(space, (ipc_object_t) port,
1954 name, entry);
1955 entry->ie_object = IO_NULL;
1956 }
1957 entry->ie_bits = bits &~
1958 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
1959 } else {
1960 port->ip_srights++;
1961 ip_reference(port);
1962 entry->ie_bits = bits-1; /* decrement urefs */
1963 }
316670eb 1964 ipc_entry_modified(space, name, entry);
1c79356b
A
1965 ip_unlock(port);
1966
1967 *objectp = (ipc_object_t) port;
6d2010ae 1968 *sorightp = request;
1c79356b
A
1969 break;
1970 }
1971
1972 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
6d2010ae 1973 ipc_port_t request;
1c79356b
A
1974
1975 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1976 goto move_dead;
1977
1978 /* allow for dead send rights */
1979
1980 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1981 goto invalid_right;
1982
1983 assert(IE_BITS_UREFS(bits) > 0);
1984
1985 port = (ipc_port_t) entry->ie_object;
1986 assert(port != IP_NULL);
1987
1988 if (ipc_right_check(space, port, name, entry)) {
1989 bits = entry->ie_bits;
3e170ce0 1990 *releasep = port;
1c79356b
A
1991 goto move_dead;
1992 }
1993 /* port is locked and active */
1994
1995 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
1996 assert(bits & MACH_PORT_TYPE_SEND);
1997 assert(port->ip_srights > 0);
1998
1999 ip_unlock(port);
2000 goto invalid_right;
2001 }
2002
2003 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2004 assert(IE_BITS_UREFS(bits) == 1);
2005 assert(port->ip_sorights > 0);
2006
6d2010ae 2007 request = ipc_right_request_cancel_macro(space, port, name, entry);
1c79356b
A
2008 ip_unlock(port);
2009
2010 entry->ie_object = IO_NULL;
2011 entry->ie_bits = bits &~
2012 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
316670eb 2013 ipc_entry_modified(space, name, entry);
1c79356b 2014 *objectp = (ipc_object_t) port;
6d2010ae 2015 *sorightp = request;
1c79356b
A
2016 break;
2017 }
2018
2019 default:
2020 invalid_right:
2021 return KERN_INVALID_RIGHT;
2022 }
2023
2024 return KERN_SUCCESS;
2025
2026 copy_dead:
2027 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2028 assert(IE_BITS_UREFS(bits) > 0);
6d2010ae 2029 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
2030 assert(entry->ie_object == 0);
2031
2032 if (!deadok)
2033 goto invalid_right;
2034
2035 *objectp = IO_DEAD;
2036 *sorightp = IP_NULL;
2037 return KERN_SUCCESS;
2038
2039 move_dead:
2040 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2041 assert(IE_BITS_UREFS(bits) > 0);
6d2010ae 2042 assert(entry->ie_request == IE_REQ_NONE);
1c79356b
A
2043 assert(entry->ie_object == 0);
2044
2045 if (!deadok)
2046 goto invalid_right;
2047
2048 if (IE_BITS_UREFS(bits) == 1) {
2049 bits &= ~MACH_PORT_TYPE_DEAD_NAME;
2050 }
2051 entry->ie_bits = bits-1; /* decrement urefs */
316670eb 2052 ipc_entry_modified(space, name, entry);
1c79356b
A
2053 *objectp = IO_DEAD;
2054 *sorightp = IP_NULL;
2055 return KERN_SUCCESS;
2056
2057}
2058
2059/*
2060 * Routine: ipc_right_copyin_undo
2061 * Purpose:
2062 * Undoes the effects of an ipc_right_copyin
2063 * of a send/send-once right that is dead.
2064 * (Object is either IO_DEAD or a dead port.)
2065 * Conditions:
2066 * The space is write-locked and active.
2067 */
2068
2069void
2070ipc_right_copyin_undo(
2071 ipc_space_t space,
2072 mach_port_name_t name,
2073 ipc_entry_t entry,
2074 mach_msg_type_name_t msgt_name,
2075 ipc_object_t object,
2076 ipc_port_t soright)
2077{
2078 ipc_entry_bits_t bits;
2079
2080 bits = entry->ie_bits;
2081
316670eb 2082 assert(is_active(space));
1c79356b
A
2083
2084 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2085 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
2086 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2087
2088 if (soright != IP_NULL) {
2089 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2090 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2091 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2092 assert(object != IO_DEAD);
2093
2094 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
2095 MACH_PORT_TYPE_DEAD_NAME | 2);
2096
2097 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
2098 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2099 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2100
2101 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
2102 MACH_PORT_TYPE_DEAD_NAME | 1);
2103 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
2104 assert(object == IO_DEAD);
2105 assert(IE_BITS_UREFS(bits) > 0);
2106
2107 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2108 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
2109 entry->ie_bits = bits+1; /* increment urefs */
2110 }
2111 } else {
2112 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2113 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
2114 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2115 assert(object != IO_DEAD);
2116 assert(entry->ie_object == object);
2117 assert(IE_BITS_UREFS(bits) > 0);
2118
2119 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2120 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
2121 entry->ie_bits = bits+1; /* increment urefs */
2122 }
2123
2124 /*
2125 * May as well convert the entry to a dead name.
2126 * (Or if it is a compat entry, destroy it.)
2127 */
2128
2129 (void) ipc_right_check(space, (ipc_port_t) object,
2130 name, entry);
2131 /* object is dead so it is not locked */
2132 }
316670eb 2133 ipc_entry_modified(space, name, entry);
1c79356b
A
2134 /* release the reference acquired by copyin */
2135
2136 if (object != IO_DEAD)
316670eb 2137 io_release(object);
1c79356b
A
2138}
2139
2140/*
fe8ab488 2141 * Routine: ipc_right_copyin_two_move_sends
1c79356b
A
2142 * Purpose:
2143 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2144 * and deadok == FALSE, except that this moves two
2145 * send rights at once.
2146 * Conditions:
2147 * The space is write-locked and active.
2148 * The object is returned with two refs/send rights.
2149 * Returns:
2150 * KERN_SUCCESS Acquired an object.
2151 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2152 */
fe8ab488 2153static
1c79356b 2154kern_return_t
fe8ab488 2155ipc_right_copyin_two_move_sends(
1c79356b
A
2156 ipc_space_t space,
2157 mach_port_name_t name,
2158 ipc_entry_t entry,
2159 ipc_object_t *objectp,
316670eb
A
2160 ipc_port_t *sorightp,
2161 ipc_port_t *releasep)
1c79356b
A
2162{
2163 ipc_entry_bits_t bits;
2164 mach_port_urefs_t urefs;
2165 ipc_port_t port;
6d2010ae 2166 ipc_port_t request = IP_NULL;
1c79356b 2167
316670eb
A
2168 *releasep = IP_NULL;
2169
2170 assert(is_active(space));
1c79356b
A
2171
2172 bits = entry->ie_bits;
2173
2174 if ((bits & MACH_PORT_TYPE_SEND) == 0)
2175 goto invalid_right;
2176
2177 urefs = IE_BITS_UREFS(bits);
2178 if (urefs < 2)
2179 goto invalid_right;
2180
2181 port = (ipc_port_t) entry->ie_object;
2182 assert(port != IP_NULL);
2183
2184 if (ipc_right_check(space, port, name, entry)) {
316670eb 2185 *releasep = port;
1c79356b
A
2186 goto invalid_right;
2187 }
2188 /* port is locked and active */
2189
2190 assert(port->ip_srights > 0);
2191
2192 if (urefs == 2) {
2193 if (bits & MACH_PORT_TYPE_RECEIVE) {
2194 assert(port->ip_receiver_name == name);
2195 assert(port->ip_receiver == space);
2196 assert(IE_BITS_TYPE(bits) ==
2197 MACH_PORT_TYPE_SEND_RECEIVE);
2198
2199 port->ip_srights++;
2200 ip_reference(port);
2201 ip_reference(port);
2202 } else {
2203 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2204
6d2010ae 2205 request = ipc_right_request_cancel_macro(space, port,
1c79356b
A
2206 name, entry);
2207
2208 port->ip_srights++;
2209 ip_reference(port);
2210 ipc_hash_delete(space, (ipc_object_t) port,
2211 name, entry);
2212 entry->ie_object = IO_NULL;
2213 }
2214 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2215 } else {
2216 port->ip_srights += 2;
2217 ip_reference(port);
2218 ip_reference(port);
2219 entry->ie_bits = bits-2; /* decrement urefs */
2220 }
316670eb
A
2221 ipc_entry_modified(space, name, entry);
2222
1c79356b
A
2223 ip_unlock(port);
2224
2225 *objectp = (ipc_object_t) port;
6d2010ae 2226 *sorightp = request;
1c79356b
A
2227 return KERN_SUCCESS;
2228
2229 invalid_right:
2230 return KERN_INVALID_RIGHT;
2231}
2232
fe8ab488
A
2233
2234/*
2235 * Routine: ipc_right_copyin_two
2236 * Purpose:
2237 * Like ipc_right_copyin with two dispositions,
2238 * each of which results in a send or send-once right,
2239 * and deadok = FALSE.
2240 * Conditions:
2241 * The space is write-locked and active.
2242 * The object is returned with two refs/rights.
2243 * Returns:
2244 * KERN_SUCCESS Acquired an object.
2245 * KERN_INVALID_RIGHT Name doesn't denote correct right(s).
2246 * KERN_INVALID_CAPABILITY Name doesn't denote correct right for msgt_two.
2247 */
2248kern_return_t
2249ipc_right_copyin_two(
2250 ipc_space_t space,
2251 mach_port_name_t name,
2252 ipc_entry_t entry,
2253 mach_msg_type_name_t msgt_one,
2254 mach_msg_type_name_t msgt_two,
2255 ipc_object_t *objectp,
2256 ipc_port_t *sorightp,
2257 ipc_port_t *releasep)
2258{
fe8ab488 2259 kern_return_t kr;
fe8ab488 2260 int assertcnt = 0;
fe8ab488
A
2261
2262 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one));
2263 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two));
2264
2265
2266 /*
2267 * Pre-validate the second disposition is possible all by itself.
2268 */
2269 if (!ipc_right_copyin_check(space, name, entry, msgt_two)) {
2270 return KERN_INVALID_CAPABILITY;
2271 }
2272
2273 /*
2274 * This is a little tedious to make atomic, because
2275 * there are 25 combinations of valid dispositions.
2276 * However, most are easy.
2277 */
2278
2279 /*
2280 * If either is move-sonce, then there must be an error.
2281 */
2282 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND_ONCE ||
2283 msgt_two == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
2284 return KERN_INVALID_RIGHT;
2285 }
2286
2287 if ((msgt_one == MACH_MSG_TYPE_MAKE_SEND) ||
2288 (msgt_one == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
2289 (msgt_two == MACH_MSG_TYPE_MAKE_SEND) ||
2290 (msgt_two == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
2291 /*
2292 * One of the dispositions needs a receive right.
2293 *
2294 * If the copyin below succeeds, we know the receive
2295 * right is there (because the pre-validation of
2296 * the second disposition already succeeded in our
2297 * caller).
2298 *
2299 * Hence the port is not in danger of dying.
2300 */
2301 ipc_object_t object_two;
2302
fe8ab488
A
2303 kr = ipc_right_copyin(space, name, entry,
2304 msgt_one, FALSE,
2305 objectp, sorightp, releasep,
3e170ce0 2306 &assertcnt);
fe8ab488 2307 assert(assertcnt == 0);
fe8ab488
A
2308 if (kr != KERN_SUCCESS) {
2309 return kr;
2310 }
2311
2312 assert(IO_VALID(*objectp));
2313 assert(*sorightp == IP_NULL);
2314 assert(*releasep == IP_NULL);
2315
2316 /*
2317 * Now copyin the second (previously validated)
2318 * disposition. The result can't be a dead port,
2319 * as no valid disposition can make us lose our
2320 * receive right.
2321 */
fe8ab488
A
2322 kr = ipc_right_copyin(space, name, entry,
2323 msgt_two, FALSE,
2324 &object_two, sorightp, releasep,
3e170ce0 2325 &assertcnt);
fe8ab488 2326 assert(assertcnt == 0);
fe8ab488
A
2327 assert(kr == KERN_SUCCESS);
2328 assert(*sorightp == IP_NULL);
2329 assert(*releasep == IP_NULL);
2330 assert(object_two == *objectp);
2331 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
2332
2333 } else if ((msgt_one == MACH_MSG_TYPE_MOVE_SEND) &&
2334 (msgt_two == MACH_MSG_TYPE_MOVE_SEND)) {
2335 /*
2336 * This is an easy case. Just use our
2337 * handy-dandy special-purpose copyin call
2338 * to get two send rights for the price of one.
2339 */
2340 kr = ipc_right_copyin_two_move_sends(space, name, entry,
2341 objectp, sorightp,
2342 releasep);
2343 if (kr != KERN_SUCCESS) {
2344 return kr;
2345 }
2346
2347 } else {
2348 mach_msg_type_name_t msgt_name;
2349
2350 /*
2351 * Must be either a single move-send and a
2352 * copy-send, or two copy-send dispositions.
2353 * Use the disposition with the greatest side
2354 * effects for the actual copyin - then just
2355 * duplicate the send right you get back.
2356 */
2357 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND ||
2358 msgt_two == MACH_MSG_TYPE_MOVE_SEND) {
2359 msgt_name = MACH_MSG_TYPE_MOVE_SEND;
2360 } else {
2361 msgt_name = MACH_MSG_TYPE_COPY_SEND;
2362 }
2363
fe8ab488
A
2364 kr = ipc_right_copyin(space, name, entry,
2365 msgt_name, FALSE,
2366 objectp, sorightp, releasep,
3e170ce0 2367 &assertcnt);
fe8ab488 2368 assert(assertcnt == 0);
fe8ab488
A
2369 if (kr != KERN_SUCCESS) {
2370 return kr;
2371 }
2372
2373 /*
2374 * Copy the right we got back. If it is dead now,
2375 * that's OK. Neither right will be usable to send
2376 * a message anyway.
2377 */
2378 (void)ipc_port_copy_send((ipc_port_t)*objectp);
2379 }
2380
fe8ab488
A
2381 return KERN_SUCCESS;
2382}
2383
2384
1c79356b
A
2385/*
2386 * Routine: ipc_right_copyout
2387 * Purpose:
2388 * Copyout a capability to a space.
2389 * If successful, consumes a ref for the object.
2390 *
2391 * Always succeeds when given a newly-allocated entry,
2392 * because user-reference overflow isn't a possibility.
2393 *
2394 * If copying out the object would cause the user-reference
2395 * count in the entry to overflow, and overflow is TRUE,
2396 * then instead the user-reference count is left pegged
2397 * to its maximum value and the copyout succeeds anyway.
2398 * Conditions:
2399 * The space is write-locked and active.
2400 * The object is locked and active.
2401 * The object is unlocked; the space isn't.
2402 * Returns:
2403 * KERN_SUCCESS Copied out capability.
2404 * KERN_UREFS_OVERFLOW User-refs would overflow;
2405 * guaranteed not to happen with a fresh entry
2406 * or if overflow=TRUE was specified.
2407 */
2408
2409kern_return_t
2410ipc_right_copyout(
2411 ipc_space_t space,
2412 mach_port_name_t name,
2413 ipc_entry_t entry,
2414 mach_msg_type_name_t msgt_name,
2415 boolean_t overflow,
2416 ipc_object_t object)
2417{
2418 ipc_entry_bits_t bits;
2419 ipc_port_t port;
2420
2421 bits = entry->ie_bits;
2422
2423 assert(IO_VALID(object));
2424 assert(io_otype(object) == IOT_PORT);
2425 assert(io_active(object));
2426 assert(entry->ie_object == object);
2427
2428 port = (ipc_port_t) object;
2429
2430 switch (msgt_name) {
2431 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2432
2433 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2434 assert(port->ip_sorights > 0);
2435
2436 /* transfer send-once right and ref to entry */
2437 ip_unlock(port);
2438
2439 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
316670eb 2440 ipc_entry_modified(space, name, entry);
1c79356b
A
2441 break;
2442
2443 case MACH_MSG_TYPE_PORT_SEND:
2444 assert(port->ip_srights > 0);
2445
2446 if (bits & MACH_PORT_TYPE_SEND) {
2447 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2448
2449 assert(port->ip_srights > 1);
2450 assert(urefs > 0);
2451 assert(urefs < MACH_PORT_UREFS_MAX);
2452
2453 if (urefs+1 == MACH_PORT_UREFS_MAX) {
2454 if (overflow) {
2455 /* leave urefs pegged to maximum */
2456
2457 port->ip_srights--;
1c79356b 2458 ip_unlock(port);
316670eb 2459 ip_release(port);
1c79356b
A
2460 return KERN_SUCCESS;
2461 }
2462
2463 ip_unlock(port);
2464 return KERN_UREFS_OVERFLOW;
2465 }
1c79356b 2466 port->ip_srights--;
1c79356b 2467 ip_unlock(port);
316670eb
A
2468 ip_release(port);
2469
1c79356b
A
2470 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2471 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2472 assert(IE_BITS_UREFS(bits) == 0);
2473
2474 /* transfer send right to entry */
1c79356b 2475 ip_unlock(port);
316670eb
A
2476 ip_release(port);
2477
1c79356b
A
2478 } else {
2479 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2480 assert(IE_BITS_UREFS(bits) == 0);
2481
2482 /* transfer send right and ref to entry */
2483 ip_unlock(port);
2484
2485 /* entry is locked holding ref, so can use port */
2486
2487 ipc_hash_insert(space, (ipc_object_t) port,
2488 name, entry);
2489 }
2490
2491 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
316670eb 2492 ipc_entry_modified(space, name, entry);
1c79356b
A
2493 break;
2494
2495 case MACH_MSG_TYPE_PORT_RECEIVE: {
2496 ipc_port_t dest;
2497
39236c6e
A
2498#if IMPORTANCE_INHERITANCE
2499 natural_t assertcnt = port->ip_impcount;
2500#endif /* IMPORTANCE_INHERITANCE */
2501
1c79356b
A
2502 assert(port->ip_mscount == 0);
2503 assert(port->ip_receiver_name == MACH_PORT_NULL);
2504 dest = port->ip_destination;
2505
2506 port->ip_receiver_name = name;
2507 port->ip_receiver = space;
2508
2509 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2510
2511 if (bits & MACH_PORT_TYPE_SEND) {
2512 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2513 assert(IE_BITS_UREFS(bits) > 0);
2514 assert(port->ip_srights > 0);
2515
1c79356b 2516 ip_unlock(port);
316670eb 2517 ip_release(port);
1c79356b
A
2518
2519 /* entry is locked holding ref, so can use port */
2520
2521 ipc_hash_delete(space, (ipc_object_t) port,
2522 name, entry);
2523 } else {
2524 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2525 assert(IE_BITS_UREFS(bits) == 0);
2526
2527 /* transfer ref to entry */
2528 ip_unlock(port);
2529 }
2530 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
316670eb 2531 ipc_entry_modified(space, name, entry);
1c79356b 2532
39236c6e
A
2533 if (dest != IP_NULL) {
2534#if IMPORTANCE_INHERITANCE
2535 /*
2536 * Deduct the assertion counts we contributed to
2537 * the old destination port. They've already
2538 * been reflected into the task as a result of
2539 * getting enqueued.
2540 */
2541 ip_lock(dest);
fe8ab488 2542 ipc_port_impcount_delta(dest, 0 - assertcnt, IP_NULL);
39236c6e
A
2543 ip_unlock(dest);
2544#endif /* IMPORTANCE_INHERITANCE */
316670eb 2545 ip_release(dest);
39236c6e 2546 }
1c79356b
A
2547 break;
2548 }
2549
2550 default:
2551 panic("ipc_right_copyout: strange rights");
2552 }
1c79356b
A
2553 return KERN_SUCCESS;
2554}
2555
2556/*
2557 * Routine: ipc_right_rename
2558 * Purpose:
2559 * Transfer an entry from one name to another.
2560 * The old entry is deallocated.
2561 * Conditions:
2562 * The space is write-locked and active.
2563 * The new entry is unused. Upon return,
2564 * the space is unlocked.
2565 * Returns:
2566 * KERN_SUCCESS Moved entry to new name.
2567 */
2568
2569kern_return_t
2570ipc_right_rename(
2571 ipc_space_t space,
2572 mach_port_name_t oname,
2573 ipc_entry_t oentry,
2574 mach_port_name_t nname,
2575 ipc_entry_t nentry)
2576{
2577 ipc_port_request_index_t request = oentry->ie_request;
2578 ipc_entry_bits_t bits = oentry->ie_bits;
2579 ipc_object_t object = oentry->ie_object;
316670eb 2580 ipc_port_t release_port = IP_NULL;
1c79356b 2581
316670eb 2582 assert(is_active(space));
1c79356b
A
2583 assert(oname != nname);
2584
2585 /*
2586 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2587 * if the port is dead. (This would foil ipc_port_destroy.)
2588 * Instead we should fail because oentry shouldn't exist.
2589 * Note IE_BITS_COMPAT implies ie_request != 0.
2590 */
2591
6d2010ae 2592 if (request != IE_REQ_NONE) {
1c79356b
A
2593 ipc_port_t port;
2594
2595 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2596 port = (ipc_port_t) object;
2597 assert(port != IP_NULL);
2598
2599 if (ipc_right_check(space, port, oname, oentry)) {
6d2010ae 2600 request = IE_REQ_NONE;
1c79356b
A
2601 object = IO_NULL;
2602 bits = oentry->ie_bits;
316670eb 2603 release_port = port;
1c79356b 2604 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
6d2010ae 2605 assert(oentry->ie_request == IE_REQ_NONE);
1c79356b
A
2606 } else {
2607 /* port is locked and active */
2608
6d2010ae 2609 ipc_port_request_rename(port, request, oname, nname);
1c79356b 2610 ip_unlock(port);
6d2010ae 2611 oentry->ie_request = IE_REQ_NONE;
1c79356b
A
2612 }
2613 }
2614
2615 /* initialize nentry before letting ipc_hash_insert see it */
2616
2617 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2618 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2619 nentry->ie_request = request;
2620 nentry->ie_object = object;
2621
2622 switch (IE_BITS_TYPE(bits)) {
2623 case MACH_PORT_TYPE_SEND: {
2624 ipc_port_t port;
2625
2626 port = (ipc_port_t) object;
2627 assert(port != IP_NULL);
2628
2629 /* remember, there are no other share entries possible */
2630 /* or we can't do the rename. Therefore we do not need */
2631 /* to check the other subspaces */
2632 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2633 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2634 break;
2635 }
2636
2637 case MACH_PORT_TYPE_RECEIVE:
2638 case MACH_PORT_TYPE_SEND_RECEIVE: {
2639 ipc_port_t port;
2640
2641 port = (ipc_port_t) object;
2642 assert(port != IP_NULL);
2643
2644 ip_lock(port);
2645 assert(ip_active(port));
2646 assert(port->ip_receiver_name == oname);
2647 assert(port->ip_receiver == space);
2648
2649 port->ip_receiver_name = nname;
2650 ip_unlock(port);
2651 break;
2652 }
2653
2654 case MACH_PORT_TYPE_PORT_SET: {
2655 ipc_pset_t pset;
2656
2657 pset = (ipc_pset_t) object;
2658 assert(pset != IPS_NULL);
2659
2660 ips_lock(pset);
2661 assert(ips_active(pset));
1c79356b 2662
1c79356b
A
2663 ips_unlock(pset);
2664 break;
2665 }
2666
2667 case MACH_PORT_TYPE_SEND_ONCE:
2668 case MACH_PORT_TYPE_DEAD_NAME:
2669 break;
2670
2671 default:
2672 panic("ipc_right_rename: strange rights");
2673 }
2674
6d2010ae 2675 assert(oentry->ie_request == IE_REQ_NONE);
1c79356b
A
2676 oentry->ie_object = IO_NULL;
2677 ipc_entry_dealloc(space, oname, oentry);
316670eb 2678 ipc_entry_modified(space, nname, nentry);
1c79356b
A
2679 is_write_unlock(space);
2680
316670eb
A
2681 if (release_port != IP_NULL)
2682 ip_release(release_port);
2683
1c79356b
A
2684 return KERN_SUCCESS;
2685}