]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_object.c
27a1cca4af9c77bd2ad5a4e48df8a758d3501ae8
[apple/xnu.git] / osfmk / ipc / ipc_object.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_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_object.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Functions to manipulate IPC objects.
71 */
72
73 #include <mach/mach_types.h>
74 #include <mach/boolean.h>
75 #include <mach/kern_return.h>
76 #include <mach/port.h>
77 #include <mach/message.h>
78
79 #include <kern/kern_types.h>
80 #include <kern/misc_protos.h>
81 #include <kern/ipc_kobject.h>
82
83 #include <ipc/ipc_types.h>
84 #include <ipc/ipc_importance.h>
85 #include <ipc/port.h>
86 #include <ipc/ipc_space.h>
87 #include <ipc/ipc_entry.h>
88 #include <ipc/ipc_object.h>
89 #include <ipc/ipc_hash.h>
90 #include <ipc/ipc_right.h>
91 #include <ipc/ipc_notify.h>
92 #include <ipc/ipc_port.h>
93 #include <ipc/ipc_pset.h>
94
95 #include <security/mac_mach_internal.h>
96
97 zone_t ipc_object_zones[IOT_NUMBER];
98
99 /*
100 * Routine: ipc_object_reference
101 * Purpose:
102 * Take a reference to an object.
103 */
104
105 void
106 ipc_object_reference(
107 ipc_object_t object)
108 {
109 io_reference(object);
110 }
111
112 /*
113 * Routine: ipc_object_release
114 * Purpose:
115 * Release a reference to an object.
116 */
117
118 void
119 ipc_object_release(
120 ipc_object_t object)
121 {
122 io_release(object);
123 }
124
125 /*
126 * Routine: ipc_object_translate
127 * Purpose:
128 * Look up an object in a space.
129 * Conditions:
130 * Nothing locked before. If successful, the object
131 * is returned locked. The caller doesn't get a ref.
132 * Returns:
133 * KERN_SUCCESS Object returned locked.
134 * KERN_INVALID_TASK The space is dead.
135 * KERN_INVALID_NAME The name doesn't denote a right
136 * KERN_INVALID_RIGHT Name doesn't denote the correct right
137 */
138 kern_return_t
139 ipc_object_translate(
140 ipc_space_t space,
141 mach_port_name_t name,
142 mach_port_right_t right,
143 ipc_object_t *objectp)
144 {
145 ipc_entry_t entry;
146 ipc_object_t object;
147 kern_return_t kr;
148
149 kr = ipc_right_lookup_read(space, name, &entry);
150 if (kr != KERN_SUCCESS) {
151 return kr;
152 }
153 /* space is read-locked and active */
154
155 if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
156 is_read_unlock(space);
157 return KERN_INVALID_RIGHT;
158 }
159
160 object = entry->ie_object;
161 assert(object != IO_NULL);
162
163 io_lock(object);
164 is_read_unlock(space);
165
166 *objectp = object;
167 return KERN_SUCCESS;
168 }
169
170 /*
171 * Routine: ipc_object_translate_two
172 * Purpose:
173 * Look up two objects in a space.
174 * Conditions:
175 * Nothing locked before. If successful, the objects
176 * are returned locked. The caller doesn't get a ref.
177 * Returns:
178 * KERN_SUCCESS Objects returned locked.
179 * KERN_INVALID_TASK The space is dead.
180 * KERN_INVALID_NAME A name doesn't denote a right.
181 * KERN_INVALID_RIGHT A name doesn't denote the correct right.
182 */
183
184 kern_return_t
185 ipc_object_translate_two(
186 ipc_space_t space,
187 mach_port_name_t name1,
188 mach_port_right_t right1,
189 ipc_object_t *objectp1,
190 mach_port_name_t name2,
191 mach_port_right_t right2,
192 ipc_object_t *objectp2)
193 {
194 ipc_entry_t entry1;
195 ipc_entry_t entry2;
196 ipc_object_t object;
197 kern_return_t kr;
198
199 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
200 if (kr != KERN_SUCCESS) {
201 return kr;
202 }
203 /* space is read-locked and active */
204
205 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
206 is_read_unlock(space);
207 mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT);
208 return KERN_INVALID_RIGHT;
209 }
210
211 if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
212 is_read_unlock(space);
213 mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT);
214 return KERN_INVALID_RIGHT;
215 }
216
217 object = entry1->ie_object;
218 assert(object != IO_NULL);
219 io_lock(object);
220 *objectp1 = object;
221
222 object = entry2->ie_object;
223 assert(object != IO_NULL);
224 io_lock(object);
225 *objectp2 = object;
226
227 is_read_unlock(space);
228 return KERN_SUCCESS;
229 }
230
231 /*
232 * Routine: ipc_object_alloc_dead
233 * Purpose:
234 * Allocate a dead-name entry.
235 * Conditions:
236 * Nothing locked.
237 * Returns:
238 * KERN_SUCCESS The dead name is allocated.
239 * KERN_INVALID_TASK The space is dead.
240 * KERN_NO_SPACE No room for an entry in the space.
241 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
242 */
243
244 kern_return_t
245 ipc_object_alloc_dead(
246 ipc_space_t space,
247 mach_port_name_t *namep)
248 {
249 ipc_entry_t entry;
250 kern_return_t kr;
251
252 kr = ipc_entry_alloc(space, namep, &entry);
253 if (kr != KERN_SUCCESS) {
254 return kr;
255 }
256 /* space is write-locked */
257
258 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
259
260 assert(entry->ie_object == IO_NULL);
261 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
262 ipc_entry_modified(space, *namep, entry);
263 is_write_unlock(space);
264 return KERN_SUCCESS;
265 }
266
267 /*
268 * Routine: ipc_object_alloc_dead_name
269 * Purpose:
270 * Allocate a dead-name entry, with a specific name.
271 * Conditions:
272 * Nothing locked.
273 * Returns:
274 * KERN_SUCCESS The dead name is allocated.
275 * KERN_INVALID_TASK The space is dead.
276 * KERN_NAME_EXISTS The name already denotes a right.
277 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
278 */
279
280 kern_return_t
281 ipc_object_alloc_dead_name(
282 ipc_space_t space,
283 mach_port_name_t name)
284 {
285 ipc_entry_t entry;
286 kern_return_t kr;
287
288 kr = ipc_entry_alloc_name(space, name, &entry);
289 if (kr != KERN_SUCCESS) {
290 return kr;
291 }
292 /* space is write-locked */
293
294 if (ipc_right_inuse(space, name, entry)) {
295 return KERN_NAME_EXISTS;
296 }
297
298 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
299
300 assert(entry->ie_object == IO_NULL);
301 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
302 ipc_entry_modified(space, name, entry);
303 is_write_unlock(space);
304 return KERN_SUCCESS;
305 }
306
307 /*
308 * Routine: ipc_object_alloc
309 * Purpose:
310 * Allocate an object.
311 * Conditions:
312 * Nothing locked. If successful, the object is returned locked.
313 * The space is write locked on successful return.
314 * The caller doesn't get a reference for the object.
315 * Returns:
316 * KERN_SUCCESS The object is allocated.
317 * KERN_INVALID_TASK The space is dead.
318 * KERN_NO_SPACE No room for an entry in the space.
319 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
320 */
321
322 kern_return_t
323 ipc_object_alloc(
324 ipc_space_t space,
325 ipc_object_type_t otype,
326 mach_port_type_t type,
327 mach_port_urefs_t urefs,
328 mach_port_name_t *namep,
329 ipc_object_t *objectp)
330 {
331 ipc_object_t object;
332 ipc_entry_t entry;
333 kern_return_t kr;
334
335 assert(otype < IOT_NUMBER);
336 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
337 assert(type != MACH_PORT_TYPE_NONE);
338 assert(urefs <= MACH_PORT_UREFS_MAX);
339
340 object = io_alloc(otype);
341 if (object == IO_NULL) {
342 return KERN_RESOURCE_SHORTAGE;
343 }
344
345 if (otype == IOT_PORT) {
346 ipc_port_t port = (ipc_port_t)object;
347
348 bzero((char *)port, sizeof(*port));
349 } else if (otype == IOT_PORT_SET) {
350 ipc_pset_t pset = (ipc_pset_t)object;
351
352 bzero((char *)pset, sizeof(*pset));
353 }
354
355 io_lock_init(object);
356 *namep = CAST_MACH_PORT_TO_NAME(object);
357 kr = ipc_entry_alloc(space, namep, &entry);
358 if (kr != KERN_SUCCESS) {
359 io_free(otype, object);
360 return kr;
361 }
362 /* space is write-locked */
363
364 entry->ie_bits |= type | urefs;
365 entry->ie_object = object;
366 ipc_entry_modified(space, *namep, entry);
367
368 io_lock(object);
369
370 object->io_references = 1; /* for entry, not caller */
371 object->io_bits = io_makebits(TRUE, otype, 0);
372
373 *objectp = object;
374 return KERN_SUCCESS;
375 }
376
377 /*
378 * Routine: ipc_object_alloc_name
379 * Purpose:
380 * Allocate an object, with a specific name.
381 * Conditions:
382 * Nothing locked. If successful, the object is returned locked.
383 * The caller doesn't get a reference for the object.
384 * Returns:
385 * KERN_SUCCESS The object is allocated.
386 * KERN_INVALID_TASK The space is dead.
387 * KERN_NAME_EXISTS The name already denotes a right.
388 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
389 */
390
391 kern_return_t
392 ipc_object_alloc_name(
393 ipc_space_t space,
394 ipc_object_type_t otype,
395 mach_port_type_t type,
396 mach_port_urefs_t urefs,
397 mach_port_name_t name,
398 ipc_object_t *objectp)
399 {
400 ipc_object_t object;
401 ipc_entry_t entry;
402 kern_return_t kr;
403
404 assert(otype < IOT_NUMBER);
405 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
406 assert(type != MACH_PORT_TYPE_NONE);
407 assert(urefs <= MACH_PORT_UREFS_MAX);
408
409 object = io_alloc(otype);
410 if (object == IO_NULL) {
411 return KERN_RESOURCE_SHORTAGE;
412 }
413
414 if (otype == IOT_PORT) {
415 ipc_port_t port = (ipc_port_t)object;
416
417 bzero((char *)port, sizeof(*port));
418 } else if (otype == IOT_PORT_SET) {
419 ipc_pset_t pset = (ipc_pset_t)object;
420
421 bzero((char *)pset, sizeof(*pset));
422 }
423
424 io_lock_init(object);
425 kr = ipc_entry_alloc_name(space, name, &entry);
426 if (kr != KERN_SUCCESS) {
427 io_free(otype, object);
428 return kr;
429 }
430 /* space is write-locked */
431
432 if (ipc_right_inuse(space, name, entry)) {
433 io_free(otype, object);
434 return KERN_NAME_EXISTS;
435 }
436
437 entry->ie_bits |= type | urefs;
438 entry->ie_object = object;
439 ipc_entry_modified(space, name, entry);
440
441 io_lock(object);
442 is_write_unlock(space);
443
444 object->io_references = 1; /* for entry, not caller */
445 object->io_bits = io_makebits(TRUE, otype, 0);
446
447 *objectp = object;
448 return KERN_SUCCESS;
449 }
450
451 /*
452 * Routine: ipc_object_copyin_type
453 * Purpose:
454 * Convert a send type name to a received type name.
455 */
456
457 mach_msg_type_name_t
458 ipc_object_copyin_type(
459 mach_msg_type_name_t msgt_name)
460 {
461 switch (msgt_name) {
462 case MACH_MSG_TYPE_MOVE_RECEIVE:
463 return MACH_MSG_TYPE_PORT_RECEIVE;
464
465 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
466 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
467 return MACH_MSG_TYPE_PORT_SEND_ONCE;
468
469 case MACH_MSG_TYPE_MOVE_SEND:
470 case MACH_MSG_TYPE_MAKE_SEND:
471 case MACH_MSG_TYPE_COPY_SEND:
472 return MACH_MSG_TYPE_PORT_SEND;
473
474 case MACH_MSG_TYPE_DISPOSE_RECEIVE:
475 case MACH_MSG_TYPE_DISPOSE_SEND:
476 case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
477 /* fall thru */
478 default:
479 return MACH_MSG_TYPE_PORT_NONE;
480 }
481 }
482
483 /*
484 * Routine: ipc_object_copyin
485 * Purpose:
486 * Copyin a capability from a space.
487 * If successful, the caller gets a ref
488 * for the resulting object, unless it is IO_DEAD.
489 * Conditions:
490 * Nothing locked.
491 * Returns:
492 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
493 * KERN_INVALID_TASK The space is dead.
494 * KERN_INVALID_NAME Name doesn't exist in space.
495 * KERN_INVALID_RIGHT Name doesn't denote correct right.
496 */
497
498 kern_return_t
499 ipc_object_copyin(
500 ipc_space_t space,
501 mach_port_name_t name,
502 mach_msg_type_name_t msgt_name,
503 ipc_object_t *objectp)
504 {
505 ipc_entry_t entry;
506 ipc_port_t soright;
507 ipc_port_t release_port;
508 kern_return_t kr;
509 int assertcnt = 0;
510
511 /*
512 * Could first try a read lock when doing
513 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
514 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
515 */
516
517 kr = ipc_right_lookup_write(space, name, &entry);
518 if (kr != KERN_SUCCESS) {
519 return kr;
520 }
521 /* space is write-locked and active */
522
523 release_port = IP_NULL;
524 kr = ipc_right_copyin(space, name, entry,
525 msgt_name, IPC_RIGHT_COPYIN_FLAGS_DEADOK,
526 objectp, &soright,
527 &release_port,
528 &assertcnt);
529 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
530 ipc_entry_dealloc(space, name, entry);
531 }
532 is_write_unlock(space);
533
534 #if IMPORTANCE_INHERITANCE
535 if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
536 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
537 }
538 #endif /* IMPORTANCE_INHERITANCE */
539
540 if (release_port != IP_NULL) {
541 ip_release(release_port);
542 }
543
544 if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) {
545 ipc_notify_port_deleted(soright, name);
546 }
547
548 return kr;
549 }
550
551 /*
552 * Routine: ipc_object_copyin_from_kernel
553 * Purpose:
554 * Copyin a naked capability from the kernel.
555 *
556 * MACH_MSG_TYPE_MOVE_RECEIVE
557 * The receiver must be ipc_space_kernel
558 * or the receive right must already be in limbo.
559 * Consumes the naked receive right.
560 * MACH_MSG_TYPE_COPY_SEND
561 * A naked send right must be supplied.
562 * The port gains a reference, and a send right
563 * if the port is still active.
564 * MACH_MSG_TYPE_MAKE_SEND
565 * The receiver must be ipc_space_kernel.
566 * The port gains a reference and a send right.
567 * MACH_MSG_TYPE_MOVE_SEND
568 * Consumes a naked send right.
569 * MACH_MSG_TYPE_MAKE_SEND_ONCE
570 * The port gains a reference and a send-once right.
571 * Receiver also be the caller of device subsystem,
572 * so no assertion.
573 * MACH_MSG_TYPE_MOVE_SEND_ONCE
574 * Consumes a naked send-once right.
575 * Conditions:
576 * Nothing locked.
577 */
578
579 void
580 ipc_object_copyin_from_kernel(
581 ipc_object_t object,
582 mach_msg_type_name_t msgt_name)
583 {
584 assert(IO_VALID(object));
585
586 switch (msgt_name) {
587 case MACH_MSG_TYPE_MOVE_RECEIVE: {
588 ipc_port_t port = (ipc_port_t) object;
589
590 ip_lock(port);
591 imq_lock(&port->ip_messages);
592 assert(ip_active(port));
593 if (port->ip_destination != IP_NULL) {
594 assert(port->ip_receiver == ipc_space_kernel);
595
596 /* relevant part of ipc_port_clear_receiver */
597 ipc_port_set_mscount(port, 0);
598
599 port->ip_receiver_name = MACH_PORT_NULL;
600 port->ip_destination = IP_NULL;
601 }
602 imq_unlock(&port->ip_messages);
603 ip_unlock(port);
604 break;
605 }
606
607 case MACH_MSG_TYPE_COPY_SEND: {
608 ipc_port_t port = (ipc_port_t) object;
609
610 ip_lock(port);
611 if (ip_active(port)) {
612 assert(port->ip_srights > 0);
613 port->ip_srights++;
614 }
615 ip_reference(port);
616 ip_unlock(port);
617 break;
618 }
619
620 case MACH_MSG_TYPE_MAKE_SEND: {
621 ipc_port_t port = (ipc_port_t) object;
622
623 ip_lock(port);
624 if (ip_active(port)) {
625 assert(port->ip_receiver_name != MACH_PORT_NULL);
626 assert((port->ip_receiver == ipc_space_kernel) ||
627 (port->ip_receiver->is_node_id != HOST_LOCAL_NODE));
628 port->ip_mscount++;
629 }
630
631 port->ip_srights++;
632 ip_reference(port);
633 ip_unlock(port);
634 break;
635 }
636
637 case MACH_MSG_TYPE_MOVE_SEND: {
638 /* move naked send right into the message */
639 assert(((ipc_port_t)object)->ip_srights);
640 break;
641 }
642
643 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
644 ipc_port_t port = (ipc_port_t) object;
645
646 ip_lock(port);
647 if (ip_active(port)) {
648 assert(port->ip_receiver_name != MACH_PORT_NULL);
649 }
650 port->ip_sorights++;
651 ip_reference(port);
652 ip_unlock(port);
653 break;
654 }
655
656 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
657 /* move naked send-once right into the message */
658 assert(((ipc_port_t)object)->ip_sorights);
659 break;
660 }
661
662 default:
663 panic("ipc_object_copyin_from_kernel: strange rights");
664 }
665 }
666
667 /*
668 * Routine: ipc_object_destroy
669 * Purpose:
670 * Destroys a naked capability.
671 * Consumes a ref for the object.
672 *
673 * A receive right should be in limbo or in transit.
674 * Conditions:
675 * Nothing locked.
676 */
677
678 void
679 ipc_object_destroy(
680 ipc_object_t object,
681 mach_msg_type_name_t msgt_name)
682 {
683 assert(IO_VALID(object));
684 assert(io_otype(object) == IOT_PORT);
685
686 switch (msgt_name) {
687 case MACH_MSG_TYPE_PORT_SEND:
688 ipc_port_release_send((ipc_port_t) object);
689 break;
690
691 case MACH_MSG_TYPE_PORT_SEND_ONCE:
692 ipc_notify_send_once((ipc_port_t) object);
693 break;
694
695 case MACH_MSG_TYPE_PORT_RECEIVE:
696 ipc_port_release_receive((ipc_port_t) object);
697 break;
698
699 default:
700 panic("ipc_object_destroy: strange rights");
701 }
702 }
703
704 /*
705 * Routine: ipc_object_destroy_dest
706 * Purpose:
707 * Destroys a naked capability for the destination of
708 * of a message. Consumes a ref for the object.
709 *
710 * Conditions:
711 * Nothing locked.
712 */
713
714 void
715 ipc_object_destroy_dest(
716 ipc_object_t object,
717 mach_msg_type_name_t msgt_name)
718 {
719 assert(IO_VALID(object));
720 assert(io_otype(object) == IOT_PORT);
721
722 switch (msgt_name) {
723 case MACH_MSG_TYPE_PORT_SEND:
724 ipc_port_release_send((ipc_port_t) object);
725 break;
726
727 case MACH_MSG_TYPE_PORT_SEND_ONCE:
728 if (io_active(object) &&
729 !ip_full_kernel((ipc_port_t) object)) {
730 ipc_notify_send_once((ipc_port_t) object);
731 } else {
732 ipc_port_release_sonce((ipc_port_t) object);
733 }
734 break;
735
736 default:
737 panic("ipc_object_destroy_dest: strange rights");
738 }
739 }
740
741 /*
742 * Routine: ipc_object_copyout
743 * Purpose:
744 * Copyout a capability, placing it into a space.
745 * If successful, consumes a ref for the object.
746 * Conditions:
747 * Nothing locked.
748 * Returns:
749 * KERN_SUCCESS Copied out object, consumed ref.
750 * KERN_INVALID_TASK The space is dead.
751 * KERN_INVALID_CAPABILITY The object is dead.
752 * KERN_NO_SPACE No room in space for another right.
753 * KERN_RESOURCE_SHORTAGE No memory available.
754 * KERN_UREFS_OVERFLOW Urefs limit exceeded
755 * and overflow wasn't specified.
756 */
757
758 kern_return_t
759 ipc_object_copyout(
760 ipc_space_t space,
761 ipc_object_t object,
762 mach_msg_type_name_t msgt_name,
763 boolean_t overflow,
764 mach_port_name_t *namep)
765 {
766 struct knote *kn = current_thread()->ith_knote;
767 mach_port_name_t name;
768 ipc_entry_t entry;
769 kern_return_t kr;
770
771 assert(IO_VALID(object));
772 assert(io_otype(object) == IOT_PORT);
773
774 if (ITH_KNOTE_VALID(kn, msgt_name)) {
775 filt_machport_turnstile_prepare_lazily(kn,
776 msgt_name, (ipc_port_t)object);
777 }
778
779 is_write_lock(space);
780
781 for (;;) {
782 if (!is_active(space)) {
783 is_write_unlock(space);
784 return KERN_INVALID_TASK;
785 }
786
787 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
788 ipc_right_reverse(space, object, &name, &entry)) {
789 /* object is locked and active */
790
791 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
792 break;
793 }
794
795 name = CAST_MACH_PORT_TO_NAME(object);
796 kr = ipc_entry_get(space, &name, &entry);
797 if (kr != KERN_SUCCESS) {
798 /* unlocks/locks space, so must start again */
799
800 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
801 if (kr != KERN_SUCCESS) {
802 return kr; /* space is unlocked */
803 }
804 continue;
805 }
806
807 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
808 assert(entry->ie_object == IO_NULL);
809
810 io_lock(object);
811 if (!io_active(object)) {
812 io_unlock(object);
813 ipc_entry_dealloc(space, name, entry);
814 is_write_unlock(space);
815 return KERN_INVALID_CAPABILITY;
816 }
817
818 entry->ie_object = object;
819 break;
820 }
821
822 /* space is write-locked and active, object is locked and active */
823
824 kr = ipc_right_copyout(space, name, entry,
825 msgt_name, overflow, object);
826
827 /* object is unlocked */
828 is_write_unlock(space);
829
830 if (kr == KERN_SUCCESS) {
831 *namep = name;
832 }
833 return kr;
834 }
835
836 /*
837 * Routine: ipc_object_copyout_name
838 * Purpose:
839 * Copyout a capability, placing it into a space.
840 * The specified name is used for the capability.
841 * If successful, consumes a ref for the object.
842 * Conditions:
843 * Nothing locked.
844 * Returns:
845 * KERN_SUCCESS Copied out object, consumed ref.
846 * KERN_INVALID_TASK The space is dead.
847 * KERN_INVALID_CAPABILITY The object is dead.
848 * KERN_RESOURCE_SHORTAGE No memory available.
849 * KERN_UREFS_OVERFLOW Urefs limit exceeded
850 * and overflow wasn't specified.
851 * KERN_RIGHT_EXISTS Space has rights under another name.
852 * KERN_NAME_EXISTS Name is already used.
853 */
854
855 kern_return_t
856 ipc_object_copyout_name(
857 ipc_space_t space,
858 ipc_object_t object,
859 mach_msg_type_name_t msgt_name,
860 boolean_t overflow,
861 mach_port_name_t name)
862 {
863 mach_port_name_t oname;
864 ipc_entry_t oentry;
865 ipc_entry_t entry;
866 kern_return_t kr;
867 struct knote *kn = current_thread()->ith_knote;
868
869 #if IMPORTANCE_INHERITANCE
870 int assertcnt = 0;
871 ipc_importance_task_t task_imp = IIT_NULL;
872 #endif /* IMPORTANCE_INHERITANCE */
873
874 assert(IO_VALID(object));
875 assert(io_otype(object) == IOT_PORT);
876
877 if (ITH_KNOTE_VALID(kn, msgt_name)) {
878 filt_machport_turnstile_prepare_lazily(kn,
879 msgt_name, (ipc_port_t)object);
880 }
881
882 kr = ipc_entry_alloc_name(space, name, &entry);
883 if (kr != KERN_SUCCESS) {
884 return kr;
885 }
886 /* space is write-locked and active */
887
888 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
889 ipc_right_reverse(space, object, &oname, &oentry)) {
890 /* object is locked and active */
891
892 if (name != oname) {
893 io_unlock(object);
894
895 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
896 ipc_entry_dealloc(space, name, entry);
897 }
898
899 is_write_unlock(space);
900 return KERN_RIGHT_EXISTS;
901 }
902
903 assert(entry == oentry);
904 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
905 } else {
906 if (ipc_right_inuse(space, name, entry)) {
907 return KERN_NAME_EXISTS;
908 }
909
910 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
911 assert(entry->ie_object == IO_NULL);
912
913 io_lock(object);
914 if (!io_active(object)) {
915 io_unlock(object);
916 ipc_entry_dealloc(space, name, entry);
917 is_write_unlock(space);
918 return KERN_INVALID_CAPABILITY;
919 }
920
921 entry->ie_object = object;
922 }
923
924 /* space is write-locked and active, object is locked and active */
925
926 #if IMPORTANCE_INHERITANCE
927 /*
928 * We are slamming a receive right into the space, without
929 * first having been enqueued on a port destined there. So,
930 * we have to arrange to boost the task appropriately if this
931 * port has assertions (and the task wants them).
932 */
933 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
934 ipc_port_t port = (ipc_port_t)object;
935
936 if (space->is_task != TASK_NULL) {
937 task_imp = space->is_task->task_imp_base;
938 if (ipc_importance_task_is_any_receiver_type(task_imp)) {
939 assertcnt = port->ip_impcount;
940 ipc_importance_task_reference(task_imp);
941 } else {
942 task_imp = IIT_NULL;
943 }
944 }
945
946 /* take port out of limbo */
947 assert(port->ip_tempowner != 0);
948 port->ip_tempowner = 0;
949 }
950
951 #endif /* IMPORTANCE_INHERITANCE */
952
953 kr = ipc_right_copyout(space, name, entry,
954 msgt_name, overflow, object);
955
956 /* object is unlocked */
957 is_write_unlock(space);
958
959 #if IMPORTANCE_INHERITANCE
960 /*
961 * Add the assertions to the task that we captured before
962 */
963 if (task_imp != IIT_NULL) {
964 ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
965 ipc_importance_task_release(task_imp);
966 }
967 #endif /* IMPORTANCE_INHERITANCE */
968
969 return kr;
970 }
971
972 /*
973 * Routine: ipc_object_copyout_dest
974 * Purpose:
975 * Translates/consumes the destination right of a message.
976 * This is unlike normal copyout because the right is consumed
977 * in a funny way instead of being given to the receiving space.
978 * The receiver gets his name for the port, if he has receive
979 * rights, otherwise MACH_PORT_NULL.
980 * Conditions:
981 * The object is locked and active. Nothing else locked.
982 * The object is unlocked and loses a reference.
983 */
984
985 void
986 ipc_object_copyout_dest(
987 ipc_space_t space,
988 ipc_object_t object,
989 mach_msg_type_name_t msgt_name,
990 mach_port_name_t *namep)
991 {
992 mach_port_name_t name;
993
994 assert(IO_VALID(object));
995 assert(io_active(object));
996
997 io_release(object);
998
999 /*
1000 * If the space is the receiver/owner of the object,
1001 * then we quietly consume the right and return
1002 * the space's name for the object. Otherwise
1003 * we destroy the right and return MACH_PORT_NULL.
1004 */
1005
1006 switch (msgt_name) {
1007 case MACH_MSG_TYPE_PORT_SEND: {
1008 ipc_port_t port = (ipc_port_t) object;
1009 ipc_port_t nsrequest = IP_NULL;
1010 mach_port_mscount_t mscount;
1011
1012 if (port->ip_receiver == space) {
1013 name = port->ip_receiver_name;
1014 } else {
1015 name = MACH_PORT_NULL;
1016 }
1017
1018 assert(port->ip_srights > 0);
1019 if (--port->ip_srights == 0 &&
1020 port->ip_nsrequest != IP_NULL) {
1021 nsrequest = port->ip_nsrequest;
1022 port->ip_nsrequest = IP_NULL;
1023 mscount = port->ip_mscount;
1024 ip_unlock(port);
1025 ipc_notify_no_senders(nsrequest, mscount);
1026 } else {
1027 ip_unlock(port);
1028 }
1029 break;
1030 }
1031
1032 case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1033 ipc_port_t port = (ipc_port_t) object;
1034
1035 assert(port->ip_sorights > 0);
1036
1037 if (port->ip_receiver == space) {
1038 /* quietly consume the send-once right */
1039
1040 port->ip_sorights--;
1041 name = port->ip_receiver_name;
1042 ip_unlock(port);
1043 } else {
1044 /*
1045 * A very bizarre case. The message
1046 * was received, but before this copyout
1047 * happened the space lost receive rights.
1048 * We can't quietly consume the soright
1049 * out from underneath some other task,
1050 * so generate a send-once notification.
1051 */
1052
1053 ip_reference(port); /* restore ref */
1054 ip_unlock(port);
1055
1056 ipc_notify_send_once(port);
1057 name = MACH_PORT_NULL;
1058 }
1059
1060 break;
1061 }
1062
1063 default:
1064 panic("ipc_object_copyout_dest: strange rights");
1065 name = MACH_PORT_DEAD;
1066 }
1067
1068 *namep = name;
1069 }
1070
1071 /*
1072 * Routine: ipc_object_rename
1073 * Purpose:
1074 * Rename an entry in a space.
1075 * Conditions:
1076 * Nothing locked.
1077 * Returns:
1078 * KERN_SUCCESS Renamed the entry.
1079 * KERN_INVALID_TASK The space was dead.
1080 * KERN_INVALID_NAME oname didn't denote an entry.
1081 * KERN_NAME_EXISTS nname already denoted an entry.
1082 * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry.
1083 */
1084
1085 kern_return_t
1086 ipc_object_rename(
1087 ipc_space_t space,
1088 mach_port_name_t oname,
1089 mach_port_name_t nname)
1090 {
1091 ipc_entry_t oentry, nentry;
1092 kern_return_t kr;
1093
1094 kr = ipc_entry_alloc_name(space, nname, &nentry);
1095 if (kr != KERN_SUCCESS) {
1096 return kr;
1097 }
1098
1099 /* space is write-locked and active */
1100
1101 if (ipc_right_inuse(space, nname, nentry)) {
1102 /* space is unlocked */
1103 return KERN_NAME_EXISTS;
1104 }
1105
1106 /* don't let ipc_entry_lookup see the uninitialized new entry */
1107
1108 if ((oname == nname) ||
1109 ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
1110 ipc_entry_dealloc(space, nname, nentry);
1111 is_write_unlock(space);
1112 return KERN_INVALID_NAME;
1113 }
1114
1115 kr = ipc_right_rename(space, oname, oentry, nname, nentry);
1116 /* space is unlocked */
1117 return kr;
1118 }
1119
1120 /*
1121 * Check whether the object is a port if so, free it. But
1122 * keep track of that fact.
1123 */
1124 void
1125 io_free(
1126 unsigned int otype,
1127 ipc_object_t object)
1128 {
1129 ipc_port_t port;
1130
1131 if (otype == IOT_PORT) {
1132 port = (ipc_port_t) object;
1133 ipc_port_finalize(port);
1134 }
1135 io_lock_destroy(object);
1136 zfree(ipc_object_zones[otype], object);
1137 }