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