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