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