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