]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_object.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_object.c
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
63 /*
64 */
65 /*
66 * File: ipc/ipc_object.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Functions to manipulate IPC objects.
71 */
72
73 #include <mach/mach_types.h>
74 #include <mach/boolean.h>
75 #include <mach/kern_return.h>
76 #include <mach/port.h>
77 #include <mach/message.h>
78
79 #include <kern/kern_types.h>
80 #include <kern/misc_protos.h>
81 #include <kern/ipc_kobject.h>
82
83 #include <ipc/ipc_types.h>
84 #include <ipc/ipc_importance.h>
85 #include <ipc/port.h>
86 #include <ipc/ipc_space.h>
87 #include <ipc/ipc_entry.h>
88 #include <ipc/ipc_object.h>
89 #include <ipc/ipc_hash.h>
90 #include <ipc/ipc_right.h>
91 #include <ipc/ipc_notify.h>
92 #include <ipc/ipc_port.h>
93 #include <ipc/ipc_pset.h>
94
95 #include <security/mac_mach_internal.h>
96
97 zone_t ipc_object_zones[IOT_NUMBER];
98
99 /*
100 * Routine: ipc_object_reference
101 * Purpose:
102 * Take a reference to an object.
103 */
104
105 void
106 ipc_object_reference(
107 ipc_object_t object)
108 {
109 io_reference(object);
110 }
111
112 /*
113 * Routine: ipc_object_release
114 * Purpose:
115 * Release a reference to an object.
116 */
117
118 void
119 ipc_object_release(
120 ipc_object_t object)
121 {
122 io_release(object);
123 }
124
125 /*
126 * Routine: ipc_object_translate
127 * Purpose:
128 * Look up an object in a space.
129 * Conditions:
130 * Nothing locked before. If successful, the object
131 * is returned active and locked. The caller doesn't get a ref.
132 * Returns:
133 * KERN_SUCCESS Object returned locked.
134 * KERN_INVALID_TASK The space is dead.
135 * KERN_INVALID_NAME The name doesn't denote a right
136 * KERN_INVALID_RIGHT Name doesn't denote the correct right
137 */
138 kern_return_t
139 ipc_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 if (!MACH_PORT_RIGHT_VALID_TRANSLATE(right)) {
150 return KERN_INVALID_RIGHT;
151 }
152
153 kr = ipc_right_lookup_read(space, name, &entry);
154 if (kr != KERN_SUCCESS) {
155 return kr;
156 }
157 /* space is read-locked and active */
158
159 if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
160 is_read_unlock(space);
161 return KERN_INVALID_RIGHT;
162 }
163
164 object = entry->ie_object;
165 assert(object != IO_NULL);
166
167 io_lock(object);
168 is_read_unlock(space);
169
170 if (!io_active(object)) {
171 io_unlock(object);
172 return KERN_INVALID_NAME;
173 }
174
175 *objectp = object;
176 return KERN_SUCCESS;
177 }
178
179 /*
180 * Routine: ipc_object_translate_two
181 * Purpose:
182 * Look up two objects in a space.
183 * Conditions:
184 * Nothing locked before. If successful, the objects
185 * are returned locked. The caller doesn't get a ref.
186 * Returns:
187 * KERN_SUCCESS Objects returned locked.
188 * KERN_INVALID_TASK The space is dead.
189 * KERN_INVALID_NAME A name doesn't denote a right.
190 * KERN_INVALID_RIGHT A name doesn't denote the correct right.
191 */
192
193 kern_return_t
194 ipc_object_translate_two(
195 ipc_space_t space,
196 mach_port_name_t name1,
197 mach_port_right_t right1,
198 ipc_object_t *objectp1,
199 mach_port_name_t name2,
200 mach_port_right_t right2,
201 ipc_object_t *objectp2)
202 {
203 ipc_entry_t entry1;
204 ipc_entry_t entry2;
205 ipc_object_t object1, object2;
206 kern_return_t kr;
207 boolean_t doguard = TRUE;
208
209 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
210 if (kr != KERN_SUCCESS) {
211 return kr;
212 }
213 /* space is read-locked and active */
214
215 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
216 /* If looking for receive, and the entry used to hold one, give a pass on EXC_GUARD */
217 if ((right1 & MACH_PORT_RIGHT_RECEIVE) == MACH_PORT_RIGHT_RECEIVE &&
218 (entry1->ie_bits & MACH_PORT_TYPE_EX_RECEIVE) == MACH_PORT_TYPE_EX_RECEIVE) {
219 doguard = FALSE;
220 }
221 is_read_unlock(space);
222 if (doguard) {
223 mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT);
224 }
225 return KERN_INVALID_RIGHT;
226 }
227
228 if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
229 /* If looking for receive, and the entry used to hold one, give a pass on EXC_GUARD */
230 if ((right2 & MACH_PORT_RIGHT_RECEIVE) == MACH_PORT_RIGHT_RECEIVE &&
231 (entry2->ie_bits & MACH_PORT_TYPE_EX_RECEIVE) == MACH_PORT_TYPE_EX_RECEIVE) {
232 doguard = FALSE;
233 }
234 is_read_unlock(space);
235 if (doguard) {
236 mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT);
237 }
238 return KERN_INVALID_RIGHT;
239 }
240
241 object1 = entry1->ie_object;
242 assert(object1 != IO_NULL);
243 io_lock(object1);
244 if (!io_active(object1)) {
245 io_unlock(object1);
246 is_read_unlock(space);
247 return KERN_INVALID_NAME;
248 }
249
250 object2 = entry2->ie_object;
251 assert(object2 != IO_NULL);
252 io_lock(object2);
253 if (!io_active(object2)) {
254 io_unlock(object1);
255 io_unlock(object2);
256 is_read_unlock(space);
257 return KERN_INVALID_NAME;
258 }
259
260 *objectp1 = object1;
261 *objectp2 = object2;
262
263 is_read_unlock(space);
264 return KERN_SUCCESS;
265 }
266
267 /*
268 * Routine: ipc_object_alloc_dead
269 * Purpose:
270 * Allocate a dead-name entry.
271 * Conditions:
272 * Nothing locked.
273 * Returns:
274 * KERN_SUCCESS The dead name is allocated.
275 * KERN_INVALID_TASK The space is dead.
276 * KERN_NO_SPACE No room for an entry in the space.
277 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
278 */
279
280 kern_return_t
281 ipc_object_alloc_dead(
282 ipc_space_t space,
283 mach_port_name_t *namep)
284 {
285 ipc_entry_t entry;
286 kern_return_t kr;
287
288 kr = ipc_entry_alloc(space, namep, &entry);
289 if (kr != KERN_SUCCESS) {
290 return kr;
291 }
292 /* space is write-locked */
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;
298 ipc_entry_modified(space, *namep, entry);
299 is_write_unlock(space);
300 return KERN_SUCCESS;
301 }
302
303 /*
304 * Routine: ipc_object_alloc_dead_name
305 * Purpose:
306 * Allocate a dead-name entry, with a specific name.
307 * Conditions:
308 * Nothing locked.
309 * Returns:
310 * KERN_SUCCESS The dead name is allocated.
311 * KERN_INVALID_TASK The space is dead.
312 * KERN_NAME_EXISTS The name already denotes a right.
313 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
314 */
315
316 kern_return_t
317 ipc_object_alloc_dead_name(
318 ipc_space_t space,
319 mach_port_name_t name)
320 {
321 ipc_entry_t entry;
322 kern_return_t kr;
323
324 kr = ipc_entry_alloc_name(space, name, &entry);
325 if (kr != KERN_SUCCESS) {
326 return kr;
327 }
328 /* space is write-locked */
329
330 if (ipc_right_inuse(space, name, entry)) {
331 return KERN_NAME_EXISTS;
332 }
333
334 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
335
336 assert(entry->ie_object == IO_NULL);
337 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
338 ipc_entry_modified(space, name, entry);
339 is_write_unlock(space);
340 return KERN_SUCCESS;
341 }
342
343 /*
344 * Routine: ipc_object_alloc
345 * Purpose:
346 * Allocate an object.
347 * Conditions:
348 * Nothing locked. If successful, the object is returned locked.
349 * The space is write locked on successful return.
350 * The caller doesn't get a reference for the object.
351 * Returns:
352 * KERN_SUCCESS The object is allocated.
353 * KERN_INVALID_TASK The space is dead.
354 * KERN_NO_SPACE No room for an entry in the space.
355 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
356 */
357
358 kern_return_t
359 ipc_object_alloc(
360 ipc_space_t space,
361 ipc_object_type_t otype,
362 mach_port_type_t type,
363 mach_port_urefs_t urefs,
364 mach_port_name_t *namep,
365 ipc_object_t *objectp)
366 {
367 ipc_object_t object;
368 ipc_entry_t entry;
369 kern_return_t kr;
370
371 assert(otype < IOT_NUMBER);
372 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
373 assert(type != MACH_PORT_TYPE_NONE);
374 assert(urefs <= MACH_PORT_UREFS_MAX);
375
376 object = io_alloc(otype);
377 if (object == IO_NULL) {
378 return KERN_RESOURCE_SHORTAGE;
379 }
380
381 if (otype == IOT_PORT) {
382 ipc_port_t port = ip_object_to_port(object);
383
384 bzero((char *)port, sizeof(*port));
385 } else if (otype == IOT_PORT_SET) {
386 ipc_pset_t pset = ips_object_to_pset(object);
387
388 bzero((char *)pset, sizeof(*pset));
389 }
390
391 io_lock_init(object);
392 *namep = CAST_MACH_PORT_TO_NAME(object);
393 kr = ipc_entry_alloc(space, namep, &entry);
394 if (kr != KERN_SUCCESS) {
395 io_free(otype, object);
396 return kr;
397 }
398 /* space is write-locked */
399
400 entry->ie_bits |= type | urefs;
401 entry->ie_object = object;
402 ipc_entry_modified(space, *namep, entry);
403
404 object->io_bits = io_makebits(TRUE, otype, 0);
405 io_lock(object);
406
407 object->io_references = 1; /* for entry, not caller */
408
409 *objectp = object;
410 return KERN_SUCCESS;
411 }
412
413 /*
414 * Routine: ipc_object_alloc_name
415 * Purpose:
416 * Allocate an object, with a specific name.
417 * Conditions:
418 * Nothing locked. If successful, the object is returned locked.
419 * The caller doesn't get a reference for the object.
420 * Returns:
421 * KERN_SUCCESS The object is allocated.
422 * KERN_INVALID_TASK The space is dead.
423 * KERN_NAME_EXISTS The name already denotes a right.
424 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
425 */
426
427 kern_return_t
428 ipc_object_alloc_name(
429 ipc_space_t space,
430 ipc_object_type_t otype,
431 mach_port_type_t type,
432 mach_port_urefs_t urefs,
433 mach_port_name_t name,
434 ipc_object_t *objectp)
435 {
436 ipc_object_t object;
437 ipc_entry_t entry;
438 kern_return_t kr;
439
440 assert(otype < IOT_NUMBER);
441 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
442 assert(type != MACH_PORT_TYPE_NONE);
443 assert(urefs <= MACH_PORT_UREFS_MAX);
444
445 object = io_alloc(otype);
446 if (object == IO_NULL) {
447 return KERN_RESOURCE_SHORTAGE;
448 }
449
450 if (otype == IOT_PORT) {
451 ipc_port_t port = ip_object_to_port(object);
452
453 bzero((char *)port, sizeof(*port));
454 } else if (otype == IOT_PORT_SET) {
455 ipc_pset_t pset = ips_object_to_pset(object);
456
457 bzero((char *)pset, sizeof(*pset));
458 }
459
460 io_lock_init(object);
461 kr = ipc_entry_alloc_name(space, name, &entry);
462 if (kr != KERN_SUCCESS) {
463 io_free(otype, object);
464 return kr;
465 }
466 /* space is write-locked */
467
468 if (ipc_right_inuse(space, name, entry)) {
469 io_free(otype, object);
470 return KERN_NAME_EXISTS;
471 }
472
473 entry->ie_bits |= type | urefs;
474 entry->ie_object = object;
475 ipc_entry_modified(space, name, entry);
476
477 object->io_bits = io_makebits(TRUE, otype, 0);
478
479 io_lock(object);
480 is_write_unlock(space);
481
482 object->io_references = 1; /* for entry, not caller */
483
484 *objectp = object;
485 return KERN_SUCCESS;
486 }
487
488 /* Routine: ipc_object_validate
489 * Purpose:
490 * Validates an ipc port or port set as belonging to the correct
491 * zone.
492 */
493
494 void
495 ipc_object_validate(
496 ipc_object_t object)
497 {
498 int otype = (io_otype(object) == IOT_PORT_SET) ? IOT_PORT_SET : IOT_PORT;
499 zone_require(object, ipc_object_zones[otype]);
500 }
501
502 /*
503 * Routine: ipc_object_copyin_type
504 * Purpose:
505 * Convert a send type name to a received type name.
506 */
507
508 mach_msg_type_name_t
509 ipc_object_copyin_type(
510 mach_msg_type_name_t msgt_name)
511 {
512 switch (msgt_name) {
513 case MACH_MSG_TYPE_MOVE_RECEIVE:
514 return MACH_MSG_TYPE_PORT_RECEIVE;
515
516 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
517 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
518 return MACH_MSG_TYPE_PORT_SEND_ONCE;
519
520 case MACH_MSG_TYPE_MOVE_SEND:
521 case MACH_MSG_TYPE_MAKE_SEND:
522 case MACH_MSG_TYPE_COPY_SEND:
523 return MACH_MSG_TYPE_PORT_SEND;
524
525 case MACH_MSG_TYPE_DISPOSE_RECEIVE:
526 case MACH_MSG_TYPE_DISPOSE_SEND:
527 case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
528 /* fall thru */
529 default:
530 return MACH_MSG_TYPE_PORT_NONE;
531 }
532 }
533
534 /*
535 * Routine: ipc_object_copyin
536 * Purpose:
537 * Copyin a capability from a space.
538 * If successful, the caller gets a ref
539 * for the resulting object, unless it is IO_DEAD.
540 * Conditions:
541 * Nothing locked.
542 * Returns:
543 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
544 * KERN_INVALID_TASK The space is dead.
545 * KERN_INVALID_NAME Name doesn't exist in space.
546 * KERN_INVALID_RIGHT Name doesn't denote correct right.
547 */
548
549 kern_return_t
550 ipc_object_copyin(
551 ipc_space_t space,
552 mach_port_name_t name,
553 mach_msg_type_name_t msgt_name,
554 ipc_object_t *objectp,
555 mach_port_context_t context,
556 mach_msg_guard_flags_t *guard_flags,
557 ipc_kmsg_flags_t kmsg_flags)
558 {
559 ipc_entry_t entry;
560 ipc_port_t soright;
561 ipc_port_t release_port;
562 kern_return_t kr;
563 int assertcnt = 0;
564
565 ipc_right_copyin_flags_t irc_flags = IPC_RIGHT_COPYIN_FLAGS_DEADOK;
566 if (kmsg_flags & IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND) {
567 irc_flags |= IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND;
568 }
569
570 /*
571 * Could first try a read lock when doing
572 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
573 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
574 */
575
576 kr = ipc_right_lookup_write(space, name, &entry);
577 if (kr != KERN_SUCCESS) {
578 return kr;
579 }
580 /* space is write-locked and active */
581
582 release_port = IP_NULL;
583 kr = ipc_right_copyin(space, name, entry,
584 msgt_name, irc_flags,
585 objectp, &soright,
586 &release_port,
587 &assertcnt,
588 context,
589 guard_flags);
590 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
591 ipc_entry_dealloc(space, name, entry);
592 }
593 is_write_unlock(space);
594
595 #if IMPORTANCE_INHERITANCE
596 if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
597 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
598 }
599 #endif /* IMPORTANCE_INHERITANCE */
600
601 if (release_port != IP_NULL) {
602 ip_release(release_port);
603 }
604
605 if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) {
606 ipc_notify_port_deleted(soright, name);
607 }
608
609 return kr;
610 }
611
612 /*
613 * Routine: ipc_object_copyin_from_kernel
614 * Purpose:
615 * Copyin a naked capability from the kernel.
616 *
617 * MACH_MSG_TYPE_MOVE_RECEIVE
618 * The receiver must be ipc_space_kernel
619 * or the receive right must already be in limbo.
620 * Consumes the naked receive right.
621 * MACH_MSG_TYPE_COPY_SEND
622 * A naked send right must be supplied.
623 * The port gains a reference, and a send right
624 * if the port is still active.
625 * MACH_MSG_TYPE_MAKE_SEND
626 * The receiver must be ipc_space_kernel.
627 * The port gains a reference and a send right.
628 * MACH_MSG_TYPE_MOVE_SEND
629 * Consumes a naked send right.
630 * MACH_MSG_TYPE_MAKE_SEND_ONCE
631 * The port gains a reference and a send-once right.
632 * Receiver also be the caller of device subsystem,
633 * so no assertion.
634 * MACH_MSG_TYPE_MOVE_SEND_ONCE
635 * Consumes a naked send-once right.
636 * Conditions:
637 * Nothing locked.
638 */
639
640 void
641 ipc_object_copyin_from_kernel(
642 ipc_object_t object,
643 mach_msg_type_name_t msgt_name)
644 {
645 assert(IO_VALID(object));
646
647 switch (msgt_name) {
648 case MACH_MSG_TYPE_MOVE_RECEIVE: {
649 ipc_port_t port = ip_object_to_port(object);
650
651 ip_lock(port);
652 imq_lock(&port->ip_messages);
653 require_ip_active(port);
654 if (port->ip_destination != IP_NULL) {
655 assert(port->ip_receiver == ipc_space_kernel);
656 assert(port->ip_immovable_receive == 0);
657
658 /* relevant part of ipc_port_clear_receiver */
659 port->ip_mscount = 0;
660 port->ip_receiver_name = MACH_PORT_NULL;
661 port->ip_destination = IP_NULL;
662 }
663 imq_unlock(&port->ip_messages);
664 ip_unlock(port);
665 break;
666 }
667
668 case MACH_MSG_TYPE_COPY_SEND: {
669 ipc_port_t port = ip_object_to_port(object);
670
671 ip_lock(port);
672 if (ip_active(port)) {
673 assert(port->ip_srights > 0);
674 port->ip_srights++;
675 }
676 ip_reference(port);
677 ip_unlock(port);
678 break;
679 }
680
681 case MACH_MSG_TYPE_MAKE_SEND: {
682 ipc_port_t port = ip_object_to_port(object);
683
684 ip_lock(port);
685 if (ip_active(port)) {
686 assert(port->ip_receiver_name != MACH_PORT_NULL);
687 assert((port->ip_receiver == ipc_space_kernel) ||
688 (port->ip_receiver->is_node_id != HOST_LOCAL_NODE));
689 port->ip_mscount++;
690 }
691
692 port->ip_srights++;
693 ip_reference(port);
694 ip_unlock(port);
695 break;
696 }
697
698 case MACH_MSG_TYPE_MOVE_SEND: {
699 /* move naked send right into the message */
700 assert(ip_object_to_port(object)->ip_srights);
701 break;
702 }
703
704 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
705 ipc_port_t port = ip_object_to_port(object);
706
707 ip_lock(port);
708 if (ip_active(port)) {
709 assert(port->ip_receiver_name != MACH_PORT_NULL);
710 }
711 ipc_port_make_sonce_locked(port);
712 ip_unlock(port);
713 break;
714 }
715
716 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
717 /* move naked send-once right into the message */
718 assert(ip_object_to_port(object)->ip_sorights);
719 break;
720 }
721
722 default:
723 panic("ipc_object_copyin_from_kernel: strange rights");
724 }
725 }
726
727 /*
728 * Routine: ipc_object_destroy
729 * Purpose:
730 * Destroys a naked capability.
731 * Consumes a ref for the object.
732 *
733 * A receive right should be in limbo or in transit.
734 * Conditions:
735 * Nothing locked.
736 */
737
738 void
739 ipc_object_destroy(
740 ipc_object_t object,
741 mach_msg_type_name_t msgt_name)
742 {
743 assert(IO_VALID(object));
744 assert(io_otype(object) == IOT_PORT);
745
746 switch (msgt_name) {
747 case MACH_MSG_TYPE_PORT_SEND:
748 ipc_port_release_send(ip_object_to_port(object));
749 break;
750
751 case MACH_MSG_TYPE_PORT_SEND_ONCE:
752 ipc_notify_send_once(ip_object_to_port(object));
753 break;
754
755 case MACH_MSG_TYPE_PORT_RECEIVE:
756 ipc_port_release_receive(ip_object_to_port(object));
757 break;
758
759 default:
760 panic("ipc_object_destroy: strange rights");
761 }
762 }
763
764 /*
765 * Routine: ipc_object_destroy_dest
766 * Purpose:
767 * Destroys a naked capability for the destination of
768 * of a message. Consumes a ref for the object.
769 *
770 * Conditions:
771 * Nothing locked.
772 */
773
774 void
775 ipc_object_destroy_dest(
776 ipc_object_t object,
777 mach_msg_type_name_t msgt_name)
778 {
779 assert(IO_VALID(object));
780 assert(io_otype(object) == IOT_PORT);
781
782 switch (msgt_name) {
783 case MACH_MSG_TYPE_PORT_SEND:
784 ipc_port_release_send(ip_object_to_port(object));
785 break;
786
787 case MACH_MSG_TYPE_PORT_SEND_ONCE:
788 if (io_active(object) &&
789 !ip_full_kernel(ip_object_to_port(object))) {
790 ipc_notify_send_once(ip_object_to_port(object));
791 } else {
792 ipc_port_release_sonce(ip_object_to_port(object));
793 }
794 break;
795
796 default:
797 panic("ipc_object_destroy_dest: strange rights");
798 }
799 }
800
801 /*
802 * Routine: ipc_object_insert_send_right
803 * Purpose:
804 * Insert a send right into an object already in the space.
805 * The specified name must already point to a valid object.
806 *
807 * Note: This really is a combined copyin()/copyout(),
808 * that avoids most of the overhead of being implemented that way.
809 *
810 * This is the fastpath for mach_port_insert_right.
811 *
812 * Conditions:
813 * Nothing locked.
814 *
815 * msgt_name must be MACH_MSG_TYPE_MAKE_SEND_ONCE or
816 * MACH_MSG_TYPE_MOVE_SEND_ONCE.
817 *
818 * Returns:
819 * KERN_SUCCESS Copied out object, consumed ref.
820 * KERN_INVALID_TASK The space is dead.
821 * KERN_INVALID_NAME Name doesn't exist in space.
822 * KERN_INVALID_CAPABILITY The object is dead.
823 * KERN_RIGHT_EXISTS Space has rights under another name.
824 */
825 kern_return_t
826 ipc_object_insert_send_right(
827 ipc_space_t space,
828 mach_port_name_t name,
829 mach_msg_type_name_t msgt_name)
830 {
831 ipc_entry_bits_t bits;
832 ipc_object_t object;
833 ipc_entry_t entry;
834 kern_return_t kr;
835
836 assert(msgt_name == MACH_MSG_TYPE_MAKE_SEND ||
837 msgt_name == MACH_MSG_TYPE_COPY_SEND);
838
839 kr = ipc_right_lookup_write(space, name, &entry);
840 if (kr != KERN_SUCCESS) {
841 return kr;
842 }
843 /* space is write-locked and active */
844
845 if (!IO_VALID(entry->ie_object)) {
846 is_write_unlock(space);
847 return KERN_INVALID_CAPABILITY;
848 }
849
850 bits = entry->ie_bits;
851 object = entry->ie_object;
852
853 io_lock(object);
854 if (!io_active(object)) {
855 kr = KERN_INVALID_CAPABILITY;
856 } else if (msgt_name == MACH_MSG_TYPE_MAKE_SEND) {
857 if (bits & MACH_PORT_TYPE_RECEIVE) {
858 ipc_port_t port = ip_object_to_port(object);
859 port->ip_mscount++;
860 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
861 port->ip_srights++;
862 bits |= MACH_PORT_TYPE_SEND;
863 }
864 /* leave urefs pegged to maximum if it overflowed */
865 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
866 bits += 1; /* increment urefs */
867 }
868 entry->ie_bits = bits;
869 ipc_entry_modified(space, name, entry);
870 kr = KERN_SUCCESS;
871 } else {
872 kr = KERN_INVALID_RIGHT;
873 }
874 } else { // MACH_MSG_TYPE_COPY_SEND
875 if (bits & MACH_PORT_TYPE_SEND) {
876 /* leave urefs pegged to maximum if it overflowed */
877 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
878 entry->ie_bits = bits + 1; /* increment urefs */
879 }
880 ipc_entry_modified(space, name, entry);
881 kr = KERN_SUCCESS;
882 } else {
883 kr = KERN_INVALID_RIGHT;
884 }
885 }
886
887 io_unlock(object);
888 is_write_unlock(space);
889
890 return kr;
891 }
892
893 /*
894 * Routine: ipc_object_copyout
895 * Purpose:
896 * Copyout a capability, placing it into a space.
897 * If successful, consumes a ref for the object.
898 * Conditions:
899 * Nothing locked.
900 * Returns:
901 * KERN_SUCCESS Copied out object, consumed ref.
902 * KERN_INVALID_TASK The space is dead.
903 * KERN_INVALID_CAPABILITY The object is dead.
904 * KERN_NO_SPACE No room in space for another right.
905 * KERN_RESOURCE_SHORTAGE No memory available.
906 * KERN_UREFS_OVERFLOW Urefs limit exceeded
907 * and overflow wasn't specified.
908 */
909
910 kern_return_t
911 ipc_object_copyout(
912 ipc_space_t space,
913 ipc_object_t object,
914 mach_msg_type_name_t msgt_name,
915 mach_port_context_t *context,
916 mach_msg_guard_flags_t *guard_flags,
917 mach_port_name_t *namep)
918 {
919 struct knote *kn = current_thread()->ith_knote;
920 mach_port_name_t name;
921 ipc_entry_t entry;
922 kern_return_t kr;
923
924 assert(IO_VALID(object));
925 assert(io_otype(object) == IOT_PORT);
926
927 if (ITH_KNOTE_VALID(kn, msgt_name)) {
928 filt_machport_turnstile_prepare_lazily(kn,
929 msgt_name, ip_object_to_port(object));
930 }
931
932 is_write_lock(space);
933
934 for (;;) {
935 if (!is_active(space)) {
936 is_write_unlock(space);
937 return KERN_INVALID_TASK;
938 }
939
940 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
941 ipc_right_reverse(space, object, &name, &entry)) {
942 /* object is locked and active */
943
944 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
945 break;
946 }
947
948
949 name = CAST_MACH_PORT_TO_NAME(object);
950 kr = ipc_entry_get(space, &name, &entry);
951 if (kr != KERN_SUCCESS) {
952 /* unlocks/locks space, so must start again */
953
954 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
955 if (kr != KERN_SUCCESS) {
956 return kr; /* space is unlocked */
957 }
958 continue;
959 }
960
961 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
962 assert(entry->ie_object == IO_NULL);
963
964 io_lock(object);
965 if (!io_active(object)) {
966 io_unlock(object);
967 ipc_entry_dealloc(space, name, entry);
968 is_write_unlock(space);
969 return KERN_INVALID_CAPABILITY;
970 }
971
972 /* Don't actually copyout rights we aren't allowed to */
973 if (!ip_label_check(space, ip_object_to_port(object), msgt_name)) {
974 io_unlock(object);
975 ipc_entry_dealloc(space, name, entry);
976 is_write_unlock(space);
977
978 switch (msgt_name) {
979 case MACH_MSG_TYPE_PORT_SEND_ONCE:
980 ipc_port_release_sonce(ip_object_to_port(object));
981 break;
982 case MACH_MSG_TYPE_PORT_SEND:
983 ipc_port_release_send(ip_object_to_port(object));
984 break;
985 default:
986 /*
987 * We don't allow labeling of "kobjects" with receive
988 * rights at user-space or port-sets. So, if we get this far,
989 * something went VERY wrong.
990 */
991 panic("ipc_object_copyout: bad port label check failure");
992 }
993 return KERN_INVALID_CAPABILITY;
994 }
995
996 entry->ie_object = object;
997 break;
998 }
999
1000 /* space is write-locked and active, object is locked and active */
1001
1002 kr = ipc_right_copyout(space, name, entry,
1003 msgt_name, context, guard_flags, object);
1004
1005 /* object is unlocked */
1006 is_write_unlock(space);
1007
1008 if (kr == KERN_SUCCESS) {
1009 *namep = name;
1010 }
1011 return kr;
1012 }
1013
1014 /*
1015 * Routine: ipc_object_copyout_name
1016 * Purpose:
1017 * Copyout a capability, placing it into a space.
1018 * The specified name is used for the capability.
1019 * If successful, consumes a ref for the object.
1020 * Conditions:
1021 * Nothing locked.
1022 * Returns:
1023 * KERN_SUCCESS Copied out object, consumed ref.
1024 * KERN_INVALID_TASK The space is dead.
1025 * KERN_INVALID_CAPABILITY The object is dead.
1026 * KERN_RESOURCE_SHORTAGE No memory available.
1027 * KERN_UREFS_OVERFLOW Urefs limit exceeded
1028 * and overflow wasn't specified.
1029 * KERN_RIGHT_EXISTS Space has rights under another name.
1030 * KERN_NAME_EXISTS Name is already used.
1031 */
1032
1033 kern_return_t
1034 ipc_object_copyout_name(
1035 ipc_space_t space,
1036 ipc_object_t object,
1037 mach_msg_type_name_t msgt_name,
1038 mach_port_name_t name)
1039 {
1040 mach_port_name_t oname;
1041 ipc_entry_t oentry;
1042 ipc_entry_t entry;
1043 kern_return_t kr;
1044
1045 #if IMPORTANCE_INHERITANCE
1046 int assertcnt = 0;
1047 ipc_importance_task_t task_imp = IIT_NULL;
1048 #endif /* IMPORTANCE_INHERITANCE */
1049
1050 assert(IO_VALID(object));
1051 assert(io_otype(object) == IOT_PORT);
1052
1053 kr = ipc_entry_alloc_name(space, name, &entry);
1054 if (kr != KERN_SUCCESS) {
1055 return kr;
1056 }
1057 /* space is write-locked and active */
1058
1059 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1060 ipc_right_reverse(space, object, &oname, &oentry)) {
1061 /* object is locked and active */
1062
1063 if (name != oname) {
1064 io_unlock(object);
1065
1066 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
1067 ipc_entry_dealloc(space, name, entry);
1068 }
1069
1070 is_write_unlock(space);
1071 return KERN_RIGHT_EXISTS;
1072 }
1073
1074 assert(entry == oentry);
1075 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
1076 } else {
1077 if (ipc_right_inuse(space, name, entry)) {
1078 return KERN_NAME_EXISTS;
1079 }
1080
1081 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
1082 assert(entry->ie_object == IO_NULL);
1083
1084 io_lock(object);
1085 if (!io_active(object)) {
1086 io_unlock(object);
1087 ipc_entry_dealloc(space, name, entry);
1088 is_write_unlock(space);
1089 return KERN_INVALID_CAPABILITY;
1090 }
1091
1092 /* Don't actually copyout rights we aren't allowed to */
1093 if (!ip_label_check(space, ip_object_to_port(object), msgt_name)) {
1094 io_unlock(object);
1095 ipc_entry_dealloc(space, name, entry);
1096 is_write_unlock(space);
1097
1098 switch (msgt_name) {
1099 case MACH_MSG_TYPE_PORT_SEND_ONCE:
1100 ipc_port_release_sonce(ip_object_to_port(object));
1101 break;
1102 case MACH_MSG_TYPE_PORT_SEND:
1103 ipc_port_release_send(ip_object_to_port(object));
1104 break;
1105 default:
1106 panic("ipc_object_copyout_name: bad port label check failure");
1107 }
1108 return KERN_INVALID_CAPABILITY;
1109 }
1110
1111 entry->ie_object = object;
1112 }
1113
1114 /* space is write-locked and active, object is locked and active */
1115
1116 #if IMPORTANCE_INHERITANCE
1117 /*
1118 * We are slamming a receive right into the space, without
1119 * first having been enqueued on a port destined there. So,
1120 * we have to arrange to boost the task appropriately if this
1121 * port has assertions (and the task wants them).
1122 */
1123 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
1124 ipc_port_t port = ip_object_to_port(object);
1125
1126 if (space->is_task != TASK_NULL) {
1127 task_imp = space->is_task->task_imp_base;
1128 if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1129 assertcnt = port->ip_impcount;
1130 ipc_importance_task_reference(task_imp);
1131 } else {
1132 task_imp = IIT_NULL;
1133 }
1134 }
1135
1136 /* take port out of limbo */
1137 assert(port->ip_tempowner != 0);
1138 port->ip_tempowner = 0;
1139 }
1140
1141 #endif /* IMPORTANCE_INHERITANCE */
1142
1143 kr = ipc_right_copyout(space, name, entry,
1144 msgt_name, NULL, NULL, object);
1145
1146 /* object is unlocked */
1147 is_write_unlock(space);
1148
1149 #if IMPORTANCE_INHERITANCE
1150 /*
1151 * Add the assertions to the task that we captured before
1152 */
1153 if (task_imp != IIT_NULL) {
1154 ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
1155 ipc_importance_task_release(task_imp);
1156 }
1157 #endif /* IMPORTANCE_INHERITANCE */
1158
1159 return kr;
1160 }
1161
1162 /*
1163 * Routine: ipc_object_copyout_dest
1164 * Purpose:
1165 * Translates/consumes the destination right of a message.
1166 * This is unlike normal copyout because the right is consumed
1167 * in a funny way instead of being given to the receiving space.
1168 * The receiver gets his name for the port, if he has receive
1169 * rights, otherwise MACH_PORT_NULL.
1170 * Conditions:
1171 * The object is locked and active. Nothing else locked.
1172 * The object is unlocked and loses a reference.
1173 */
1174
1175 void
1176 ipc_object_copyout_dest(
1177 ipc_space_t space,
1178 ipc_object_t object,
1179 mach_msg_type_name_t msgt_name,
1180 mach_port_name_t *namep)
1181 {
1182 mach_port_name_t name;
1183
1184 assert(IO_VALID(object));
1185 assert(io_active(object));
1186
1187 /*
1188 * If the space is the receiver/owner of the object,
1189 * then we quietly consume the right and return
1190 * the space's name for the object. Otherwise
1191 * we destroy the right and return MACH_PORT_NULL.
1192 */
1193
1194 switch (msgt_name) {
1195 case MACH_MSG_TYPE_PORT_SEND: {
1196 ipc_port_t port = ip_object_to_port(object);
1197 ipc_port_t nsrequest = IP_NULL;
1198 mach_port_mscount_t mscount;
1199
1200 if (port->ip_receiver == space) {
1201 name = port->ip_receiver_name;
1202 } else {
1203 name = MACH_PORT_NULL;
1204 }
1205
1206 assert(port->ip_srights > 0);
1207 if (--port->ip_srights == 0 &&
1208 port->ip_nsrequest != IP_NULL) {
1209 nsrequest = port->ip_nsrequest;
1210 port->ip_nsrequest = IP_NULL;
1211 mscount = port->ip_mscount;
1212 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1213 /* port unlocked */
1214 ipc_notify_no_senders(nsrequest, mscount);
1215 } else {
1216 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1217 /* port unlocked */
1218 }
1219
1220 ip_release(port);
1221 break;
1222 }
1223
1224 case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1225 ipc_port_t port = ip_object_to_port(object);
1226
1227 assert(port->ip_sorights > 0);
1228
1229 if (port->ip_receiver == space) {
1230 /* quietly consume the send-once right */
1231
1232 port->ip_sorights--;
1233 name = port->ip_receiver_name;
1234 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1235 /* port unlocked */
1236 ip_release(port);
1237 } else {
1238 /*
1239 * A very bizarre case. The message
1240 * was received, but before this copyout
1241 * happened the space lost receive rights.
1242 * We can't quietly consume the soright
1243 * out from underneath some other task,
1244 * so generate a send-once notification.
1245 */
1246
1247 ip_unlock(port);
1248
1249 ipc_notify_send_once(port);
1250 name = MACH_PORT_NULL;
1251 }
1252
1253 break;
1254 }
1255
1256 default:
1257 panic("ipc_object_copyout_dest: strange rights");
1258 name = MACH_PORT_DEAD;
1259 }
1260
1261 *namep = name;
1262 }
1263
1264 /*
1265 * Routine: io_lock
1266 * Purpose:
1267 * Validate, then acquire a lock on an ipc object
1268 */
1269
1270 void
1271 io_lock(ipc_object_t io)
1272 {
1273 ipc_object_validate(io);
1274 lck_spin_lock_grp(&(io)->io_lock_data, &ipc_lck_grp);
1275 }
1276
1277 /*
1278 * Routine: io_lock_try
1279 * Purpose:
1280 * Validate, then try to acquire a lock on an object,
1281 * fail if there is an existing busy lock
1282 */
1283
1284 boolean_t
1285 io_lock_try(ipc_object_t io)
1286 {
1287 ipc_object_validate(io);
1288 return lck_spin_try_lock_grp(&(io)->io_lock_data, &ipc_lck_grp);
1289 }
1290
1291 /*
1292 * Check whether the object is a port if so, free it. But
1293 * keep track of that fact.
1294 */
1295 void
1296 io_free(
1297 unsigned int otype,
1298 ipc_object_t object)
1299 {
1300 if (otype == IOT_PORT) {
1301 ipc_port_finalize(ip_object_to_port(object));
1302 }
1303 io_lock_destroy(object);
1304 zfree(ipc_object_zones[otype], object);
1305 }