]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_object.c
xnu-2782.1.97.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_object.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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 */
2d21ac55
A
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 */
1c79356b
A
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
91447636 75#include <mach/mach_types.h>
1c79356b
A
76#include <mach/boolean.h>
77#include <mach/kern_return.h>
78#include <mach/port.h>
79#include <mach/message.h>
91447636
A
80
81#include <kern/kern_types.h>
1c79356b 82#include <kern/misc_protos.h>
2d21ac55 83#include <kern/ipc_kobject.h>
91447636
A
84
85#include <ipc/ipc_types.h>
fe8ab488 86#include <ipc/ipc_importance.h>
1c79356b
A
87#include <ipc/port.h>
88#include <ipc/ipc_space.h>
89#include <ipc/ipc_entry.h>
90#include <ipc/ipc_object.h>
91#include <ipc/ipc_hash.h>
92#include <ipc/ipc_right.h>
93#include <ipc/ipc_notify.h>
6d2010ae 94#include <ipc/ipc_port.h>
1c79356b 95#include <ipc/ipc_pset.h>
2d21ac55
A
96
97#include <security/mac_mach_internal.h>
1c79356b
A
98
99zone_t ipc_object_zones[IOT_NUMBER];
100
101/*
102 * Routine: ipc_object_reference
103 * Purpose:
104 * Take a reference to an object.
105 */
106
107void
108ipc_object_reference(
109 ipc_object_t object)
110{
1c79356b 111 io_reference(object);
1c79356b
A
112}
113
114/*
115 * Routine: ipc_object_release
116 * Purpose:
117 * Release a reference to an object.
118 */
119
120void
121ipc_object_release(
122 ipc_object_t object)
123{
1c79356b 124 io_release(object);
1c79356b
A
125}
126
127/*
128 * Routine: ipc_object_translate
129 * Purpose:
130 * Look up an object in a space.
131 * Conditions:
132 * Nothing locked before. If successful, the object
133 * is returned locked. The caller doesn't get a ref.
134 * Returns:
135 * KERN_SUCCESS Object returned locked.
136 * KERN_INVALID_TASK The space is dead.
137 * KERN_INVALID_NAME The name doesn't denote a right.
138 * KERN_INVALID_RIGHT Name doesn't denote the correct right.
139 */
140
141kern_return_t
142ipc_object_translate(
143 ipc_space_t space,
144 mach_port_name_t name,
145 mach_port_right_t right,
146 ipc_object_t *objectp)
147{
148 ipc_entry_t entry;
149 ipc_object_t object;
150 kern_return_t kr;
151
152 kr = ipc_right_lookup_read(space, name, &entry);
153 if (kr != KERN_SUCCESS)
154 return kr;
155 /* space is read-locked and active */
156
157 if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
158 is_read_unlock(space);
159 return KERN_INVALID_RIGHT;
160 }
161
162 object = entry->ie_object;
163 assert(object != IO_NULL);
164
165 io_lock(object);
166 is_read_unlock(space);
167
168 *objectp = object;
169 return KERN_SUCCESS;
170}
171
172/*
173 * Routine: ipc_object_translate_two
174 * Purpose:
175 * Look up two objects in a space.
176 * Conditions:
177 * Nothing locked before. If successful, the objects
178 * are returned locked. The caller doesn't get a ref.
179 * Returns:
180 * KERN_SUCCESS Objects returned locked.
181 * KERN_INVALID_TASK The space is dead.
182 * KERN_INVALID_NAME A name doesn't denote a right.
183 * KERN_INVALID_RIGHT A name doesn't denote the correct right.
184 */
185
186kern_return_t
187ipc_object_translate_two(
188 ipc_space_t space,
189 mach_port_name_t name1,
190 mach_port_right_t right1,
191 ipc_object_t *objectp1,
192 mach_port_name_t name2,
193 mach_port_right_t right2,
194 ipc_object_t *objectp2)
195{
196 ipc_entry_t entry1;
197 ipc_entry_t entry2;
198 ipc_object_t object;
199 kern_return_t kr;
200
201 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
202 if (kr != KERN_SUCCESS)
203 return kr;
204 /* space is read-locked and active */
205
206 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
207 is_read_unlock(space);
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 return KERN_INVALID_RIGHT;
214 }
215
216 object = entry1->ie_object;
217 assert(object != IO_NULL);
218 io_lock(object);
219 *objectp1 = object;
220
221 object = entry2->ie_object;
222 assert(object != IO_NULL);
223 io_lock(object);
224 *objectp2 = object;
225
226 is_read_unlock(space);
227 return KERN_SUCCESS;
228}
229
230/*
231 * Routine: ipc_object_alloc_dead
232 * Purpose:
233 * Allocate a dead-name entry.
234 * Conditions:
235 * Nothing locked.
236 * Returns:
237 * KERN_SUCCESS The dead name is allocated.
238 * KERN_INVALID_TASK The space is dead.
239 * KERN_NO_SPACE No room for an entry in the space.
240 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
241 */
242
243kern_return_t
244ipc_object_alloc_dead(
245 ipc_space_t space,
246 mach_port_name_t *namep)
247{
248 ipc_entry_t entry;
249 kern_return_t kr;
250
1c79356b
A
251 kr = ipc_entry_alloc(space, namep, &entry);
252 if (kr != KERN_SUCCESS)
253 return kr;
254 /* space is write-locked */
255
256 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
257
258 assert(entry->ie_object == IO_NULL);
259 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
316670eb 260 ipc_entry_modified(space, *namep, entry);
1c79356b
A
261 is_write_unlock(space);
262 return KERN_SUCCESS;
263}
264
265/*
266 * Routine: ipc_object_alloc_dead_name
267 * Purpose:
268 * Allocate a dead-name entry, with a specific name.
269 * Conditions:
270 * Nothing locked.
271 * Returns:
272 * KERN_SUCCESS The dead name is allocated.
273 * KERN_INVALID_TASK The space is dead.
274 * KERN_NAME_EXISTS The name already denotes a right.
275 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
276 */
277
278kern_return_t
279ipc_object_alloc_dead_name(
280 ipc_space_t space,
281 mach_port_name_t name)
282{
283 ipc_entry_t entry;
284 kern_return_t kr;
285
1c79356b
A
286 kr = ipc_entry_alloc_name(space, name, &entry);
287 if (kr != KERN_SUCCESS)
288 return kr;
289 /* space is write-locked */
290
291 if (ipc_right_inuse(space, name, entry))
292 return KERN_NAME_EXISTS;
293
294 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
295
296 assert(entry->ie_object == IO_NULL);
297 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
316670eb 298 ipc_entry_modified(space, name, entry);
1c79356b
A
299 is_write_unlock(space);
300 return KERN_SUCCESS;
301}
302
303/*
304 * Routine: ipc_object_alloc
305 * Purpose:
306 * Allocate an object.
307 * Conditions:
308 * Nothing locked. If successful, the object is returned locked.
99c3a104 309 * The space is write locked on successful return.
1c79356b
A
310 * The caller doesn't get a reference for the object.
311 * Returns:
312 * KERN_SUCCESS The object is allocated.
313 * KERN_INVALID_TASK The space is dead.
314 * KERN_NO_SPACE No room for an entry in the space.
315 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
316 */
317
318kern_return_t
319ipc_object_alloc(
320 ipc_space_t space,
321 ipc_object_type_t otype,
322 mach_port_type_t type,
323 mach_port_urefs_t urefs,
324 mach_port_name_t *namep,
325 ipc_object_t *objectp)
326{
327 ipc_object_t object;
328 ipc_entry_t entry;
329 kern_return_t kr;
330
331 assert(otype < IOT_NUMBER);
332 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
333 assert(type != MACH_PORT_TYPE_NONE);
334 assert(urefs <= MACH_PORT_UREFS_MAX);
335
336 object = io_alloc(otype);
337 if (object == IO_NULL)
338 return KERN_RESOURCE_SHORTAGE;
339
340 if (otype == IOT_PORT) {
341 ipc_port_t port = (ipc_port_t)object;
342
343 bzero((char *)port, sizeof(*port));
344 } else if (otype == IOT_PORT_SET) {
345 ipc_pset_t pset = (ipc_pset_t)object;
346
347 bzero((char *)pset, sizeof(*pset));
348 }
349
350 io_lock_init(object);
b0d623f7 351 *namep = CAST_MACH_PORT_TO_NAME(object);
1c79356b
A
352 kr = ipc_entry_alloc(space, namep, &entry);
353 if (kr != KERN_SUCCESS) {
354 io_free(otype, object);
355 return kr;
356 }
357 /* space is write-locked */
358
359 entry->ie_bits |= type | urefs;
360 entry->ie_object = object;
316670eb 361 ipc_entry_modified(space, *namep, entry);
1c79356b
A
362
363 io_lock(object);
1c79356b
A
364
365 object->io_references = 1; /* for entry, not caller */
366 object->io_bits = io_makebits(TRUE, otype, 0);
367
368 *objectp = object;
369 return KERN_SUCCESS;
370}
371
372/*
373 * Routine: ipc_object_alloc_name
374 * Purpose:
375 * Allocate an object, with a specific name.
376 * Conditions:
377 * Nothing locked. If successful, the object is returned locked.
378 * The caller doesn't get a reference for the object.
379 * Returns:
380 * KERN_SUCCESS The object is allocated.
381 * KERN_INVALID_TASK The space is dead.
382 * KERN_NAME_EXISTS The name already denotes a right.
383 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
384 */
385
386kern_return_t
387ipc_object_alloc_name(
388 ipc_space_t space,
389 ipc_object_type_t otype,
390 mach_port_type_t type,
391 mach_port_urefs_t urefs,
392 mach_port_name_t name,
393 ipc_object_t *objectp)
394{
395 ipc_object_t object;
396 ipc_entry_t entry;
397 kern_return_t kr;
398
399 assert(otype < IOT_NUMBER);
400 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
401 assert(type != MACH_PORT_TYPE_NONE);
402 assert(urefs <= MACH_PORT_UREFS_MAX);
403
404 object = io_alloc(otype);
405 if (object == IO_NULL)
406 return KERN_RESOURCE_SHORTAGE;
407
408 if (otype == IOT_PORT) {
409 ipc_port_t port = (ipc_port_t)object;
410
411 bzero((char *)port, sizeof(*port));
412 } else if (otype == IOT_PORT_SET) {
413 ipc_pset_t pset = (ipc_pset_t)object;
414
415 bzero((char *)pset, sizeof(*pset));
416 }
417
418 io_lock_init(object);
419 kr = ipc_entry_alloc_name(space, name, &entry);
420 if (kr != KERN_SUCCESS) {
421 io_free(otype, object);
422 return kr;
423 }
424 /* space is write-locked */
425
426 if (ipc_right_inuse(space, name, entry)) {
427 io_free(otype, object);
428 return KERN_NAME_EXISTS;
429 }
430
431 entry->ie_bits |= type | urefs;
432 entry->ie_object = object;
316670eb 433 ipc_entry_modified(space, name, entry);
1c79356b
A
434
435 io_lock(object);
436 is_write_unlock(space);
437
438 object->io_references = 1; /* for entry, not caller */
439 object->io_bits = io_makebits(TRUE, otype, 0);
440
441 *objectp = object;
442 return KERN_SUCCESS;
443}
444
445/*
446 * Routine: ipc_object_copyin_type
447 * Purpose:
448 * Convert a send type name to a received type name.
449 */
450
451mach_msg_type_name_t
452ipc_object_copyin_type(
453 mach_msg_type_name_t msgt_name)
454{
455 switch (msgt_name) {
456
457 case MACH_MSG_TYPE_MOVE_RECEIVE:
1c79356b
A
458 return MACH_MSG_TYPE_PORT_RECEIVE;
459
460 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
461 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
462 return MACH_MSG_TYPE_PORT_SEND_ONCE;
463
464 case MACH_MSG_TYPE_MOVE_SEND:
465 case MACH_MSG_TYPE_MAKE_SEND:
466 case MACH_MSG_TYPE_COPY_SEND:
467 return MACH_MSG_TYPE_PORT_SEND;
468
fe8ab488
A
469 case MACH_MSG_TYPE_DISPOSE_RECEIVE:
470 case MACH_MSG_TYPE_DISPOSE_SEND:
471 case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
472 /* fall thru */
1c79356b
A
473 default:
474 return MACH_MSG_TYPE_PORT_NONE;
475 }
476}
477
478/*
479 * Routine: ipc_object_copyin
480 * Purpose:
481 * Copyin a capability from a space.
482 * If successful, the caller gets a ref
483 * for the resulting object, unless it is IO_DEAD.
484 * Conditions:
485 * Nothing locked.
486 * Returns:
487 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
488 * KERN_INVALID_TASK The space is dead.
489 * KERN_INVALID_NAME Name doesn't exist in space.
490 * KERN_INVALID_RIGHT Name doesn't denote correct right.
491 */
492
493kern_return_t
494ipc_object_copyin(
495 ipc_space_t space,
496 mach_port_name_t name,
497 mach_msg_type_name_t msgt_name,
498 ipc_object_t *objectp)
499{
500 ipc_entry_t entry;
501 ipc_port_t soright;
316670eb 502 ipc_port_t release_port;
1c79356b 503 kern_return_t kr;
316670eb
A
504 queue_head_t links_data;
505 queue_t links = &links_data;
506 wait_queue_link_t wql;
507
39236c6e
A
508#if IMPORTANCE_INHERITANCE
509 int assertcnt = 0;
510#endif
511
316670eb 512 queue_init(links);
1c79356b 513
1c79356b
A
514 /*
515 * Could first try a read lock when doing
516 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
517 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
518 */
519
520 kr = ipc_right_lookup_write(space, name, &entry);
521 if (kr != KERN_SUCCESS)
522 return kr;
523 /* space is write-locked and active */
524
316670eb 525 release_port = IP_NULL;
1c79356b
A
526 kr = ipc_right_copyin(space, name, entry,
527 msgt_name, TRUE,
316670eb
A
528 objectp, &soright,
529 &release_port,
39236c6e
A
530#if IMPORTANCE_INHERITANCE
531 &assertcnt,
532#endif /* IMPORTANCE_INHERITANCE */
316670eb 533 links);
1c79356b
A
534 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
535 ipc_entry_dealloc(space, name, entry);
536 is_write_unlock(space);
537
316670eb
A
538 while(!queue_empty(links)) {
539 wql = (wait_queue_link_t) dequeue(links);
540 wait_queue_link_free(wql);
541 }
542
39236c6e 543#if IMPORTANCE_INHERITANCE
fe8ab488
A
544 if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
545 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
39236c6e
A
546 }
547#endif /* IMPORTANCE_INHERITANCE */
548
316670eb
A
549 if (release_port != IP_NULL)
550 ip_release(release_port);
551
1c79356b
A
552 if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
553 ipc_notify_port_deleted(soright, name);
554
555 return kr;
556}
557
558/*
559 * Routine: ipc_object_copyin_from_kernel
560 * Purpose:
561 * Copyin a naked capability from the kernel.
562 *
563 * MACH_MSG_TYPE_MOVE_RECEIVE
55e303ae
A
564 * The receiver must be ipc_space_kernel
565 * or the receive right must already be in limbo.
1c79356b
A
566 * Consumes the naked receive right.
567 * MACH_MSG_TYPE_COPY_SEND
568 * A naked send right must be supplied.
569 * The port gains a reference, and a send right
570 * if the port is still active.
571 * MACH_MSG_TYPE_MAKE_SEND
572 * The receiver must be ipc_space_kernel.
573 * The port gains a reference and a send right.
574 * MACH_MSG_TYPE_MOVE_SEND
575 * Consumes a naked send right.
576 * MACH_MSG_TYPE_MAKE_SEND_ONCE
577 * The port gains a reference and a send-once right.
578 * Receiver also be the caller of device subsystem,
579 * so no assertion.
580 * MACH_MSG_TYPE_MOVE_SEND_ONCE
581 * Consumes a naked send-once right.
582 * Conditions:
583 * Nothing locked.
584 */
585
586void
587ipc_object_copyin_from_kernel(
588 ipc_object_t object,
589 mach_msg_type_name_t msgt_name)
590{
591 assert(IO_VALID(object));
592
593 switch (msgt_name) {
594 case MACH_MSG_TYPE_MOVE_RECEIVE: {
595 ipc_port_t port = (ipc_port_t) object;
596
597 ip_lock(port);
598 assert(ip_active(port));
55e303ae
A
599 if (port->ip_destination != IP_NULL) {
600 assert(port->ip_receiver == ipc_space_kernel);
1c79356b 601
55e303ae
A
602 /* relevant part of ipc_port_clear_receiver */
603 ipc_port_set_mscount(port, 0);
1c79356b 604
55e303ae
A
605 port->ip_receiver_name = MACH_PORT_NULL;
606 port->ip_destination = IP_NULL;
607 }
1c79356b
A
608 ip_unlock(port);
609 break;
610 }
611
612 case MACH_MSG_TYPE_COPY_SEND: {
613 ipc_port_t port = (ipc_port_t) object;
614
615 ip_lock(port);
616 if (ip_active(port)) {
617 assert(port->ip_srights > 0);
618 port->ip_srights++;
619 }
620 ip_reference(port);
621 ip_unlock(port);
622 break;
623 }
624
625 case MACH_MSG_TYPE_MAKE_SEND: {
626 ipc_port_t port = (ipc_port_t) object;
627
628 ip_lock(port);
39236c6e
A
629 if (ip_active(port)) {
630 assert(port->ip_receiver_name != MACH_PORT_NULL);
631 assert(port->ip_receiver == ipc_space_kernel);
632 port->ip_mscount++;
633 }
1c79356b 634
1c79356b 635 port->ip_srights++;
39236c6e 636 ip_reference(port);
1c79356b
A
637 ip_unlock(port);
638 break;
639 }
640
55e303ae 641 case MACH_MSG_TYPE_MOVE_SEND: {
1c79356b 642 /* move naked send right into the message */
91447636 643 assert(((ipc_port_t)object)->ip_srights);
1c79356b 644 break;
55e303ae 645 }
1c79356b
A
646
647 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
648 ipc_port_t port = (ipc_port_t) object;
649
650 ip_lock(port);
39236c6e
A
651 if (ip_active(port)) {
652 assert(port->ip_receiver_name != MACH_PORT_NULL);
653 }
1c79356b 654 port->ip_sorights++;
39236c6e 655 ip_reference(port);
1c79356b
A
656 ip_unlock(port);
657 break;
658 }
659
55e303ae 660 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1c79356b 661 /* move naked send-once right into the message */
91447636 662 assert(((ipc_port_t)object)->ip_sorights);
1c79356b 663 break;
55e303ae 664 }
1c79356b
A
665
666 default:
667 panic("ipc_object_copyin_from_kernel: strange rights");
668 }
669}
670
671/*
672 * Routine: ipc_object_destroy
673 * Purpose:
674 * Destroys a naked capability.
675 * Consumes a ref for the object.
676 *
677 * A receive right should be in limbo or in transit.
678 * Conditions:
679 * Nothing locked.
680 */
681
682void
683ipc_object_destroy(
684 ipc_object_t object,
685 mach_msg_type_name_t msgt_name)
686{
687 assert(IO_VALID(object));
688 assert(io_otype(object) == IOT_PORT);
689
690 switch (msgt_name) {
691 case MACH_MSG_TYPE_PORT_SEND:
692 ipc_port_release_send((ipc_port_t) object);
693 break;
694
695 case MACH_MSG_TYPE_PORT_SEND_ONCE:
696 ipc_notify_send_once((ipc_port_t) object);
697 break;
698
699 case MACH_MSG_TYPE_PORT_RECEIVE:
700 ipc_port_release_receive((ipc_port_t) object);
701 break;
702
703 default:
704 panic("ipc_object_destroy: strange rights");
705 }
706}
707
6d2010ae
A
708/*
709 * Routine: ipc_object_destroy_dest
710 * Purpose:
711 * Destroys a naked capability for the destination of
712 * of a message. Consumes a ref for the object.
713 *
714 * Conditions:
715 * Nothing locked.
716 */
717
718void
719ipc_object_destroy_dest(
720 ipc_object_t object,
721 mach_msg_type_name_t msgt_name)
722{
723 assert(IO_VALID(object));
724 assert(io_otype(object) == IOT_PORT);
725
726 switch (msgt_name) {
727 case MACH_MSG_TYPE_PORT_SEND:
728 ipc_port_release_send((ipc_port_t) object);
729 break;
730
731 case MACH_MSG_TYPE_PORT_SEND_ONCE:
732 if (io_active(object) &&
733 !ip_full_kernel((ipc_port_t) object))
734 ipc_notify_send_once((ipc_port_t) object);
735 else
736 ipc_port_release_sonce((ipc_port_t) object);
737 break;
738
739 default:
740 panic("ipc_object_destroy_dest: strange rights");
741 }
742}
743
1c79356b
A
744/*
745 * Routine: ipc_object_copyout
746 * Purpose:
747 * Copyout a capability, placing it into a space.
748 * If successful, consumes a ref for the object.
749 * Conditions:
750 * Nothing locked.
751 * Returns:
752 * KERN_SUCCESS Copied out object, consumed ref.
753 * KERN_INVALID_TASK The space is dead.
754 * KERN_INVALID_CAPABILITY The object is dead.
755 * KERN_NO_SPACE No room in space for another right.
756 * KERN_RESOURCE_SHORTAGE No memory available.
757 * KERN_UREFS_OVERFLOW Urefs limit exceeded
758 * and overflow wasn't specified.
759 */
760
761kern_return_t
762ipc_object_copyout(
763 ipc_space_t space,
764 ipc_object_t object,
765 mach_msg_type_name_t msgt_name,
766 boolean_t overflow,
767 mach_port_name_t *namep)
768{
769 mach_port_name_t name;
770 ipc_entry_t entry;
771 kern_return_t kr;
772
773 assert(IO_VALID(object));
774 assert(io_otype(object) == IOT_PORT);
775
776 is_write_lock(space);
777
778 for (;;) {
316670eb 779 if (!is_active(space)) {
1c79356b
A
780 is_write_unlock(space);
781 return KERN_INVALID_TASK;
782 }
783
784 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
785 ipc_right_reverse(space, object, &name, &entry)) {
786 /* object is locked and active */
787
788 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
789 break;
790 }
791
b0d623f7 792 name = CAST_MACH_PORT_TO_NAME(object);
1c79356b
A
793 kr = ipc_entry_get(space, &name, &entry);
794 if (kr != KERN_SUCCESS) {
795 /* unlocks/locks space, so must start again */
796
797 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
798 if (kr != KERN_SUCCESS)
799 return kr; /* space is unlocked */
800
801 continue;
802 }
803
804 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
805 assert(entry->ie_object == IO_NULL);
806
807 io_lock(object);
808 if (!io_active(object)) {
809 io_unlock(object);
810 ipc_entry_dealloc(space, name, entry);
811 is_write_unlock(space);
812 return KERN_INVALID_CAPABILITY;
813 }
814
815 entry->ie_object = object;
816 break;
817 }
818
819 /* space is write-locked and active, object is locked and active */
820
821 kr = ipc_right_copyout(space, name, entry,
822 msgt_name, overflow, object);
39236c6e 823
1c79356b
A
824 /* object is unlocked */
825 is_write_unlock(space);
826
827 if (kr == KERN_SUCCESS)
828 *namep = name;
829 return kr;
830}
831
832/*
833 * Routine: ipc_object_copyout_name
834 * Purpose:
835 * Copyout a capability, placing it into a space.
836 * The specified name is used for the capability.
837 * If successful, consumes a ref for the object.
838 * Conditions:
839 * Nothing locked.
840 * Returns:
841 * KERN_SUCCESS Copied out object, consumed ref.
842 * KERN_INVALID_TASK The space is dead.
843 * KERN_INVALID_CAPABILITY The object is dead.
844 * KERN_RESOURCE_SHORTAGE No memory available.
845 * KERN_UREFS_OVERFLOW Urefs limit exceeded
846 * and overflow wasn't specified.
847 * KERN_RIGHT_EXISTS Space has rights under another name.
848 * KERN_NAME_EXISTS Name is already used.
849 */
850
851kern_return_t
852ipc_object_copyout_name(
853 ipc_space_t space,
854 ipc_object_t object,
855 mach_msg_type_name_t msgt_name,
856 boolean_t overflow,
857 mach_port_name_t name)
858{
859 mach_port_name_t oname;
860 ipc_entry_t oentry;
861 ipc_entry_t entry;
862 kern_return_t kr;
863
39236c6e
A
864#if IMPORTANCE_INHERITANCE
865 int assertcnt = 0;
fe8ab488 866 ipc_importance_task_t task_imp = IIT_NULL;
39236c6e
A
867#endif /* IMPORTANCE_INHERITANCE */
868
1c79356b
A
869 assert(IO_VALID(object));
870 assert(io_otype(object) == IOT_PORT);
871
872 kr = ipc_entry_alloc_name(space, name, &entry);
873 if (kr != KERN_SUCCESS)
874 return kr;
875 /* space is write-locked and active */
876
877 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
878 ipc_right_reverse(space, object, &oname, &oentry)) {
879 /* object is locked and active */
880
881 if (name != oname) {
882 io_unlock(object);
883
884 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
885 ipc_entry_dealloc(space, name, entry);
886
887 is_write_unlock(space);
888 return KERN_RIGHT_EXISTS;
889 }
890
891 assert(entry == oentry);
892 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
893 } else {
894 if (ipc_right_inuse(space, name, entry))
895 return KERN_NAME_EXISTS;
896
897 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
898 assert(entry->ie_object == IO_NULL);
899
900 io_lock(object);
901 if (!io_active(object)) {
902 io_unlock(object);
903 ipc_entry_dealloc(space, name, entry);
904 is_write_unlock(space);
905 return KERN_INVALID_CAPABILITY;
906 }
907
908 entry->ie_object = object;
909 }
910
911 /* space is write-locked and active, object is locked and active */
912
39236c6e
A
913#if IMPORTANCE_INHERITANCE
914 /*
915 * We are slamming a receive right into the space, without
916 * first having been enqueued on a port destined there. So,
917 * we have to arrange to boost the task appropriately if this
918 * port has assertions (and the task wants them).
919 */
920 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
921 ipc_port_t port = (ipc_port_t)object;
922
fe8ab488
A
923 if (space->is_task != TASK_NULL) {
924 task_imp = space->is_task->task_imp_base;
925 if (ipc_importance_task_is_any_receiver_type(task_imp)) {
926 assertcnt = port->ip_impcount;
927 ipc_importance_task_reference(task_imp);
928 }
39236c6e
A
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
1c79356b
A
938 kr = ipc_right_copyout(space, name, entry,
939 msgt_name, overflow, object);
39236c6e 940
1c79356b
A
941 /* object is unlocked */
942 is_write_unlock(space);
39236c6e
A
943
944#if IMPORTANCE_INHERITANCE
945 /*
946 * Add the assertions to the task that we captured before
947 */
fe8ab488
A
948 if (task_imp != IIT_NULL) {
949 ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
950 ipc_importance_task_release(task_imp);
39236c6e
A
951 }
952#endif /* IMPORTANCE_INHERITANCE */
953
1c79356b
A
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");
91447636 1048 name = MACH_PORT_DEAD;
1c79356b
A
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
1c79356b
A
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
1c79356b
A
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;
6d2010ae 1115 ipc_port_finalize(port);
1c79356b 1116 }
b0d623f7 1117 io_lock_destroy(object);
91447636 1118 zfree(ipc_object_zones[otype], object);
1c79356b 1119}