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