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