]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_right.c
xnu-3789.41.3.tar.gz
[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 mach_port_mscount_t mscount = 0;
1314
1315 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1316 goto invalid_right;
1317
1318 /* maximum urefs for send is MACH_PORT_UREFS_MAX */
1319
1320 port = (ipc_port_t) entry->ie_object;
1321 assert(port != IP_NULL);
1322
1323 if (ipc_right_check(space, port, name, entry)) {
1324 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
1325 goto invalid_right;
1326 }
1327 /* port is locked and active */
1328
1329 assert(port->ip_srights > 0);
1330
1331 if (delta > ((mach_port_delta_t)MACH_PORT_UREFS_MAX) ||
1332 delta < (-((mach_port_delta_t)MACH_PORT_UREFS_MAX))) {
1333 ip_unlock(port);
1334 goto invalid_value;
1335 }
1336
1337 urefs = IE_BITS_UREFS(bits);
1338
1339 if (urefs == MACH_PORT_UREFS_MAX) {
1340 /*
1341 * urefs are pegged due to an overflow
1342 * only a delta removing all refs at once can change it
1343 */
1344
1345 if (delta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX)))
1346 delta = 0;
1347 } else {
1348 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
1349 ip_unlock(port);
1350 goto invalid_value;
1351 }
1352 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) {
1353 /* leave urefs pegged to maximum if it overflowed */
1354 delta = MACH_PORT_UREFS_MAX - urefs;
1355 }
1356 }
1357
1358 if ((urefs + delta) == 0) {
1359 if (--port->ip_srights == 0) {
1360 nsrequest = port->ip_nsrequest;
1361 if (nsrequest != IP_NULL) {
1362 port->ip_nsrequest = IP_NULL;
1363 mscount = port->ip_mscount;
1364 }
1365 }
1366
1367 if (bits & MACH_PORT_TYPE_RECEIVE) {
1368 assert(port->ip_receiver_name == name);
1369 assert(port->ip_receiver == space);
1370 ip_unlock(port);
1371 assert(IE_BITS_TYPE(bits) ==
1372 MACH_PORT_TYPE_SEND_RECEIVE);
1373
1374 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1375 MACH_PORT_TYPE_SEND);
1376 ipc_entry_modified(space, name, entry);
1377 } else {
1378 assert(IE_BITS_TYPE(bits) ==
1379 MACH_PORT_TYPE_SEND);
1380
1381 request = ipc_right_request_cancel_macro(space, port,
1382 name, entry);
1383 ipc_hash_delete(space, (ipc_object_t) port,
1384 name, entry);
1385
1386 ip_unlock(port);
1387 ip_release(port);
1388
1389 entry->ie_object = IO_NULL;
1390 ipc_entry_dealloc(space, name, entry);
1391 }
1392 } else if (delta != 0) {
1393 ip_unlock(port);
1394 entry->ie_bits = bits + delta;
1395 ipc_entry_modified(space, name, entry);
1396 } else {
1397 ip_unlock(port);
1398 }
1399
1400 is_write_unlock(space);
1401
1402 if (nsrequest != IP_NULL)
1403 ipc_notify_no_senders(nsrequest, mscount);
1404
1405 if (request != IP_NULL)
1406 ipc_notify_port_deleted(request, name);
1407 break;
1408 }
1409
1410 default:
1411 panic("ipc_right_delta: strange right");
1412 }
1413
1414 return KERN_SUCCESS;
1415
1416 success:
1417 is_write_unlock(space);
1418 return KERN_SUCCESS;
1419
1420 invalid_right:
1421 is_write_unlock(space);
1422 if (port != IP_NULL)
1423 ip_release(port);
1424 return KERN_INVALID_RIGHT;
1425
1426 invalid_value:
1427 is_write_unlock(space);
1428 return KERN_INVALID_VALUE;
1429
1430 guard_failure:
1431 return KERN_INVALID_RIGHT;
1432 }
1433
1434 /*
1435 * Routine: ipc_right_destruct
1436 * Purpose:
1437 * Deallocates the receive right and modifies the
1438 * user-reference count for the send rights as requested.
1439 * Conditions:
1440 * The space is write-locked, and is unlocked upon return.
1441 * The space must be active.
1442 * Returns:
1443 * KERN_SUCCESS Count was modified.
1444 * KERN_INVALID_RIGHT Entry has wrong type.
1445 * KERN_INVALID_VALUE Bad delta for the right.
1446 */
1447
1448 kern_return_t
1449 ipc_right_destruct(
1450 ipc_space_t space,
1451 mach_port_name_t name,
1452 ipc_entry_t entry,
1453 mach_port_delta_t srdelta,
1454 uint64_t guard)
1455 {
1456 ipc_port_t port = IP_NULL;
1457 ipc_entry_bits_t bits;
1458
1459 mach_port_urefs_t urefs;
1460 ipc_port_t request = IP_NULL;
1461 ipc_port_t nsrequest = IP_NULL;
1462 mach_port_mscount_t mscount = 0;
1463
1464 bits = entry->ie_bits;
1465
1466 assert(is_active(space));
1467
1468 if (((bits & MACH_PORT_TYPE_RECEIVE) == 0) ||
1469 (srdelta && ((bits & MACH_PORT_TYPE_SEND) == 0))) {
1470 is_write_unlock(space);
1471 return KERN_INVALID_RIGHT;
1472 }
1473
1474 if (srdelta > 0)
1475 goto invalid_value;
1476
1477 port = (ipc_port_t) entry->ie_object;
1478 assert(port != IP_NULL);
1479
1480 ip_lock(port);
1481 assert(ip_active(port));
1482 assert(port->ip_receiver_name == name);
1483 assert(port->ip_receiver == space);
1484
1485 /* Mach Port Guard Checking */
1486 if(port->ip_guarded && (guard != port->ip_context)) {
1487 uint64_t portguard = port->ip_context;
1488 ip_unlock(port);
1489 is_write_unlock(space);
1490 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY);
1491 return KERN_INVALID_ARGUMENT;
1492 }
1493
1494 /*
1495 * First reduce the send rights as requested and
1496 * adjust the entry->ie_bits accordingly. The
1497 * ipc_entry_modified() call is made once the receive
1498 * right is destroyed too.
1499 */
1500
1501 if (srdelta) {
1502
1503 assert(port->ip_srights > 0);
1504
1505 urefs = IE_BITS_UREFS(bits);
1506
1507 /*
1508 * Since we made sure that srdelta is negative,
1509 * the check for urefs overflow is not required.
1510 */
1511 if (MACH_PORT_UREFS_UNDERFLOW(urefs, srdelta)) {
1512 ip_unlock(port);
1513 goto invalid_value;
1514 }
1515
1516 if (urefs == MACH_PORT_UREFS_MAX) {
1517 /*
1518 * urefs are pegged due to an overflow
1519 * only a delta removing all refs at once can change it
1520 */
1521 if (srdelta != (-((mach_port_delta_t)MACH_PORT_UREFS_MAX)))
1522 srdelta = 0;
1523 }
1524
1525 if ((urefs + srdelta) == 0) {
1526 if (--port->ip_srights == 0) {
1527 nsrequest = port->ip_nsrequest;
1528 if (nsrequest != IP_NULL) {
1529 port->ip_nsrequest = IP_NULL;
1530 mscount = port->ip_mscount;
1531 }
1532 }
1533 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_RECEIVE);
1534 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
1535 MACH_PORT_TYPE_SEND);
1536 } else {
1537 entry->ie_bits = bits + srdelta;
1538 }
1539 }
1540
1541 /*
1542 * Now destroy the receive right. Update space and
1543 * entry accordingly.
1544 */
1545
1546 bits = entry->ie_bits;
1547 if (bits & MACH_PORT_TYPE_SEND) {
1548 assert(IE_BITS_UREFS(bits) > 0);
1549 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
1550
1551 if (port->ip_pdrequest != NULL) {
1552 /*
1553 * Since another task has requested a
1554 * destroy notification for this port, it
1555 * isn't actually being destroyed - the receive
1556 * right is just being moved to another task.
1557 * Since we still have one or more send rights,
1558 * we need to record the loss of the receive
1559 * right and enter the remaining send right
1560 * into the hash table.
1561 */
1562 ipc_entry_modified(space, name, entry);
1563 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE;
1564 ipc_hash_insert(space, (ipc_object_t) port,
1565 name, entry);
1566 ip_reference(port);
1567 } else {
1568 /*
1569 * The remaining send right turns into a
1570 * dead name. Notice we don't decrement
1571 * ip_srights, generate a no-senders notif,
1572 * or use ipc_right_dncancel, because the
1573 * port is destroyed "first".
1574 */
1575 bits &= ~IE_BITS_TYPE_MASK;
1576 bits |= MACH_PORT_TYPE_DEAD_NAME;
1577 if (entry->ie_request) {
1578 entry->ie_request = IE_REQ_NONE;
1579 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
1580 bits++; /* increment urefs */
1581 }
1582 entry->ie_bits = bits;
1583 entry->ie_object = IO_NULL;
1584 ipc_entry_modified(space, name, entry);
1585 }
1586 } else {
1587 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1588 assert(IE_BITS_UREFS(bits) == 0);
1589 request = ipc_right_request_cancel_macro(space, port,
1590 name, entry);
1591 entry->ie_object = IO_NULL;
1592 ipc_entry_dealloc(space, name, entry);
1593 }
1594
1595 /* Unlock space */
1596 is_write_unlock(space);
1597
1598 if (nsrequest != IP_NULL)
1599 ipc_notify_no_senders(nsrequest, mscount);
1600
1601 ipc_port_destroy(port); /* clears receiver, consumes ref, unlocks */
1602
1603 if (request != IP_NULL)
1604 ipc_notify_port_deleted(request, name);
1605
1606 return KERN_SUCCESS;
1607
1608 invalid_value:
1609 is_write_unlock(space);
1610 return KERN_INVALID_VALUE;
1611
1612 }
1613
1614
1615 /*
1616 * Routine: ipc_right_info
1617 * Purpose:
1618 * Retrieves information about the right.
1619 * Conditions:
1620 * The space is active and write-locked.
1621 * The space is unlocked upon return.
1622 * Returns:
1623 * KERN_SUCCESS Retrieved info
1624 */
1625
1626 kern_return_t
1627 ipc_right_info(
1628 ipc_space_t space,
1629 mach_port_name_t name,
1630 ipc_entry_t entry,
1631 mach_port_type_t *typep,
1632 mach_port_urefs_t *urefsp)
1633 {
1634 ipc_port_t port;
1635 ipc_entry_bits_t bits;
1636 mach_port_type_t type = 0;
1637 ipc_port_request_index_t request;
1638
1639 bits = entry->ie_bits;
1640 request = entry->ie_request;
1641 port = (ipc_port_t) entry->ie_object;
1642
1643 if (bits & MACH_PORT_TYPE_RECEIVE) {
1644 assert(IP_VALID(port));
1645
1646 if (request != IE_REQ_NONE) {
1647 ip_lock(port);
1648 assert(ip_active(port));
1649 type |= ipc_port_request_type(port, name, request);
1650 ip_unlock(port);
1651 }
1652 is_write_unlock(space);
1653
1654 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
1655 /*
1656 * validate port is still alive - if so, get request
1657 * types while we still have it locked. Otherwise,
1658 * recapture the (now dead) bits.
1659 */
1660 if (!ipc_right_check(space, port, name, entry)) {
1661 if (request != IE_REQ_NONE)
1662 type |= ipc_port_request_type(port, name, request);
1663 ip_unlock(port);
1664 is_write_unlock(space);
1665 } else {
1666 bits = entry->ie_bits;
1667 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
1668 is_write_unlock(space);
1669 ip_release(port);
1670 }
1671 } else {
1672 is_write_unlock(space);
1673 }
1674
1675 type |= IE_BITS_TYPE(bits);
1676
1677 *typep = type;
1678 *urefsp = IE_BITS_UREFS(bits);
1679 return KERN_SUCCESS;
1680 }
1681
1682 /*
1683 * Routine: ipc_right_copyin_check
1684 * Purpose:
1685 * Check if a subsequent ipc_right_copyin would succeed.
1686 * Conditions:
1687 * The space is locked (read or write) and active.
1688 */
1689
1690 boolean_t
1691 ipc_right_copyin_check(
1692 __assert_only ipc_space_t space,
1693 __unused mach_port_name_t name,
1694 ipc_entry_t entry,
1695 mach_msg_type_name_t msgt_name)
1696 {
1697 ipc_entry_bits_t bits;
1698 ipc_port_t port;
1699
1700 bits= entry->ie_bits;
1701 assert(is_active(space));
1702
1703 switch (msgt_name) {
1704 case MACH_MSG_TYPE_MAKE_SEND:
1705 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1706 return FALSE;
1707 break;
1708
1709 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1710 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1711 return FALSE;
1712 break;
1713
1714 case MACH_MSG_TYPE_MOVE_RECEIVE:
1715 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1716 return FALSE;
1717 break;
1718
1719 case MACH_MSG_TYPE_COPY_SEND:
1720 case MACH_MSG_TYPE_MOVE_SEND:
1721 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1722
1723 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1724 break;
1725
1726 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1727 return FALSE;
1728
1729 port = (ipc_port_t) entry->ie_object;
1730 assert(port != IP_NULL);
1731
1732 /*
1733 * active status peek to avoid checks that will be skipped
1734 * on copyin for dead ports. Lock not held, so will not be
1735 * atomic (but once dead, there's no going back).
1736 */
1737 if (!ip_active(port)) {
1738 break;
1739 }
1740
1741 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
1742 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
1743 return FALSE;
1744 } else {
1745 if ((bits & MACH_PORT_TYPE_SEND) == 0)
1746 return FALSE;
1747 }
1748
1749 break;
1750 }
1751
1752 default:
1753 panic("ipc_right_copyin_check: strange rights");
1754 }
1755
1756 return TRUE;
1757 }
1758
1759 /*
1760 * Routine: ipc_right_copyin
1761 * Purpose:
1762 * Copyin a capability from a space.
1763 * If successful, the caller gets a ref
1764 * for the resulting object, unless it is IO_DEAD,
1765 * and possibly a send-once right which should
1766 * be used in a port-deleted notification.
1767 *
1768 * If deadok is not TRUE, the copyin operation
1769 * will fail instead of producing IO_DEAD.
1770 *
1771 * The entry is never deallocated (except
1772 * when KERN_INVALID_NAME), so the caller
1773 * should deallocate the entry if its type
1774 * is MACH_PORT_TYPE_NONE.
1775 * Conditions:
1776 * The space is write-locked and active.
1777 * Returns:
1778 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
1779 * KERN_INVALID_RIGHT Name doesn't denote correct right.
1780 */
1781
1782 kern_return_t
1783 ipc_right_copyin(
1784 ipc_space_t space,
1785 mach_port_name_t name,
1786 ipc_entry_t entry,
1787 mach_msg_type_name_t msgt_name,
1788 boolean_t deadok,
1789 ipc_object_t *objectp,
1790 ipc_port_t *sorightp,
1791 ipc_port_t *releasep,
1792 int *assertcntp)
1793 {
1794 ipc_entry_bits_t bits;
1795 ipc_port_t port;
1796
1797 *releasep = IP_NULL;
1798 *assertcntp = 0;
1799
1800 bits = entry->ie_bits;
1801
1802 assert(is_active(space));
1803
1804 switch (msgt_name) {
1805 case MACH_MSG_TYPE_MAKE_SEND: {
1806
1807 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1808 goto invalid_right;
1809
1810 port = (ipc_port_t) entry->ie_object;
1811 assert(port != IP_NULL);
1812
1813 ip_lock(port);
1814 assert(ip_active(port));
1815 assert(port->ip_receiver_name == name);
1816 assert(port->ip_receiver == space);
1817
1818 port->ip_mscount++;
1819 port->ip_srights++;
1820 ip_reference(port);
1821 ip_unlock(port);
1822
1823 *objectp = (ipc_object_t) port;
1824 *sorightp = IP_NULL;
1825 break;
1826 }
1827
1828 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
1829
1830 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1831 goto invalid_right;
1832
1833 port = (ipc_port_t) entry->ie_object;
1834 assert(port != IP_NULL);
1835
1836 ip_lock(port);
1837 assert(ip_active(port));
1838 assert(port->ip_receiver_name == name);
1839 assert(port->ip_receiver == space);
1840
1841 port->ip_sorights++;
1842 ip_reference(port);
1843 ip_unlock(port);
1844
1845 *objectp = (ipc_object_t) port;
1846 *sorightp = IP_NULL;
1847 break;
1848 }
1849
1850 case MACH_MSG_TYPE_MOVE_RECEIVE: {
1851 ipc_port_t request = IP_NULL;
1852
1853 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
1854 goto invalid_right;
1855
1856 port = (ipc_port_t) entry->ie_object;
1857 assert(port != IP_NULL);
1858
1859 ip_lock(port);
1860 assert(ip_active(port));
1861 assert(port->ip_receiver_name == name);
1862 assert(port->ip_receiver == space);
1863
1864 if (bits & MACH_PORT_TYPE_SEND) {
1865 assert(IE_BITS_TYPE(bits) ==
1866 MACH_PORT_TYPE_SEND_RECEIVE);
1867 assert(IE_BITS_UREFS(bits) > 0);
1868 assert(port->ip_srights > 0);
1869
1870 ipc_hash_insert(space, (ipc_object_t) port,
1871 name, entry);
1872 ip_reference(port);
1873 } else {
1874 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
1875 assert(IE_BITS_UREFS(bits) == 0);
1876
1877 request = ipc_right_request_cancel_macro(space, port,
1878 name, entry);
1879 entry->ie_object = IO_NULL;
1880 }
1881 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
1882 ipc_entry_modified(space, name, entry);
1883
1884 (void)ipc_port_clear_receiver(port, FALSE); /* don't destroy the port/mqueue */
1885 port->ip_receiver_name = MACH_PORT_NULL;
1886 port->ip_destination = IP_NULL;
1887
1888 #if IMPORTANCE_INHERITANCE
1889 /*
1890 * Account for boosts the current task is going to lose when
1891 * copying this right in. Tempowner ports have either not
1892 * been accounting to any task (and therefore are already in
1893 * "limbo" state w.r.t. assertions) or to some other specific
1894 * task. As we have no way to drop the latter task's assertions
1895 * here, We'll deduct those when we enqueue it on its
1896 * destination port (see ipc_port_check_circularity()).
1897 */
1898 if (port->ip_tempowner == 0) {
1899 assert(IIT_NULL == port->ip_imp_task);
1900
1901 /* ports in limbo have to be tempowner */
1902 port->ip_tempowner = 1;
1903 *assertcntp = port->ip_impcount;
1904 }
1905 #endif /* IMPORTANCE_INHERITANCE */
1906
1907 ip_unlock(port);
1908
1909 *objectp = (ipc_object_t) port;
1910 *sorightp = request;
1911 break;
1912 }
1913
1914 case MACH_MSG_TYPE_COPY_SEND: {
1915
1916 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1917 goto copy_dead;
1918
1919 /* allow for dead send-once rights */
1920
1921 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1922 goto invalid_right;
1923
1924 assert(IE_BITS_UREFS(bits) > 0);
1925
1926 port = (ipc_port_t) entry->ie_object;
1927 assert(port != IP_NULL);
1928
1929 if (ipc_right_check(space, port, name, entry)) {
1930 bits = entry->ie_bits;
1931 *releasep = port;
1932 goto copy_dead;
1933 }
1934 /* port is locked and active */
1935
1936 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1937 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1938 assert(port->ip_sorights > 0);
1939
1940 ip_unlock(port);
1941 goto invalid_right;
1942 }
1943
1944 assert(port->ip_srights > 0);
1945
1946 port->ip_srights++;
1947 ip_reference(port);
1948 ip_unlock(port);
1949
1950 *objectp = (ipc_object_t) port;
1951 *sorightp = IP_NULL;
1952 break;
1953 }
1954
1955 case MACH_MSG_TYPE_MOVE_SEND: {
1956 ipc_port_t request = IP_NULL;
1957
1958 if (bits & MACH_PORT_TYPE_DEAD_NAME)
1959 goto move_dead;
1960
1961 /* allow for dead send-once rights */
1962
1963 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
1964 goto invalid_right;
1965
1966 assert(IE_BITS_UREFS(bits) > 0);
1967
1968 port = (ipc_port_t) entry->ie_object;
1969 assert(port != IP_NULL);
1970
1971 if (ipc_right_check(space, port, name, entry)) {
1972 bits = entry->ie_bits;
1973 *releasep = port;
1974 goto move_dead;
1975 }
1976 /* port is locked and active */
1977
1978 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
1979 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1980 assert(port->ip_sorights > 0);
1981
1982 ip_unlock(port);
1983 goto invalid_right;
1984 }
1985
1986 assert(port->ip_srights > 0);
1987
1988 if (IE_BITS_UREFS(bits) == 1) {
1989 if (bits & MACH_PORT_TYPE_RECEIVE) {
1990 assert(port->ip_receiver_name == name);
1991 assert(port->ip_receiver == space);
1992 assert(IE_BITS_TYPE(bits) ==
1993 MACH_PORT_TYPE_SEND_RECEIVE);
1994
1995 ip_reference(port);
1996 } else {
1997 assert(IE_BITS_TYPE(bits) ==
1998 MACH_PORT_TYPE_SEND);
1999
2000 request = ipc_right_request_cancel_macro(space, port,
2001 name, entry);
2002 ipc_hash_delete(space, (ipc_object_t) port,
2003 name, entry);
2004 entry->ie_object = IO_NULL;
2005 /* transfer entry's reference to caller */
2006 }
2007 entry->ie_bits = bits &~
2008 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2009 } else {
2010 port->ip_srights++;
2011 ip_reference(port);
2012 /* if urefs are pegged due to overflow, leave them pegged */
2013 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2014 entry->ie_bits = bits-1; /* decrement urefs */
2015 }
2016
2017 ipc_entry_modified(space, name, entry);
2018 ip_unlock(port);
2019
2020 *objectp = (ipc_object_t) port;
2021 *sorightp = request;
2022 break;
2023 }
2024
2025 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
2026 ipc_port_t request;
2027
2028 if (bits & MACH_PORT_TYPE_DEAD_NAME)
2029 goto move_dead;
2030
2031 /* allow for dead send rights */
2032
2033 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
2034 goto invalid_right;
2035
2036 assert(IE_BITS_UREFS(bits) > 0);
2037
2038 port = (ipc_port_t) entry->ie_object;
2039 assert(port != IP_NULL);
2040
2041 if (ipc_right_check(space, port, name, entry)) {
2042 bits = entry->ie_bits;
2043 *releasep = port;
2044 goto move_dead;
2045 }
2046 /* port is locked and active */
2047
2048 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
2049 assert(bits & MACH_PORT_TYPE_SEND);
2050 assert(port->ip_srights > 0);
2051
2052 ip_unlock(port);
2053 goto invalid_right;
2054 }
2055
2056 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
2057 assert(IE_BITS_UREFS(bits) == 1);
2058 assert(port->ip_sorights > 0);
2059
2060 request = ipc_right_request_cancel_macro(space, port, name, entry);
2061 ip_unlock(port);
2062
2063 entry->ie_object = IO_NULL;
2064 entry->ie_bits = bits &~
2065 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
2066 ipc_entry_modified(space, name, entry);
2067 *objectp = (ipc_object_t) port;
2068 *sorightp = request;
2069 break;
2070 }
2071
2072 default:
2073 invalid_right:
2074 return KERN_INVALID_RIGHT;
2075 }
2076
2077 return KERN_SUCCESS;
2078
2079 copy_dead:
2080 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2081 assert(IE_BITS_UREFS(bits) > 0);
2082 assert(entry->ie_request == IE_REQ_NONE);
2083 assert(entry->ie_object == 0);
2084
2085 if (!deadok)
2086 goto invalid_right;
2087
2088 *objectp = IO_DEAD;
2089 *sorightp = IP_NULL;
2090 return KERN_SUCCESS;
2091
2092 move_dead:
2093 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2094 assert(IE_BITS_UREFS(bits) > 0);
2095 assert(entry->ie_request == IE_REQ_NONE);
2096 assert(entry->ie_object == 0);
2097
2098 if (!deadok)
2099 goto invalid_right;
2100
2101 if (IE_BITS_UREFS(bits) == 1) {
2102 bits &= ~MACH_PORT_TYPE_DEAD_NAME;
2103 }
2104 /* if urefs are pegged due to overflow, leave them pegged */
2105 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2106 entry->ie_bits = bits-1; /* decrement urefs */
2107
2108 ipc_entry_modified(space, name, entry);
2109 *objectp = IO_DEAD;
2110 *sorightp = IP_NULL;
2111 return KERN_SUCCESS;
2112
2113 }
2114
2115 /*
2116 * Routine: ipc_right_copyin_undo
2117 * Purpose:
2118 * Undoes the effects of an ipc_right_copyin
2119 * of a send/send-once right that is dead.
2120 * (Object is either IO_DEAD or a dead port.)
2121 * Conditions:
2122 * The space is write-locked and active.
2123 */
2124
2125 void
2126 ipc_right_copyin_undo(
2127 ipc_space_t space,
2128 mach_port_name_t name,
2129 ipc_entry_t entry,
2130 mach_msg_type_name_t msgt_name,
2131 ipc_object_t object,
2132 ipc_port_t soright)
2133 {
2134 ipc_entry_bits_t bits;
2135
2136 bits = entry->ie_bits;
2137
2138 assert(is_active(space));
2139
2140 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2141 (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
2142 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2143
2144 if (soright != IP_NULL) {
2145 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2146 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2147 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2148 assert(object != IO_DEAD);
2149
2150 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
2151 MACH_PORT_TYPE_DEAD_NAME | 2);
2152
2153 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
2154 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2155 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
2156
2157 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
2158 MACH_PORT_TYPE_DEAD_NAME | 1);
2159 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
2160 assert(object == IO_DEAD);
2161 assert(IE_BITS_UREFS(bits) > 0);
2162
2163 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2164 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
2165 /* if urefs are pegged due to overflow, leave them pegged */
2166 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2167 entry->ie_bits = bits+1; /* increment urefs */
2168 }
2169 } else {
2170 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
2171 (msgt_name == MACH_MSG_TYPE_COPY_SEND));
2172 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2173 assert(object != IO_DEAD);
2174 assert(entry->ie_object == object);
2175 assert(IE_BITS_UREFS(bits) > 0);
2176
2177 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
2178 assert(IE_BITS_UREFS(bits) <= MACH_PORT_UREFS_MAX);
2179 /* if urefs are pegged due to overflow, leave them pegged */
2180 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2181 entry->ie_bits = bits+1; /* increment urefs */
2182 }
2183
2184 /*
2185 * May as well convert the entry to a dead name.
2186 * (Or if it is a compat entry, destroy it.)
2187 */
2188
2189 (void) ipc_right_check(space, (ipc_port_t) object,
2190 name, entry);
2191 /* object is dead so it is not locked */
2192 }
2193 ipc_entry_modified(space, name, entry);
2194 /* release the reference acquired by copyin */
2195
2196 if (object != IO_DEAD)
2197 io_release(object);
2198 }
2199
2200 /*
2201 * Routine: ipc_right_copyin_two_move_sends
2202 * Purpose:
2203 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
2204 * and deadok == FALSE, except that this moves two
2205 * send rights at once.
2206 * Conditions:
2207 * The space is write-locked and active.
2208 * The object is returned with two refs/send rights.
2209 * Returns:
2210 * KERN_SUCCESS Acquired an object.
2211 * KERN_INVALID_RIGHT Name doesn't denote correct right.
2212 */
2213 static
2214 kern_return_t
2215 ipc_right_copyin_two_move_sends(
2216 ipc_space_t space,
2217 mach_port_name_t name,
2218 ipc_entry_t entry,
2219 ipc_object_t *objectp,
2220 ipc_port_t *sorightp,
2221 ipc_port_t *releasep)
2222 {
2223 ipc_entry_bits_t bits;
2224 mach_port_urefs_t urefs;
2225 ipc_port_t port;
2226 ipc_port_t request = IP_NULL;
2227
2228 *releasep = IP_NULL;
2229
2230 assert(is_active(space));
2231
2232 bits = entry->ie_bits;
2233
2234 if ((bits & MACH_PORT_TYPE_SEND) == 0)
2235 goto invalid_right;
2236
2237 urefs = IE_BITS_UREFS(bits);
2238 if (urefs < 2)
2239 goto invalid_right;
2240
2241 port = (ipc_port_t) entry->ie_object;
2242 assert(port != IP_NULL);
2243
2244 if (ipc_right_check(space, port, name, entry)) {
2245 *releasep = port;
2246 goto invalid_right;
2247 }
2248 /* port is locked and active */
2249
2250 assert(port->ip_srights > 0);
2251
2252 if (urefs == 2) {
2253 if (bits & MACH_PORT_TYPE_RECEIVE) {
2254 assert(port->ip_receiver_name == name);
2255 assert(port->ip_receiver == space);
2256 assert(IE_BITS_TYPE(bits) ==
2257 MACH_PORT_TYPE_SEND_RECEIVE);
2258
2259 port->ip_srights++;
2260 ip_reference(port);
2261 ip_reference(port);
2262 } else {
2263 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2264
2265 request = ipc_right_request_cancel_macro(space, port,
2266 name, entry);
2267
2268 port->ip_srights++;
2269 ip_reference(port);
2270 ipc_hash_delete(space, (ipc_object_t) port,
2271 name, entry);
2272 entry->ie_object = IO_NULL;
2273 }
2274 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
2275 } else {
2276 port->ip_srights += 2;
2277 ip_reference(port);
2278 ip_reference(port);
2279 /* if urefs are pegged due to overflow, leave them pegged */
2280 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2281 entry->ie_bits = bits-2; /* decrement urefs */
2282 }
2283 ipc_entry_modified(space, name, entry);
2284
2285 ip_unlock(port);
2286
2287 *objectp = (ipc_object_t) port;
2288 *sorightp = request;
2289 return KERN_SUCCESS;
2290
2291 invalid_right:
2292 return KERN_INVALID_RIGHT;
2293 }
2294
2295
2296 /*
2297 * Routine: ipc_right_copyin_two
2298 * Purpose:
2299 * Like ipc_right_copyin with two dispositions,
2300 * each of which results in a send or send-once right,
2301 * and deadok = FALSE.
2302 * Conditions:
2303 * The space is write-locked and active.
2304 * The object is returned with two refs/rights.
2305 * Returns:
2306 * KERN_SUCCESS Acquired an object.
2307 * KERN_INVALID_RIGHT Name doesn't denote correct right(s).
2308 * KERN_INVALID_CAPABILITY Name doesn't denote correct right for msgt_two.
2309 */
2310 kern_return_t
2311 ipc_right_copyin_two(
2312 ipc_space_t space,
2313 mach_port_name_t name,
2314 ipc_entry_t entry,
2315 mach_msg_type_name_t msgt_one,
2316 mach_msg_type_name_t msgt_two,
2317 ipc_object_t *objectp,
2318 ipc_port_t *sorightp,
2319 ipc_port_t *releasep)
2320 {
2321 kern_return_t kr;
2322 int assertcnt = 0;
2323
2324 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_one));
2325 assert(MACH_MSG_TYPE_PORT_ANY_SEND(msgt_two));
2326
2327
2328 /*
2329 * Pre-validate the second disposition is possible all by itself.
2330 */
2331 if (!ipc_right_copyin_check(space, name, entry, msgt_two)) {
2332 return KERN_INVALID_CAPABILITY;
2333 }
2334
2335 /*
2336 * This is a little tedious to make atomic, because
2337 * there are 25 combinations of valid dispositions.
2338 * However, most are easy.
2339 */
2340
2341 /*
2342 * If either is move-sonce, then there must be an error.
2343 */
2344 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND_ONCE ||
2345 msgt_two == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
2346 return KERN_INVALID_RIGHT;
2347 }
2348
2349 if ((msgt_one == MACH_MSG_TYPE_MAKE_SEND) ||
2350 (msgt_one == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
2351 (msgt_two == MACH_MSG_TYPE_MAKE_SEND) ||
2352 (msgt_two == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
2353 /*
2354 * One of the dispositions needs a receive right.
2355 *
2356 * If the copyin below succeeds, we know the receive
2357 * right is there (because the pre-validation of
2358 * the second disposition already succeeded in our
2359 * caller).
2360 *
2361 * Hence the port is not in danger of dying.
2362 */
2363 ipc_object_t object_two;
2364
2365 kr = ipc_right_copyin(space, name, entry,
2366 msgt_one, FALSE,
2367 objectp, sorightp, releasep,
2368 &assertcnt);
2369 assert(assertcnt == 0);
2370 if (kr != KERN_SUCCESS) {
2371 return kr;
2372 }
2373
2374 assert(IO_VALID(*objectp));
2375 assert(*sorightp == IP_NULL);
2376 assert(*releasep == IP_NULL);
2377
2378 /*
2379 * Now copyin the second (previously validated)
2380 * disposition. The result can't be a dead port,
2381 * as no valid disposition can make us lose our
2382 * receive right.
2383 */
2384 kr = ipc_right_copyin(space, name, entry,
2385 msgt_two, FALSE,
2386 &object_two, sorightp, releasep,
2387 &assertcnt);
2388 assert(assertcnt == 0);
2389 assert(kr == KERN_SUCCESS);
2390 assert(*sorightp == IP_NULL);
2391 assert(*releasep == IP_NULL);
2392 assert(object_two == *objectp);
2393 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
2394
2395 } else if ((msgt_one == MACH_MSG_TYPE_MOVE_SEND) &&
2396 (msgt_two == MACH_MSG_TYPE_MOVE_SEND)) {
2397 /*
2398 * This is an easy case. Just use our
2399 * handy-dandy special-purpose copyin call
2400 * to get two send rights for the price of one.
2401 */
2402 kr = ipc_right_copyin_two_move_sends(space, name, entry,
2403 objectp, sorightp,
2404 releasep);
2405 if (kr != KERN_SUCCESS) {
2406 return kr;
2407 }
2408
2409 } else {
2410 mach_msg_type_name_t msgt_name;
2411
2412 /*
2413 * Must be either a single move-send and a
2414 * copy-send, or two copy-send dispositions.
2415 * Use the disposition with the greatest side
2416 * effects for the actual copyin - then just
2417 * duplicate the send right you get back.
2418 */
2419 if (msgt_one == MACH_MSG_TYPE_MOVE_SEND ||
2420 msgt_two == MACH_MSG_TYPE_MOVE_SEND) {
2421 msgt_name = MACH_MSG_TYPE_MOVE_SEND;
2422 } else {
2423 msgt_name = MACH_MSG_TYPE_COPY_SEND;
2424 }
2425
2426 kr = ipc_right_copyin(space, name, entry,
2427 msgt_name, FALSE,
2428 objectp, sorightp, releasep,
2429 &assertcnt);
2430 assert(assertcnt == 0);
2431 if (kr != KERN_SUCCESS) {
2432 return kr;
2433 }
2434
2435 /*
2436 * Copy the right we got back. If it is dead now,
2437 * that's OK. Neither right will be usable to send
2438 * a message anyway.
2439 */
2440 (void)ipc_port_copy_send((ipc_port_t)*objectp);
2441 }
2442
2443 return KERN_SUCCESS;
2444 }
2445
2446
2447 /*
2448 * Routine: ipc_right_copyout
2449 * Purpose:
2450 * Copyout a capability to a space.
2451 * If successful, consumes a ref for the object.
2452 *
2453 * Always succeeds when given a newly-allocated entry,
2454 * because user-reference overflow isn't a possibility.
2455 *
2456 * If copying out the object would cause the user-reference
2457 * count in the entry to overflow, and overflow is TRUE,
2458 * then instead the user-reference count is left pegged
2459 * to its maximum value and the copyout succeeds anyway.
2460 * Conditions:
2461 * The space is write-locked and active.
2462 * The object is locked and active.
2463 * The object is unlocked; the space isn't.
2464 * Returns:
2465 * KERN_SUCCESS Copied out capability.
2466 */
2467
2468 kern_return_t
2469 ipc_right_copyout(
2470 ipc_space_t space,
2471 mach_port_name_t name,
2472 ipc_entry_t entry,
2473 mach_msg_type_name_t msgt_name,
2474 __unused boolean_t overflow,
2475 ipc_object_t object)
2476 {
2477 ipc_entry_bits_t bits;
2478 ipc_port_t port;
2479
2480 bits = entry->ie_bits;
2481
2482 assert(IO_VALID(object));
2483 assert(io_otype(object) == IOT_PORT);
2484 assert(io_active(object));
2485 assert(entry->ie_object == object);
2486
2487 port = (ipc_port_t) object;
2488
2489 switch (msgt_name) {
2490 case MACH_MSG_TYPE_PORT_SEND_ONCE:
2491
2492 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2493 assert(IE_BITS_UREFS(bits) == 0);
2494 assert(port->ip_sorights > 0);
2495
2496 /* transfer send-once right and ref to entry */
2497 ip_unlock(port);
2498
2499 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1); /* set urefs to 1 */
2500 ipc_entry_modified(space, name, entry);
2501 break;
2502
2503 case MACH_MSG_TYPE_PORT_SEND:
2504 assert(port->ip_srights > 0);
2505
2506 if (bits & MACH_PORT_TYPE_SEND) {
2507 mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
2508
2509 assert(port->ip_srights > 1);
2510 assert(urefs > 0);
2511 assert(urefs <= MACH_PORT_UREFS_MAX);
2512
2513 if (urefs == MACH_PORT_UREFS_MAX) {
2514 /*
2515 * leave urefs pegged to maximum,
2516 * consume send right and ref
2517 */
2518
2519 port->ip_srights--;
2520 ip_unlock(port);
2521 ip_release(port);
2522 return KERN_SUCCESS;
2523 }
2524
2525 /* consume send right and ref */
2526 port->ip_srights--;
2527 ip_unlock(port);
2528 ip_release(port);
2529
2530 } else if (bits & MACH_PORT_TYPE_RECEIVE) {
2531 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
2532 assert(IE_BITS_UREFS(bits) == 0);
2533
2534 /* transfer send right to entry, consume ref */
2535 ip_unlock(port);
2536 ip_release(port);
2537
2538 } else {
2539 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2540 assert(IE_BITS_UREFS(bits) == 0);
2541
2542 /* transfer send right and ref to entry */
2543 ip_unlock(port);
2544
2545 /* entry is locked holding ref, so can use port */
2546
2547 ipc_hash_insert(space, (ipc_object_t) port,
2548 name, entry);
2549 }
2550
2551 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; /* increment urefs */
2552 ipc_entry_modified(space, name, entry);
2553 break;
2554
2555 case MACH_MSG_TYPE_PORT_RECEIVE: {
2556 ipc_port_t dest;
2557
2558 #if IMPORTANCE_INHERITANCE
2559 natural_t assertcnt = port->ip_impcount;
2560 #endif /* IMPORTANCE_INHERITANCE */
2561
2562 assert(port->ip_mscount == 0);
2563 assert(port->ip_receiver_name == MACH_PORT_NULL);
2564 dest = port->ip_destination;
2565
2566 port->ip_receiver_name = name;
2567 port->ip_receiver = space;
2568
2569 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
2570
2571 if (bits & MACH_PORT_TYPE_SEND) {
2572 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
2573 assert(IE_BITS_UREFS(bits) > 0);
2574 assert(port->ip_srights > 0);
2575
2576 ip_unlock(port);
2577 ip_release(port);
2578
2579 /* entry is locked holding ref, so can use port */
2580
2581 ipc_hash_delete(space, (ipc_object_t) port,
2582 name, entry);
2583 } else {
2584 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
2585 assert(IE_BITS_UREFS(bits) == 0);
2586
2587 /* transfer ref to entry */
2588 ip_unlock(port);
2589 }
2590 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
2591 ipc_entry_modified(space, name, entry);
2592
2593 if (dest != IP_NULL) {
2594 #if IMPORTANCE_INHERITANCE
2595 /*
2596 * Deduct the assertion counts we contributed to
2597 * the old destination port. They've already
2598 * been reflected into the task as a result of
2599 * getting enqueued.
2600 */
2601 ip_lock(dest);
2602 ipc_port_impcount_delta(dest, 0 - assertcnt, IP_NULL);
2603 ip_unlock(dest);
2604 #endif /* IMPORTANCE_INHERITANCE */
2605 ip_release(dest);
2606 }
2607 break;
2608 }
2609
2610 default:
2611 panic("ipc_right_copyout: strange rights");
2612 }
2613 return KERN_SUCCESS;
2614 }
2615
2616 /*
2617 * Routine: ipc_right_rename
2618 * Purpose:
2619 * Transfer an entry from one name to another.
2620 * The old entry is deallocated.
2621 * Conditions:
2622 * The space is write-locked and active.
2623 * The new entry is unused. Upon return,
2624 * the space is unlocked.
2625 * Returns:
2626 * KERN_SUCCESS Moved entry to new name.
2627 */
2628
2629 kern_return_t
2630 ipc_right_rename(
2631 ipc_space_t space,
2632 mach_port_name_t oname,
2633 ipc_entry_t oentry,
2634 mach_port_name_t nname,
2635 ipc_entry_t nentry)
2636 {
2637 ipc_port_request_index_t request = oentry->ie_request;
2638 ipc_entry_bits_t bits = oentry->ie_bits;
2639 ipc_object_t object = oentry->ie_object;
2640 ipc_port_t release_port = IP_NULL;
2641
2642 assert(is_active(space));
2643 assert(oname != nname);
2644
2645 /*
2646 * If IE_BITS_COMPAT, we can't allow the entry to be renamed
2647 * if the port is dead. (This would foil ipc_port_destroy.)
2648 * Instead we should fail because oentry shouldn't exist.
2649 * Note IE_BITS_COMPAT implies ie_request != 0.
2650 */
2651
2652 if (request != IE_REQ_NONE) {
2653 ipc_port_t port;
2654
2655 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
2656 port = (ipc_port_t) object;
2657 assert(port != IP_NULL);
2658
2659 if (ipc_right_check(space, port, oname, oentry)) {
2660 request = IE_REQ_NONE;
2661 object = IO_NULL;
2662 bits = oentry->ie_bits;
2663 release_port = port;
2664 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
2665 assert(oentry->ie_request == IE_REQ_NONE);
2666 } else {
2667 /* port is locked and active */
2668
2669 ipc_port_request_rename(port, request, oname, nname);
2670 ip_unlock(port);
2671 oentry->ie_request = IE_REQ_NONE;
2672 }
2673 }
2674
2675 /* initialize nentry before letting ipc_hash_insert see it */
2676
2677 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
2678 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
2679 nentry->ie_request = request;
2680 nentry->ie_object = object;
2681
2682 switch (IE_BITS_TYPE(bits)) {
2683 case MACH_PORT_TYPE_SEND: {
2684 ipc_port_t port;
2685
2686 port = (ipc_port_t) object;
2687 assert(port != IP_NULL);
2688
2689 /* remember, there are no other share entries possible */
2690 /* or we can't do the rename. Therefore we do not need */
2691 /* to check the other subspaces */
2692 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
2693 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
2694 break;
2695 }
2696
2697 case MACH_PORT_TYPE_RECEIVE:
2698 case MACH_PORT_TYPE_SEND_RECEIVE: {
2699 ipc_port_t port;
2700
2701 port = (ipc_port_t) object;
2702 assert(port != IP_NULL);
2703
2704 ip_lock(port);
2705 assert(ip_active(port));
2706 assert(port->ip_receiver_name == oname);
2707 assert(port->ip_receiver == space);
2708
2709 port->ip_receiver_name = nname;
2710 ip_unlock(port);
2711 break;
2712 }
2713
2714 case MACH_PORT_TYPE_PORT_SET: {
2715 ipc_pset_t pset;
2716
2717 pset = (ipc_pset_t) object;
2718 assert(pset != IPS_NULL);
2719
2720 ips_lock(pset);
2721 assert(ips_active(pset));
2722
2723 ips_unlock(pset);
2724 break;
2725 }
2726
2727 case MACH_PORT_TYPE_SEND_ONCE:
2728 case MACH_PORT_TYPE_DEAD_NAME:
2729 break;
2730
2731 default:
2732 panic("ipc_right_rename: strange rights");
2733 }
2734
2735 assert(oentry->ie_request == IE_REQ_NONE);
2736 oentry->ie_object = IO_NULL;
2737 ipc_entry_dealloc(space, oname, oentry);
2738 ipc_entry_modified(space, nname, nentry);
2739 is_write_unlock(space);
2740
2741 if (release_port != IP_NULL)
2742 ip_release(release_port);
2743
2744 return KERN_SUCCESS;
2745 }