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