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