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