]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_object.c
xnu-2422.115.4.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>
1c79356b
A
86#include <ipc/port.h>
87#include <ipc/ipc_space.h>
88#include <ipc/ipc_entry.h>
89#include <ipc/ipc_object.h>
90#include <ipc/ipc_hash.h>
91#include <ipc/ipc_right.h>
92#include <ipc/ipc_notify.h>
6d2010ae 93#include <ipc/ipc_port.h>
1c79356b 94#include <ipc/ipc_pset.h>
2d21ac55
A
95#include <ipc/ipc_labelh.h>
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));
2d21ac55
A
344#if CONFIG_MACF_MACH
345 mac_port_label_init(&port->ip_label);
346#endif
1c79356b
A
347 } else if (otype == IOT_PORT_SET) {
348 ipc_pset_t pset = (ipc_pset_t)object;
349
350 bzero((char *)pset, sizeof(*pset));
351 }
352
353 io_lock_init(object);
b0d623f7 354 *namep = CAST_MACH_PORT_TO_NAME(object);
1c79356b
A
355 kr = ipc_entry_alloc(space, namep, &entry);
356 if (kr != KERN_SUCCESS) {
357 io_free(otype, object);
358 return kr;
359 }
360 /* space is write-locked */
361
362 entry->ie_bits |= type | urefs;
363 entry->ie_object = object;
316670eb 364 ipc_entry_modified(space, *namep, entry);
1c79356b
A
365
366 io_lock(object);
1c79356b
A
367
368 object->io_references = 1; /* for entry, not caller */
369 object->io_bits = io_makebits(TRUE, otype, 0);
370
371 *objectp = object;
372 return KERN_SUCCESS;
373}
374
375/*
376 * Routine: ipc_object_alloc_name
377 * Purpose:
378 * Allocate an object, with a specific name.
379 * Conditions:
380 * Nothing locked. If successful, the object is returned locked.
381 * The caller doesn't get a reference for the object.
382 * Returns:
383 * KERN_SUCCESS The object is allocated.
384 * KERN_INVALID_TASK The space is dead.
385 * KERN_NAME_EXISTS The name already denotes a right.
386 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
387 */
388
389kern_return_t
390ipc_object_alloc_name(
391 ipc_space_t space,
392 ipc_object_type_t otype,
393 mach_port_type_t type,
394 mach_port_urefs_t urefs,
395 mach_port_name_t name,
396 ipc_object_t *objectp)
397{
398 ipc_object_t object;
399 ipc_entry_t entry;
400 kern_return_t kr;
401
402 assert(otype < IOT_NUMBER);
403 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
404 assert(type != MACH_PORT_TYPE_NONE);
405 assert(urefs <= MACH_PORT_UREFS_MAX);
406
407 object = io_alloc(otype);
408 if (object == IO_NULL)
409 return KERN_RESOURCE_SHORTAGE;
410
411 if (otype == IOT_PORT) {
412 ipc_port_t port = (ipc_port_t)object;
413
414 bzero((char *)port, sizeof(*port));
2d21ac55
A
415#if CONFIG_MACF_MACH
416 mac_port_label_init(&port->ip_label);
417#endif
1c79356b
A
418 } else if (otype == IOT_PORT_SET) {
419 ipc_pset_t pset = (ipc_pset_t)object;
420
421 bzero((char *)pset, sizeof(*pset));
422 }
423
424 io_lock_init(object);
425 kr = ipc_entry_alloc_name(space, name, &entry);
426 if (kr != KERN_SUCCESS) {
427 io_free(otype, object);
428 return kr;
429 }
430 /* space is write-locked */
431
432 if (ipc_right_inuse(space, name, entry)) {
433 io_free(otype, object);
434 return KERN_NAME_EXISTS;
435 }
436
437 entry->ie_bits |= type | urefs;
438 entry->ie_object = object;
316670eb 439 ipc_entry_modified(space, name, entry);
1c79356b
A
440
441 io_lock(object);
442 is_write_unlock(space);
443
444 object->io_references = 1; /* for entry, not caller */
445 object->io_bits = io_makebits(TRUE, otype, 0);
446
447 *objectp = object;
448 return KERN_SUCCESS;
449}
450
451/*
452 * Routine: ipc_object_copyin_type
453 * Purpose:
454 * Convert a send type name to a received type name.
455 */
456
457mach_msg_type_name_t
458ipc_object_copyin_type(
459 mach_msg_type_name_t msgt_name)
460{
461 switch (msgt_name) {
462
463 case MACH_MSG_TYPE_MOVE_RECEIVE:
464 case MACH_MSG_TYPE_COPY_RECEIVE:
465 return MACH_MSG_TYPE_PORT_RECEIVE;
466
467 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
468 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
469 return MACH_MSG_TYPE_PORT_SEND_ONCE;
470
471 case MACH_MSG_TYPE_MOVE_SEND:
472 case MACH_MSG_TYPE_MAKE_SEND:
473 case MACH_MSG_TYPE_COPY_SEND:
474 return MACH_MSG_TYPE_PORT_SEND;
475
476 default:
477 return MACH_MSG_TYPE_PORT_NONE;
478 }
479}
480
481/*
482 * Routine: ipc_object_copyin
483 * Purpose:
484 * Copyin a capability from a space.
485 * If successful, the caller gets a ref
486 * for the resulting object, unless it is IO_DEAD.
487 * Conditions:
488 * Nothing locked.
489 * Returns:
490 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
491 * KERN_INVALID_TASK The space is dead.
492 * KERN_INVALID_NAME Name doesn't exist in space.
493 * KERN_INVALID_RIGHT Name doesn't denote correct right.
494 */
495
496kern_return_t
497ipc_object_copyin(
498 ipc_space_t space,
499 mach_port_name_t name,
500 mach_msg_type_name_t msgt_name,
501 ipc_object_t *objectp)
502{
503 ipc_entry_t entry;
504 ipc_port_t soright;
316670eb 505 ipc_port_t release_port;
1c79356b 506 kern_return_t kr;
316670eb
A
507 queue_head_t links_data;
508 queue_t links = &links_data;
509 wait_queue_link_t wql;
510
39236c6e
A
511#if IMPORTANCE_INHERITANCE
512 int assertcnt = 0;
513#endif
514
316670eb 515 queue_init(links);
1c79356b 516
1c79356b
A
517 /*
518 * Could first try a read lock when doing
519 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
520 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
521 */
522
523 kr = ipc_right_lookup_write(space, name, &entry);
524 if (kr != KERN_SUCCESS)
525 return kr;
526 /* space is write-locked and active */
527
316670eb 528 release_port = IP_NULL;
1c79356b
A
529 kr = ipc_right_copyin(space, name, entry,
530 msgt_name, TRUE,
316670eb
A
531 objectp, &soright,
532 &release_port,
39236c6e
A
533#if IMPORTANCE_INHERITANCE
534 &assertcnt,
535#endif /* IMPORTANCE_INHERITANCE */
316670eb 536 links);
1c79356b
A
537 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
538 ipc_entry_dealloc(space, name, entry);
539 is_write_unlock(space);
540
316670eb
A
541 while(!queue_empty(links)) {
542 wql = (wait_queue_link_t) dequeue(links);
543 wait_queue_link_free(wql);
544 }
545
39236c6e
A
546#if IMPORTANCE_INHERITANCE
547 if (assertcnt > 0 && current_task()->imp_receiver != 0) {
548 task_importance_drop_internal_assertion(current_task(), assertcnt);
549 }
550#endif /* IMPORTANCE_INHERITANCE */
551
316670eb
A
552 if (release_port != IP_NULL)
553 ip_release(release_port);
554
1c79356b
A
555 if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
556 ipc_notify_port_deleted(soright, name);
557
558 return kr;
559}
560
561/*
562 * Routine: ipc_object_copyin_from_kernel
563 * Purpose:
564 * Copyin a naked capability from the kernel.
565 *
566 * MACH_MSG_TYPE_MOVE_RECEIVE
55e303ae
A
567 * The receiver must be ipc_space_kernel
568 * or the receive right must already be in limbo.
1c79356b
A
569 * Consumes the naked receive right.
570 * MACH_MSG_TYPE_COPY_SEND
571 * A naked send right must be supplied.
572 * The port gains a reference, and a send right
573 * if the port is still active.
574 * MACH_MSG_TYPE_MAKE_SEND
575 * The receiver must be ipc_space_kernel.
576 * The port gains a reference and a send right.
577 * MACH_MSG_TYPE_MOVE_SEND
578 * Consumes a naked send right.
579 * MACH_MSG_TYPE_MAKE_SEND_ONCE
580 * The port gains a reference and a send-once right.
581 * Receiver also be the caller of device subsystem,
582 * so no assertion.
583 * MACH_MSG_TYPE_MOVE_SEND_ONCE
584 * Consumes a naked send-once right.
585 * Conditions:
586 * Nothing locked.
587 */
588
589void
590ipc_object_copyin_from_kernel(
591 ipc_object_t object,
592 mach_msg_type_name_t msgt_name)
593{
594 assert(IO_VALID(object));
595
596 switch (msgt_name) {
597 case MACH_MSG_TYPE_MOVE_RECEIVE: {
598 ipc_port_t port = (ipc_port_t) object;
599
600 ip_lock(port);
601 assert(ip_active(port));
55e303ae
A
602 if (port->ip_destination != IP_NULL) {
603 assert(port->ip_receiver == ipc_space_kernel);
1c79356b 604
55e303ae
A
605 /* relevant part of ipc_port_clear_receiver */
606 ipc_port_set_mscount(port, 0);
1c79356b 607
55e303ae
A
608 port->ip_receiver_name = MACH_PORT_NULL;
609 port->ip_destination = IP_NULL;
610 }
1c79356b
A
611 ip_unlock(port);
612 break;
613 }
614
615 case MACH_MSG_TYPE_COPY_SEND: {
616 ipc_port_t port = (ipc_port_t) object;
617
618 ip_lock(port);
619 if (ip_active(port)) {
620 assert(port->ip_srights > 0);
621 port->ip_srights++;
622 }
623 ip_reference(port);
624 ip_unlock(port);
625 break;
626 }
627
628 case MACH_MSG_TYPE_MAKE_SEND: {
629 ipc_port_t port = (ipc_port_t) object;
630
631 ip_lock(port);
39236c6e
A
632 if (ip_active(port)) {
633 assert(port->ip_receiver_name != MACH_PORT_NULL);
634 assert(port->ip_receiver == ipc_space_kernel);
635 port->ip_mscount++;
636 }
1c79356b 637
1c79356b 638 port->ip_srights++;
39236c6e 639 ip_reference(port);
1c79356b
A
640 ip_unlock(port);
641 break;
642 }
643
55e303ae 644 case MACH_MSG_TYPE_MOVE_SEND: {
1c79356b 645 /* move naked send right into the message */
91447636 646 assert(((ipc_port_t)object)->ip_srights);
1c79356b 647 break;
55e303ae 648 }
1c79356b
A
649
650 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
651 ipc_port_t port = (ipc_port_t) object;
652
653 ip_lock(port);
39236c6e
A
654 if (ip_active(port)) {
655 assert(port->ip_receiver_name != MACH_PORT_NULL);
656 }
1c79356b 657 port->ip_sorights++;
39236c6e 658 ip_reference(port);
1c79356b
A
659 ip_unlock(port);
660 break;
661 }
662
55e303ae 663 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1c79356b 664 /* move naked send-once right into the message */
91447636 665 assert(((ipc_port_t)object)->ip_sorights);
1c79356b 666 break;
55e303ae 667 }
1c79356b
A
668
669 default:
670 panic("ipc_object_copyin_from_kernel: strange rights");
671 }
672}
673
674/*
675 * Routine: ipc_object_destroy
676 * Purpose:
677 * Destroys a naked capability.
678 * Consumes a ref for the object.
679 *
680 * A receive right should be in limbo or in transit.
681 * Conditions:
682 * Nothing locked.
683 */
684
685void
686ipc_object_destroy(
687 ipc_object_t object,
688 mach_msg_type_name_t msgt_name)
689{
690 assert(IO_VALID(object));
691 assert(io_otype(object) == IOT_PORT);
692
693 switch (msgt_name) {
694 case MACH_MSG_TYPE_PORT_SEND:
695 ipc_port_release_send((ipc_port_t) object);
696 break;
697
698 case MACH_MSG_TYPE_PORT_SEND_ONCE:
699 ipc_notify_send_once((ipc_port_t) object);
700 break;
701
702 case MACH_MSG_TYPE_PORT_RECEIVE:
703 ipc_port_release_receive((ipc_port_t) object);
704 break;
705
706 default:
707 panic("ipc_object_destroy: strange rights");
708 }
709}
710
6d2010ae
A
711/*
712 * Routine: ipc_object_destroy_dest
713 * Purpose:
714 * Destroys a naked capability for the destination of
715 * of a message. Consumes a ref for the object.
716 *
717 * Conditions:
718 * Nothing locked.
719 */
720
721void
722ipc_object_destroy_dest(
723 ipc_object_t object,
724 mach_msg_type_name_t msgt_name)
725{
726 assert(IO_VALID(object));
727 assert(io_otype(object) == IOT_PORT);
728
729 switch (msgt_name) {
730 case MACH_MSG_TYPE_PORT_SEND:
731 ipc_port_release_send((ipc_port_t) object);
732 break;
733
734 case MACH_MSG_TYPE_PORT_SEND_ONCE:
735 if (io_active(object) &&
736 !ip_full_kernel((ipc_port_t) object))
737 ipc_notify_send_once((ipc_port_t) object);
738 else
739 ipc_port_release_sonce((ipc_port_t) object);
740 break;
741
742 default:
743 panic("ipc_object_destroy_dest: strange rights");
744 }
745}
746
1c79356b
A
747/*
748 * Routine: ipc_object_copyout
749 * Purpose:
750 * Copyout a capability, placing it into a space.
751 * If successful, consumes a ref for the object.
752 * Conditions:
753 * Nothing locked.
754 * Returns:
755 * KERN_SUCCESS Copied out object, consumed ref.
756 * KERN_INVALID_TASK The space is dead.
757 * KERN_INVALID_CAPABILITY The object is dead.
758 * KERN_NO_SPACE No room in space for another right.
759 * KERN_RESOURCE_SHORTAGE No memory available.
760 * KERN_UREFS_OVERFLOW Urefs limit exceeded
761 * and overflow wasn't specified.
762 */
763
764kern_return_t
765ipc_object_copyout(
766 ipc_space_t space,
767 ipc_object_t object,
768 mach_msg_type_name_t msgt_name,
769 boolean_t overflow,
770 mach_port_name_t *namep)
771{
772 mach_port_name_t name;
773 ipc_entry_t entry;
774 kern_return_t kr;
775
776 assert(IO_VALID(object));
777 assert(io_otype(object) == IOT_PORT);
778
779 is_write_lock(space);
780
781 for (;;) {
316670eb 782 if (!is_active(space)) {
1c79356b
A
783 is_write_unlock(space);
784 return KERN_INVALID_TASK;
785 }
786
787 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
788 ipc_right_reverse(space, object, &name, &entry)) {
789 /* object is locked and active */
790
791 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
792 break;
793 }
794
b0d623f7 795 name = CAST_MACH_PORT_TO_NAME(object);
1c79356b
A
796 kr = ipc_entry_get(space, &name, &entry);
797 if (kr != KERN_SUCCESS) {
798 /* unlocks/locks space, so must start again */
799
800 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
801 if (kr != KERN_SUCCESS)
802 return kr; /* space is unlocked */
803
804 continue;
805 }
806
807 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
808 assert(entry->ie_object == IO_NULL);
809
810 io_lock(object);
811 if (!io_active(object)) {
812 io_unlock(object);
813 ipc_entry_dealloc(space, name, entry);
814 is_write_unlock(space);
815 return KERN_INVALID_CAPABILITY;
816 }
817
818 entry->ie_object = object;
819 break;
820 }
821
822 /* space is write-locked and active, object is locked and active */
823
824 kr = ipc_right_copyout(space, name, entry,
825 msgt_name, overflow, object);
39236c6e 826
1c79356b
A
827 /* object is unlocked */
828 is_write_unlock(space);
829
830 if (kr == KERN_SUCCESS)
831 *namep = name;
832 return kr;
833}
834
835/*
836 * Routine: ipc_object_copyout_name
837 * Purpose:
838 * Copyout a capability, placing it into a space.
839 * The specified name is used for the capability.
840 * If successful, consumes a ref for the object.
841 * Conditions:
842 * Nothing locked.
843 * Returns:
844 * KERN_SUCCESS Copied out object, consumed ref.
845 * KERN_INVALID_TASK The space is dead.
846 * KERN_INVALID_CAPABILITY The object is dead.
847 * KERN_RESOURCE_SHORTAGE No memory available.
848 * KERN_UREFS_OVERFLOW Urefs limit exceeded
849 * and overflow wasn't specified.
850 * KERN_RIGHT_EXISTS Space has rights under another name.
851 * KERN_NAME_EXISTS Name is already used.
852 */
853
854kern_return_t
855ipc_object_copyout_name(
856 ipc_space_t space,
857 ipc_object_t object,
858 mach_msg_type_name_t msgt_name,
859 boolean_t overflow,
860 mach_port_name_t name)
861{
862 mach_port_name_t oname;
863 ipc_entry_t oentry;
864 ipc_entry_t entry;
865 kern_return_t kr;
866
39236c6e
A
867#if IMPORTANCE_INHERITANCE
868 int assertcnt = 0;
869 task_t task = TASK_NULL;
870#endif /* IMPORTANCE_INHERITANCE */
871
1c79356b
A
872 assert(IO_VALID(object));
873 assert(io_otype(object) == IOT_PORT);
874
875 kr = ipc_entry_alloc_name(space, name, &entry);
876 if (kr != KERN_SUCCESS)
877 return kr;
878 /* space is write-locked and active */
879
880 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
881 ipc_right_reverse(space, object, &oname, &oentry)) {
882 /* object is locked and active */
883
884 if (name != oname) {
885 io_unlock(object);
886
887 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
888 ipc_entry_dealloc(space, name, entry);
889
890 is_write_unlock(space);
891 return KERN_RIGHT_EXISTS;
892 }
893
894 assert(entry == oentry);
895 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
896 } else {
897 if (ipc_right_inuse(space, name, entry))
898 return KERN_NAME_EXISTS;
899
900 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
901 assert(entry->ie_object == IO_NULL);
902
903 io_lock(object);
904 if (!io_active(object)) {
905 io_unlock(object);
906 ipc_entry_dealloc(space, name, entry);
907 is_write_unlock(space);
908 return KERN_INVALID_CAPABILITY;
909 }
910
911 entry->ie_object = object;
912 }
913
914 /* space is write-locked and active, object is locked and active */
915
39236c6e
A
916#if IMPORTANCE_INHERITANCE
917 /*
918 * We are slamming a receive right into the space, without
919 * first having been enqueued on a port destined there. So,
920 * we have to arrange to boost the task appropriately if this
921 * port has assertions (and the task wants them).
922 */
923 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
924 ipc_port_t port = (ipc_port_t)object;
925
926 if ((space->is_task != TASK_NULL) &&
927 (space->is_task->imp_receiver != 0)) {
928 assertcnt = port->ip_impcount;
929 task = space->is_task;
930 task_reference(task);
931 }
932
933 /* take port out of limbo */
934 assert(port->ip_tempowner != 0);
935 port->ip_tempowner = 0;
936 }
937
938#endif /* IMPORTANCE_INHERITANCE */
939
1c79356b
A
940 kr = ipc_right_copyout(space, name, entry,
941 msgt_name, overflow, object);
39236c6e 942
1c79356b
A
943 /* object is unlocked */
944 is_write_unlock(space);
39236c6e
A
945
946#if IMPORTANCE_INHERITANCE
947 /*
948 * Add the assertions to the task that we captured before
949 */
950 if (task != TASK_NULL) {
951 if (assertcnt > 0)
952 task_importance_hold_internal_assertion(task, assertcnt);
953 task_deallocate(task);
954 }
955#endif /* IMPORTANCE_INHERITANCE */
956
1c79356b
A
957 return kr;
958}
959
960/*
961 * Routine: ipc_object_copyout_dest
962 * Purpose:
963 * Translates/consumes the destination right of a message.
964 * This is unlike normal copyout because the right is consumed
965 * in a funny way instead of being given to the receiving space.
966 * The receiver gets his name for the port, if he has receive
967 * rights, otherwise MACH_PORT_NULL.
968 * Conditions:
969 * The object is locked and active. Nothing else locked.
970 * The object is unlocked and loses a reference.
971 */
972
973void
974ipc_object_copyout_dest(
975 ipc_space_t space,
976 ipc_object_t object,
977 mach_msg_type_name_t msgt_name,
978 mach_port_name_t *namep)
979{
980 mach_port_name_t name;
981
982 assert(IO_VALID(object));
983 assert(io_active(object));
984
985 io_release(object);
986
987 /*
988 * If the space is the receiver/owner of the object,
989 * then we quietly consume the right and return
990 * the space's name for the object. Otherwise
991 * we destroy the right and return MACH_PORT_NULL.
992 */
993
994 switch (msgt_name) {
995 case MACH_MSG_TYPE_PORT_SEND: {
996 ipc_port_t port = (ipc_port_t) object;
997 ipc_port_t nsrequest = IP_NULL;
998 mach_port_mscount_t mscount;
999
1000 if (port->ip_receiver == space)
1001 name = port->ip_receiver_name;
1002 else
1003 name = MACH_PORT_NULL;
1004
1005 assert(port->ip_srights > 0);
1006 if (--port->ip_srights == 0 &&
1007 port->ip_nsrequest != IP_NULL) {
1008 nsrequest = port->ip_nsrequest;
1009 port->ip_nsrequest = IP_NULL;
1010 mscount = port->ip_mscount;
1011 ip_unlock(port);
1012 ipc_notify_no_senders(nsrequest, mscount);
1013 } else
1014 ip_unlock(port);
1015 break;
1016 }
1017
1018 case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1019 ipc_port_t port = (ipc_port_t) object;
1020
1021 assert(port->ip_sorights > 0);
1022
1023 if (port->ip_receiver == space) {
1024 /* quietly consume the send-once right */
1025
1026 port->ip_sorights--;
1027 name = port->ip_receiver_name;
1028 ip_unlock(port);
1029 } else {
1030 /*
1031 * A very bizarre case. The message
1032 * was received, but before this copyout
1033 * happened the space lost receive rights.
1034 * We can't quietly consume the soright
1035 * out from underneath some other task,
1036 * so generate a send-once notification.
1037 */
1038
1039 ip_reference(port); /* restore ref */
1040 ip_unlock(port);
1041
1042 ipc_notify_send_once(port);
1043 name = MACH_PORT_NULL;
1044 }
1045
1046 break;
1047 }
1048
1049 default:
1050 panic("ipc_object_copyout_dest: strange rights");
91447636 1051 name = MACH_PORT_DEAD;
1c79356b
A
1052 }
1053
1054 *namep = name;
1055}
1056
1057/*
1058 * Routine: ipc_object_rename
1059 * Purpose:
1060 * Rename an entry in a space.
1061 * Conditions:
1062 * Nothing locked.
1063 * Returns:
1064 * KERN_SUCCESS Renamed the entry.
1065 * KERN_INVALID_TASK The space was dead.
1066 * KERN_INVALID_NAME oname didn't denote an entry.
1067 * KERN_NAME_EXISTS nname already denoted an entry.
1068 * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry.
1069 */
1070
1071kern_return_t
1072ipc_object_rename(
1073 ipc_space_t space,
1074 mach_port_name_t oname,
1075 mach_port_name_t nname)
1076{
1077 ipc_entry_t oentry, nentry;
1078 kern_return_t kr;
1079
1c79356b
A
1080 kr = ipc_entry_alloc_name(space, nname, &nentry);
1081 if (kr != KERN_SUCCESS)
1082 return kr;
1083
1084 /* space is write-locked and active */
1085
1086 if (ipc_right_inuse(space, nname, nentry)) {
1087 /* space is unlocked */
1088 return KERN_NAME_EXISTS;
1089 }
1090
1091 /* don't let ipc_entry_lookup see the uninitialized new entry */
1092
1093 if ((oname == nname) ||
1094 ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
1095 ipc_entry_dealloc(space, nname, nentry);
1096 is_write_unlock(space);
1097 return KERN_INVALID_NAME;
1098 }
1099
1100 kr = ipc_right_rename(space, oname, oentry, nname, nentry);
1101 /* space is unlocked */
1102 return kr;
1103}
1104
2d21ac55
A
1105/*
1106 * Get a label out of a port, to be used by a kernel call
1107 * that takes a security label as a parameter. In this case, we want
1108 * to use the label stored in the label handle and not the label on its
1109 * port.
1110 *
1111 * The port should be locked for this call. The lock protecting
1112 * label handle contents should not be necessary, as they can only
1113 * be modified when a label handle with one reference is a task label.
1114 * User allocated label handles can never be modified.
1115 */
1116#if CONFIG_MACF_MACH
1117struct label *io_getlabel (ipc_object_t objp)
1118{
1119 ipc_port_t port = (ipc_port_t)objp;
1120
1121 assert(io_otype(objp) == IOT_PORT);
1122
1123 if (ip_kotype(port) == IKOT_LABELH)
1124 return &((ipc_labelh_t) port->ip_kobject)->lh_label;
1125 else
1126 return &port->ip_label;
1127}
1128#endif
b0d623f7 1129
1c79356b
A
1130/*
1131 * Check whether the object is a port if so, free it. But
1132 * keep track of that fact.
1133 */
1134void
1135io_free(
1136 unsigned int otype,
1137 ipc_object_t object)
1138{
1139 ipc_port_t port;
1140
1141 if (otype == IOT_PORT) {
1142 port = (ipc_port_t) object;
6d2010ae 1143 ipc_port_finalize(port);
1c79356b 1144 }
b0d623f7 1145 io_lock_destroy(object);
91447636 1146 zfree(ipc_object_zones[otype], object);
1c79356b 1147}