]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_object.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_object.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 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.
0a7de745 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.
0a7de745 17 *
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
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.
0a7de745 41 *
1c79356b
A
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.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
2d21ac55
A
56/*
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005-2006 SPARTA, Inc.
62 */
1c79356b
A
63/*
64 */
65/*
66 * File: ipc/ipc_object.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Functions to manipulate IPC objects.
71 */
72
91447636 73#include <mach/mach_types.h>
1c79356b
A
74#include <mach/boolean.h>
75#include <mach/kern_return.h>
76#include <mach/port.h>
77#include <mach/message.h>
91447636
A
78
79#include <kern/kern_types.h>
1c79356b 80#include <kern/misc_protos.h>
2d21ac55 81#include <kern/ipc_kobject.h>
91447636
A
82
83#include <ipc/ipc_types.h>
fe8ab488 84#include <ipc/ipc_importance.h>
1c79356b
A
85#include <ipc/port.h>
86#include <ipc/ipc_space.h>
87#include <ipc/ipc_entry.h>
88#include <ipc/ipc_object.h>
89#include <ipc/ipc_hash.h>
90#include <ipc/ipc_right.h>
91#include <ipc/ipc_notify.h>
6d2010ae 92#include <ipc/ipc_port.h>
1c79356b 93#include <ipc/ipc_pset.h>
2d21ac55
A
94
95#include <security/mac_mach_internal.h>
1c79356b 96
f427ee49
A
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);
1c79356b
A
107
108/*
109 * Routine: ipc_object_reference
110 * Purpose:
111 * Take a reference to an object.
112 */
113
114void
115ipc_object_reference(
0a7de745 116 ipc_object_t object)
1c79356b 117{
1c79356b 118 io_reference(object);
1c79356b
A
119}
120
121/*
122 * Routine: ipc_object_release
123 * Purpose:
124 * Release a reference to an object.
125 */
126
127void
128ipc_object_release(
0a7de745 129 ipc_object_t object)
1c79356b 130{
1c79356b 131 io_release(object);
1c79356b
A
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
cb323159 140 * is returned active and locked. The caller doesn't get a ref.
1c79356b
A
141 * Returns:
142 * KERN_SUCCESS Object returned locked.
143 * KERN_INVALID_TASK The space is dead.
00867663
A
144 * KERN_INVALID_NAME The name doesn't denote a right
145 * KERN_INVALID_RIGHT Name doesn't denote the correct right
1c79356b 146 */
1c79356b
A
147kern_return_t
148ipc_object_translate(
0a7de745
A
149 ipc_space_t space,
150 mach_port_name_t name,
151 mach_port_right_t right,
152 ipc_object_t *objectp)
1c79356b
A
153{
154 ipc_entry_t entry;
155 ipc_object_t object;
156 kern_return_t kr;
157
cb323159
A
158 if (!MACH_PORT_RIGHT_VALID_TRANSLATE(right)) {
159 return KERN_INVALID_RIGHT;
160 }
161
1c79356b 162 kr = ipc_right_lookup_read(space, name, &entry);
0a7de745 163 if (kr != KERN_SUCCESS) {
1c79356b 164 return kr;
0a7de745 165 }
1c79356b
A
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
cb323159
A
179 if (!io_active(object)) {
180 io_unlock(object);
181 return KERN_INVALID_NAME;
182 }
183
1c79356b
A
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(
0a7de745
A
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)
1c79356b
A
211{
212 ipc_entry_t entry1;
213 ipc_entry_t entry2;
cb323159 214 ipc_object_t object1, object2;
1c79356b 215 kern_return_t kr;
cb323159 216 boolean_t doguard = TRUE;
1c79356b
A
217
218 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
0a7de745 219 if (kr != KERN_SUCCESS) {
1c79356b 220 return kr;
0a7de745 221 }
1c79356b
A
222 /* space is read-locked and active */
223
224 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
cb323159
A
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 }
1c79356b 230 is_read_unlock(space);
cb323159
A
231 if (doguard) {
232 mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT);
233 }
1c79356b
A
234 return KERN_INVALID_RIGHT;
235 }
236
237 if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
cb323159
A
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 }
1c79356b 243 is_read_unlock(space);
cb323159
A
244 if (doguard) {
245 mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT);
246 }
1c79356b
A
247 return KERN_INVALID_RIGHT;
248 }
249
cb323159
A
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 }
1c79356b 258
cb323159
A
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;
1c79356b
A
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(
0a7de745
A
291 ipc_space_t space,
292 mach_port_name_t *namep)
1c79356b
A
293{
294 ipc_entry_t entry;
295 kern_return_t kr;
296
1c79356b 297 kr = ipc_entry_alloc(space, namep, &entry);
0a7de745 298 if (kr != KERN_SUCCESS) {
1c79356b 299 return kr;
0a7de745 300 }
1c79356b
A
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;
316670eb 307 ipc_entry_modified(space, *namep, entry);
1c79356b
A
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(
0a7de745
A
327 ipc_space_t space,
328 mach_port_name_t name)
1c79356b
A
329{
330 ipc_entry_t entry;
331 kern_return_t kr;
332
1c79356b 333 kr = ipc_entry_alloc_name(space, name, &entry);
0a7de745 334 if (kr != KERN_SUCCESS) {
1c79356b 335 return kr;
0a7de745 336 }
1c79356b
A
337 /* space is write-locked */
338
c3c9b80d
A
339 if (ipc_right_inuse(entry)) {
340 is_write_unlock(space);
1c79356b 341 return KERN_NAME_EXISTS;
0a7de745 342 }
1c79356b
A
343
344 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
345
346 assert(entry->ie_object == IO_NULL);
347 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
316670eb 348 ipc_entry_modified(space, name, entry);
1c79356b
A
349 is_write_unlock(space);
350 return KERN_SUCCESS;
351}
352
353/*
354 * Routine: ipc_object_alloc
355 * Purpose:
356 * Allocate an object.
357 * Conditions:
358 * Nothing locked. If successful, the object is returned locked.
0a7de745 359 * The space is write locked on successful return.
1c79356b
A
360 * The caller doesn't get a reference for the object.
361 * Returns:
362 * KERN_SUCCESS The object is allocated.
363 * KERN_INVALID_TASK The space is dead.
364 * KERN_NO_SPACE No room for an entry in the space.
365 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
366 */
367
368kern_return_t
369ipc_object_alloc(
0a7de745
A
370 ipc_space_t space,
371 ipc_object_type_t otype,
372 mach_port_type_t type,
373 mach_port_urefs_t urefs,
374 mach_port_name_t *namep,
375 ipc_object_t *objectp)
1c79356b
A
376{
377 ipc_object_t object;
378 ipc_entry_t entry;
379 kern_return_t kr;
380
381 assert(otype < IOT_NUMBER);
382 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
383 assert(type != MACH_PORT_TYPE_NONE);
384 assert(urefs <= MACH_PORT_UREFS_MAX);
385
c3c9b80d 386 object = io_alloc(otype, Z_WAITOK | Z_ZERO);
0a7de745 387 if (object == IO_NULL) {
1c79356b 388 return KERN_RESOURCE_SHORTAGE;
0a7de745 389 }
1c79356b 390
1c79356b 391 io_lock_init(object);
b0d623f7 392 *namep = CAST_MACH_PORT_TO_NAME(object);
1c79356b
A
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;
316670eb 402 ipc_entry_modified(space, *namep, entry);
1c79356b 403
cb323159 404 object->io_bits = io_makebits(TRUE, otype, 0);
1c79356b 405 io_lock(object);
1c79356b
A
406
407 object->io_references = 1; /* for entry, not caller */
1c79356b
A
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
427kern_return_t
428ipc_object_alloc_name(
0a7de745
A
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)
1c79356b
A
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
c3c9b80d 445 object = io_alloc(otype, Z_WAITOK | Z_ZERO);
0a7de745 446 if (object == IO_NULL) {
1c79356b 447 return KERN_RESOURCE_SHORTAGE;
0a7de745 448 }
1c79356b 449
1c79356b
A
450 io_lock_init(object);
451 kr = ipc_entry_alloc_name(space, name, &entry);
452 if (kr != KERN_SUCCESS) {
453 io_free(otype, object);
454 return kr;
455 }
456 /* space is write-locked */
457
c3c9b80d
A
458 if (ipc_right_inuse(entry)) {
459 is_write_unlock(space);
1c79356b
A
460 io_free(otype, object);
461 return KERN_NAME_EXISTS;
462 }
463
464 entry->ie_bits |= type | urefs;
465 entry->ie_object = object;
316670eb 466 ipc_entry_modified(space, name, entry);
1c79356b 467
cb323159
A
468 object->io_bits = io_makebits(TRUE, otype, 0);
469
1c79356b
A
470 io_lock(object);
471 is_write_unlock(space);
472
473 object->io_references = 1; /* for entry, not caller */
1c79356b
A
474
475 *objectp = object;
476 return KERN_SUCCESS;
477}
478
cb323159
A
479/* Routine: ipc_object_validate
480 * Purpose:
481 * Validates an ipc port or port set as belonging to the correct
482 * zone.
483 */
484
485void
486ipc_object_validate(
487 ipc_object_t object)
488{
f427ee49
A
489 if (io_otype(object) != IOT_PORT_SET) {
490 zone_id_require(ZONE_ID_IPC_PORT,
491 sizeof(struct ipc_port), object);
492 } else {
493 zone_id_require(ZONE_ID_IPC_PORT_SET,
494 sizeof(struct ipc_pset), object);
495 }
cb323159
A
496}
497
1c79356b
A
498/*
499 * Routine: ipc_object_copyin_type
500 * Purpose:
501 * Convert a send type name to a received type name.
502 */
503
504mach_msg_type_name_t
505ipc_object_copyin_type(
0a7de745 506 mach_msg_type_name_t msgt_name)
1c79356b
A
507{
508 switch (msgt_name) {
0a7de745 509 case MACH_MSG_TYPE_MOVE_RECEIVE:
1c79356b
A
510 return MACH_MSG_TYPE_PORT_RECEIVE;
511
0a7de745
A
512 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
513 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
1c79356b
A
514 return MACH_MSG_TYPE_PORT_SEND_ONCE;
515
0a7de745
A
516 case MACH_MSG_TYPE_MOVE_SEND:
517 case MACH_MSG_TYPE_MAKE_SEND:
518 case MACH_MSG_TYPE_COPY_SEND:
1c79356b
A
519 return MACH_MSG_TYPE_PORT_SEND;
520
0a7de745
A
521 case MACH_MSG_TYPE_DISPOSE_RECEIVE:
522 case MACH_MSG_TYPE_DISPOSE_SEND:
523 case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
524 /* fall thru */
525 default:
1c79356b
A
526 return MACH_MSG_TYPE_PORT_NONE;
527 }
528}
529
530/*
531 * Routine: ipc_object_copyin
532 * Purpose:
533 * Copyin a capability from a space.
534 * If successful, the caller gets a ref
535 * for the resulting object, unless it is IO_DEAD.
536 * Conditions:
537 * Nothing locked.
538 * Returns:
539 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
540 * KERN_INVALID_TASK The space is dead.
541 * KERN_INVALID_NAME Name doesn't exist in space.
542 * KERN_INVALID_RIGHT Name doesn't denote correct right.
543 */
544
545kern_return_t
546ipc_object_copyin(
c3c9b80d
A
547 ipc_space_t space,
548 mach_port_name_t name,
549 mach_msg_type_name_t msgt_name,
550 ipc_object_t *objectp,
551 mach_port_context_t context,
552 mach_msg_guard_flags_t *guard_flags,
553 ipc_object_copyin_flags_t copyin_flags)
1c79356b
A
554{
555 ipc_entry_t entry;
556 ipc_port_t soright;
316670eb 557 ipc_port_t release_port;
1c79356b 558 kern_return_t kr;
39236c6e 559 int assertcnt = 0;
1c79356b 560
c3c9b80d
A
561 ipc_object_copyin_flags_t irc_flags = IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND |
562 IPC_OBJECT_COPYIN_FLAGS_SOFT_FAIL_IMMOVABLE_SEND;
563 irc_flags = (copyin_flags & irc_flags) | IPC_OBJECT_COPYIN_FLAGS_DEADOK;
1c79356b
A
564 /*
565 * Could first try a read lock when doing
566 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
567 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
568 */
569
570 kr = ipc_right_lookup_write(space, name, &entry);
0a7de745 571 if (kr != KERN_SUCCESS) {
1c79356b 572 return kr;
0a7de745 573 }
1c79356b
A
574 /* space is write-locked and active */
575
316670eb 576 release_port = IP_NULL;
1c79356b 577 kr = ipc_right_copyin(space, name, entry,
cb323159 578 msgt_name, irc_flags,
0a7de745
A
579 objectp, &soright,
580 &release_port,
cb323159
A
581 &assertcnt,
582 context,
583 guard_flags);
0a7de745 584 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
1c79356b 585 ipc_entry_dealloc(space, name, entry);
0a7de745 586 }
1c79356b
A
587 is_write_unlock(space);
588
39236c6e 589#if IMPORTANCE_INHERITANCE
fe8ab488
A
590 if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
591 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
39236c6e
A
592 }
593#endif /* IMPORTANCE_INHERITANCE */
594
0a7de745 595 if (release_port != IP_NULL) {
316670eb 596 ip_release(release_port);
0a7de745 597 }
316670eb 598
0a7de745 599 if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) {
1c79356b 600 ipc_notify_port_deleted(soright, name);
0a7de745 601 }
1c79356b
A
602
603 return kr;
604}
605
606/*
607 * Routine: ipc_object_copyin_from_kernel
608 * Purpose:
609 * Copyin a naked capability from the kernel.
610 *
611 * MACH_MSG_TYPE_MOVE_RECEIVE
55e303ae
A
612 * The receiver must be ipc_space_kernel
613 * or the receive right must already be in limbo.
1c79356b
A
614 * Consumes the naked receive right.
615 * MACH_MSG_TYPE_COPY_SEND
616 * A naked send right must be supplied.
617 * The port gains a reference, and a send right
618 * if the port is still active.
619 * MACH_MSG_TYPE_MAKE_SEND
620 * The receiver must be ipc_space_kernel.
621 * The port gains a reference and a send right.
622 * MACH_MSG_TYPE_MOVE_SEND
623 * Consumes a naked send right.
624 * MACH_MSG_TYPE_MAKE_SEND_ONCE
625 * The port gains a reference and a send-once right.
626 * Receiver also be the caller of device subsystem,
627 * so no assertion.
628 * MACH_MSG_TYPE_MOVE_SEND_ONCE
629 * Consumes a naked send-once right.
630 * Conditions:
631 * Nothing locked.
632 */
633
634void
635ipc_object_copyin_from_kernel(
0a7de745
A
636 ipc_object_t object,
637 mach_msg_type_name_t msgt_name)
1c79356b
A
638{
639 assert(IO_VALID(object));
640
641 switch (msgt_name) {
0a7de745 642 case MACH_MSG_TYPE_MOVE_RECEIVE: {
cb323159 643 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
644
645 ip_lock(port);
d9a64523 646 imq_lock(&port->ip_messages);
cb323159 647 require_ip_active(port);
55e303ae
A
648 if (port->ip_destination != IP_NULL) {
649 assert(port->ip_receiver == ipc_space_kernel);
cb323159 650 assert(port->ip_immovable_receive == 0);
1c79356b 651
55e303ae 652 /* relevant part of ipc_port_clear_receiver */
cb323159 653 port->ip_mscount = 0;
55e303ae
A
654 port->ip_receiver_name = MACH_PORT_NULL;
655 port->ip_destination = IP_NULL;
656 }
d9a64523 657 imq_unlock(&port->ip_messages);
1c79356b
A
658 ip_unlock(port);
659 break;
0a7de745 660 }
1c79356b 661
0a7de745 662 case MACH_MSG_TYPE_COPY_SEND: {
cb323159 663 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
664
665 ip_lock(port);
666 if (ip_active(port)) {
667 assert(port->ip_srights > 0);
1c79356b 668 }
c3c9b80d 669 port->ip_srights++;
1c79356b
A
670 ip_reference(port);
671 ip_unlock(port);
672 break;
0a7de745 673 }
1c79356b 674
0a7de745 675 case MACH_MSG_TYPE_MAKE_SEND: {
cb323159 676 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
677
678 ip_lock(port);
39236c6e
A
679 if (ip_active(port)) {
680 assert(port->ip_receiver_name != MACH_PORT_NULL);
39037602 681 assert((port->ip_receiver == ipc_space_kernel) ||
0a7de745 682 (port->ip_receiver->is_node_id != HOST_LOCAL_NODE));
39236c6e
A
683 port->ip_mscount++;
684 }
1c79356b 685
1c79356b 686 port->ip_srights++;
39236c6e 687 ip_reference(port);
1c79356b
A
688 ip_unlock(port);
689 break;
0a7de745 690 }
1c79356b 691
0a7de745 692 case MACH_MSG_TYPE_MOVE_SEND: {
1c79356b 693 /* move naked send right into the message */
cb323159 694 assert(ip_object_to_port(object)->ip_srights);
1c79356b 695 break;
0a7de745 696 }
1c79356b 697
0a7de745 698 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
cb323159 699 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
700
701 ip_lock(port);
39236c6e
A
702 if (ip_active(port)) {
703 assert(port->ip_receiver_name != MACH_PORT_NULL);
704 }
cb323159 705 ipc_port_make_sonce_locked(port);
1c79356b
A
706 ip_unlock(port);
707 break;
0a7de745 708 }
1c79356b 709
0a7de745 710 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
1c79356b 711 /* move naked send-once right into the message */
cb323159 712 assert(ip_object_to_port(object)->ip_sorights);
1c79356b 713 break;
0a7de745 714 }
1c79356b 715
0a7de745 716 default:
1c79356b
A
717 panic("ipc_object_copyin_from_kernel: strange rights");
718 }
719}
720
721/*
722 * Routine: ipc_object_destroy
723 * Purpose:
724 * Destroys a naked capability.
725 * Consumes a ref for the object.
726 *
727 * A receive right should be in limbo or in transit.
728 * Conditions:
729 * Nothing locked.
730 */
731
732void
733ipc_object_destroy(
0a7de745
A
734 ipc_object_t object,
735 mach_msg_type_name_t msgt_name)
1c79356b
A
736{
737 assert(IO_VALID(object));
738 assert(io_otype(object) == IOT_PORT);
739
740 switch (msgt_name) {
0a7de745 741 case MACH_MSG_TYPE_PORT_SEND:
cb323159 742 ipc_port_release_send(ip_object_to_port(object));
1c79356b
A
743 break;
744
0a7de745 745 case MACH_MSG_TYPE_PORT_SEND_ONCE:
cb323159 746 ipc_notify_send_once(ip_object_to_port(object));
1c79356b
A
747 break;
748
0a7de745 749 case MACH_MSG_TYPE_PORT_RECEIVE:
cb323159 750 ipc_port_release_receive(ip_object_to_port(object));
1c79356b
A
751 break;
752
0a7de745 753 default:
1c79356b
A
754 panic("ipc_object_destroy: strange rights");
755 }
756}
757
6d2010ae
A
758/*
759 * Routine: ipc_object_destroy_dest
760 * Purpose:
761 * Destroys a naked capability for the destination of
762 * of a message. Consumes a ref for the object.
763 *
764 * Conditions:
765 * Nothing locked.
766 */
767
768void
769ipc_object_destroy_dest(
0a7de745
A
770 ipc_object_t object,
771 mach_msg_type_name_t msgt_name)
6d2010ae
A
772{
773 assert(IO_VALID(object));
774 assert(io_otype(object) == IOT_PORT);
775
776 switch (msgt_name) {
0a7de745 777 case MACH_MSG_TYPE_PORT_SEND:
cb323159 778 ipc_port_release_send(ip_object_to_port(object));
6d2010ae
A
779 break;
780
0a7de745
A
781 case MACH_MSG_TYPE_PORT_SEND_ONCE:
782 if (io_active(object) &&
cb323159
A
783 !ip_full_kernel(ip_object_to_port(object))) {
784 ipc_notify_send_once(ip_object_to_port(object));
0a7de745 785 } else {
cb323159 786 ipc_port_release_sonce(ip_object_to_port(object));
0a7de745 787 }
6d2010ae
A
788 break;
789
0a7de745 790 default:
6d2010ae
A
791 panic("ipc_object_destroy_dest: strange rights");
792 }
793}
794
cb323159
A
795/*
796 * Routine: ipc_object_insert_send_right
797 * Purpose:
798 * Insert a send right into an object already in the space.
799 * The specified name must already point to a valid object.
800 *
801 * Note: This really is a combined copyin()/copyout(),
802 * that avoids most of the overhead of being implemented that way.
803 *
804 * This is the fastpath for mach_port_insert_right.
805 *
806 * Conditions:
807 * Nothing locked.
808 *
809 * msgt_name must be MACH_MSG_TYPE_MAKE_SEND_ONCE or
810 * MACH_MSG_TYPE_MOVE_SEND_ONCE.
811 *
812 * Returns:
813 * KERN_SUCCESS Copied out object, consumed ref.
814 * KERN_INVALID_TASK The space is dead.
815 * KERN_INVALID_NAME Name doesn't exist in space.
816 * KERN_INVALID_CAPABILITY The object is dead.
817 * KERN_RIGHT_EXISTS Space has rights under another name.
818 */
819kern_return_t
820ipc_object_insert_send_right(
821 ipc_space_t space,
822 mach_port_name_t name,
823 mach_msg_type_name_t msgt_name)
824{
825 ipc_entry_bits_t bits;
826 ipc_object_t object;
827 ipc_entry_t entry;
828 kern_return_t kr;
829
830 assert(msgt_name == MACH_MSG_TYPE_MAKE_SEND ||
831 msgt_name == MACH_MSG_TYPE_COPY_SEND);
832
833 kr = ipc_right_lookup_write(space, name, &entry);
834 if (kr != KERN_SUCCESS) {
835 return kr;
836 }
837 /* space is write-locked and active */
838
839 if (!IO_VALID(entry->ie_object)) {
840 is_write_unlock(space);
841 return KERN_INVALID_CAPABILITY;
842 }
843
844 bits = entry->ie_bits;
845 object = entry->ie_object;
846
847 io_lock(object);
848 if (!io_active(object)) {
849 kr = KERN_INVALID_CAPABILITY;
850 } else if (msgt_name == MACH_MSG_TYPE_MAKE_SEND) {
851 if (bits & MACH_PORT_TYPE_RECEIVE) {
852 ipc_port_t port = ip_object_to_port(object);
853 port->ip_mscount++;
854 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
855 port->ip_srights++;
856 bits |= MACH_PORT_TYPE_SEND;
857 }
858 /* leave urefs pegged to maximum if it overflowed */
859 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
860 bits += 1; /* increment urefs */
861 }
862 entry->ie_bits = bits;
863 ipc_entry_modified(space, name, entry);
864 kr = KERN_SUCCESS;
865 } else {
866 kr = KERN_INVALID_RIGHT;
867 }
868 } else { // MACH_MSG_TYPE_COPY_SEND
869 if (bits & MACH_PORT_TYPE_SEND) {
870 /* leave urefs pegged to maximum if it overflowed */
871 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
872 entry->ie_bits = bits + 1; /* increment urefs */
873 }
874 ipc_entry_modified(space, name, entry);
875 kr = KERN_SUCCESS;
876 } else {
877 kr = KERN_INVALID_RIGHT;
878 }
879 }
880
881 io_unlock(object);
882 is_write_unlock(space);
883
884 return kr;
885}
886
1c79356b
A
887/*
888 * Routine: ipc_object_copyout
889 * Purpose:
890 * Copyout a capability, placing it into a space.
c3c9b80d 891 * Always consumes a ref for the object.
1c79356b
A
892 * Conditions:
893 * Nothing locked.
894 * Returns:
895 * KERN_SUCCESS Copied out object, consumed ref.
896 * KERN_INVALID_TASK The space is dead.
897 * KERN_INVALID_CAPABILITY The object is dead.
898 * KERN_NO_SPACE No room in space for another right.
899 * KERN_RESOURCE_SHORTAGE No memory available.
900 * KERN_UREFS_OVERFLOW Urefs limit exceeded
901 * and overflow wasn't specified.
902 */
903
904kern_return_t
905ipc_object_copyout(
0a7de745
A
906 ipc_space_t space,
907 ipc_object_t object,
908 mach_msg_type_name_t msgt_name,
c3c9b80d 909 ipc_object_copyout_flags_t flags,
cb323159
A
910 mach_port_context_t *context,
911 mach_msg_guard_flags_t *guard_flags,
0a7de745 912 mach_port_name_t *namep)
1c79356b 913{
d9a64523 914 struct knote *kn = current_thread()->ith_knote;
1c79356b 915 mach_port_name_t name;
c3c9b80d 916 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
917 ipc_entry_t entry;
918 kern_return_t kr;
919
920 assert(IO_VALID(object));
921 assert(io_otype(object) == IOT_PORT);
922
d9a64523 923 if (ITH_KNOTE_VALID(kn, msgt_name)) {
c3c9b80d 924 filt_machport_turnstile_prepare_lazily(kn, msgt_name, port);
d9a64523
A
925 }
926
1c79356b
A
927 is_write_lock(space);
928
929 for (;;) {
c3c9b80d
A
930 ipc_port_t port_subst = IP_NULL;
931
316670eb 932 if (!is_active(space)) {
1c79356b 933 is_write_unlock(space);
c3c9b80d
A
934 kr = KERN_INVALID_TASK;
935 goto out;
1c79356b
A
936 }
937
c3c9b80d 938 kr = ipc_entries_hold(space, 1);
1c79356b
A
939 if (kr != KERN_SUCCESS) {
940 /* unlocks/locks space, so must start again */
941
942 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
0a7de745 943 if (kr != KERN_SUCCESS) {
c3c9b80d
A
944 /* space is unlocked */
945 goto out;
0a7de745 946 }
1c79356b
A
947 continue;
948 }
949
1c79356b
A
950 io_lock(object);
951 if (!io_active(object)) {
952 io_unlock(object);
1c79356b 953 is_write_unlock(space);
c3c9b80d
A
954 kr = KERN_INVALID_CAPABILITY;
955 goto out;
1c79356b
A
956 }
957
ea3f0419 958 /* Don't actually copyout rights we aren't allowed to */
c3c9b80d 959 if (!ip_label_check(space, port, msgt_name, &flags, &port_subst)) {
ea3f0419 960 io_unlock(object);
ea3f0419 961 is_write_unlock(space);
c3c9b80d
A
962 assert(port_subst == IP_NULL);
963 kr = KERN_INVALID_CAPABILITY;
964 goto out;
965 }
966
967 /* is the kolabel requesting a substitution */
968 if (port_subst != IP_NULL) {
969 /*
970 * port is unlocked, its right consumed
971 * space is unlocked
972 */
973 assert(msgt_name == MACH_MSG_TYPE_PORT_SEND);
974 port = port_subst;
975 if (!IP_VALID(port)) {
976 object = IO_DEAD;
977 kr = KERN_INVALID_CAPABILITY;
978 goto out;
979 }
980
981 object = ip_to_object(port);
982 is_write_lock(space);
983 continue;
ea3f0419
A
984 }
985
1c79356b
A
986 break;
987 }
988
989 /* space is write-locked and active, object is locked and active */
990
c3c9b80d
A
991 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
992 ipc_right_reverse(space, object, &name, &entry)) {
993 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
994 } else {
995 ipc_entry_claim(space, &name, &entry);
996
997 assert(!ipc_right_inuse(entry));
998 assert(entry->ie_object == IO_NULL);
999
1000 entry->ie_object = object;
1001 }
1002
1c79356b 1003 kr = ipc_right_copyout(space, name, entry,
c3c9b80d 1004 msgt_name, flags, context, guard_flags, object);
39236c6e 1005
1c79356b
A
1006 /* object is unlocked */
1007 is_write_unlock(space);
1008
c3c9b80d 1009out:
0a7de745 1010 if (kr == KERN_SUCCESS) {
1c79356b 1011 *namep = name;
c3c9b80d
A
1012 } else if (IO_VALID(object)) {
1013 ipc_object_destroy(object, msgt_name);
0a7de745 1014 }
c3c9b80d 1015
1c79356b
A
1016 return kr;
1017}
1018
1019/*
1020 * Routine: ipc_object_copyout_name
1021 * Purpose:
1022 * Copyout a capability, placing it into a space.
1023 * The specified name is used for the capability.
1024 * If successful, consumes a ref for the object.
1025 * Conditions:
1026 * Nothing locked.
1027 * Returns:
1028 * KERN_SUCCESS Copied out object, consumed ref.
1029 * KERN_INVALID_TASK The space is dead.
1030 * KERN_INVALID_CAPABILITY The object is dead.
1031 * KERN_RESOURCE_SHORTAGE No memory available.
1032 * KERN_UREFS_OVERFLOW Urefs limit exceeded
1033 * and overflow wasn't specified.
1034 * KERN_RIGHT_EXISTS Space has rights under another name.
1035 * KERN_NAME_EXISTS Name is already used.
1036 */
1037
1038kern_return_t
1039ipc_object_copyout_name(
0a7de745
A
1040 ipc_space_t space,
1041 ipc_object_t object,
1042 mach_msg_type_name_t msgt_name,
0a7de745 1043 mach_port_name_t name)
1c79356b 1044{
c3c9b80d 1045 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
1046 mach_port_name_t oname;
1047 ipc_entry_t oentry;
1048 ipc_entry_t entry;
1049 kern_return_t kr;
1050
39236c6e
A
1051#if IMPORTANCE_INHERITANCE
1052 int assertcnt = 0;
fe8ab488 1053 ipc_importance_task_t task_imp = IIT_NULL;
39236c6e
A
1054#endif /* IMPORTANCE_INHERITANCE */
1055
1c79356b
A
1056 assert(IO_VALID(object));
1057 assert(io_otype(object) == IOT_PORT);
1058
1059 kr = ipc_entry_alloc_name(space, name, &entry);
0a7de745 1060 if (kr != KERN_SUCCESS) {
1c79356b 1061 return kr;
0a7de745 1062 }
1c79356b
A
1063 /* space is write-locked and active */
1064
c3c9b80d
A
1065 io_lock(object);
1066
1067 /*
1068 * Don't actually copyout rights we aren't allowed to
1069 *
1070 * In particular, kolabel-ed objects do not allow callers
1071 * to pick the name they end up with.
1072 */
1073 if (!io_active(object) || ip_is_kolabeled(port)) {
1074 io_unlock(object);
1075 if (!ipc_right_inuse(entry)) {
1076 ipc_entry_dealloc(space, name, entry);
1077 }
1078 is_write_unlock(space);
1079 return KERN_INVALID_CAPABILITY;
1080 }
1081
1082 /* space is write-locked and active, object is locked and active */
1083
1c79356b
A
1084 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1085 ipc_right_reverse(space, object, &oname, &oentry)) {
1c79356b
A
1086 if (name != oname) {
1087 io_unlock(object);
c3c9b80d 1088 if (!ipc_right_inuse(entry)) {
1c79356b 1089 ipc_entry_dealloc(space, name, entry);
0a7de745 1090 }
1c79356b
A
1091 is_write_unlock(space);
1092 return KERN_RIGHT_EXISTS;
1093 }
1094
1095 assert(entry == oentry);
1096 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
c3c9b80d
A
1097 } else if (ipc_right_inuse(entry)) {
1098 io_unlock(object);
1099 is_write_unlock(space);
1100 return KERN_NAME_EXISTS;
1c79356b 1101 } else {
1c79356b
A
1102 assert(entry->ie_object == IO_NULL);
1103
1c79356b
A
1104 entry->ie_object = object;
1105 }
1106
39236c6e
A
1107#if IMPORTANCE_INHERITANCE
1108 /*
1109 * We are slamming a receive right into the space, without
1110 * first having been enqueued on a port destined there. So,
1111 * we have to arrange to boost the task appropriately if this
1112 * port has assertions (and the task wants them).
1113 */
1114 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
fe8ab488
A
1115 if (space->is_task != TASK_NULL) {
1116 task_imp = space->is_task->task_imp_base;
1117 if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1118 assertcnt = port->ip_impcount;
1119 ipc_importance_task_reference(task_imp);
5ba3f43e
A
1120 } else {
1121 task_imp = IIT_NULL;
fe8ab488 1122 }
39236c6e
A
1123 }
1124
1125 /* take port out of limbo */
1126 assert(port->ip_tempowner != 0);
1127 port->ip_tempowner = 0;
1128 }
1129
1130#endif /* IMPORTANCE_INHERITANCE */
1131
1c79356b 1132 kr = ipc_right_copyout(space, name, entry,
c3c9b80d 1133 msgt_name, IPC_OBJECT_COPYOUT_FLAGS_NONE, NULL, NULL, object);
39236c6e 1134
1c79356b
A
1135 /* object is unlocked */
1136 is_write_unlock(space);
39236c6e
A
1137
1138#if IMPORTANCE_INHERITANCE
1139 /*
1140 * Add the assertions to the task that we captured before
1141 */
fe8ab488
A
1142 if (task_imp != IIT_NULL) {
1143 ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
1144 ipc_importance_task_release(task_imp);
39236c6e
A
1145 }
1146#endif /* IMPORTANCE_INHERITANCE */
1147
1c79356b
A
1148 return kr;
1149}
1150
1151/*
1152 * Routine: ipc_object_copyout_dest
1153 * Purpose:
1154 * Translates/consumes the destination right of a message.
1155 * This is unlike normal copyout because the right is consumed
1156 * in a funny way instead of being given to the receiving space.
1157 * The receiver gets his name for the port, if he has receive
1158 * rights, otherwise MACH_PORT_NULL.
1159 * Conditions:
1160 * The object is locked and active. Nothing else locked.
1161 * The object is unlocked and loses a reference.
1162 */
1163
1164void
1165ipc_object_copyout_dest(
0a7de745
A
1166 ipc_space_t space,
1167 ipc_object_t object,
1168 mach_msg_type_name_t msgt_name,
1169 mach_port_name_t *namep)
1c79356b
A
1170{
1171 mach_port_name_t name;
1172
1173 assert(IO_VALID(object));
1174 assert(io_active(object));
1175
1c79356b
A
1176 /*
1177 * If the space is the receiver/owner of the object,
1178 * then we quietly consume the right and return
1179 * the space's name for the object. Otherwise
1180 * we destroy the right and return MACH_PORT_NULL.
1181 */
1182
1183 switch (msgt_name) {
0a7de745 1184 case MACH_MSG_TYPE_PORT_SEND: {
cb323159 1185 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
1186 ipc_port_t nsrequest = IP_NULL;
1187 mach_port_mscount_t mscount;
1188
0a7de745 1189 if (port->ip_receiver == space) {
1c79356b 1190 name = port->ip_receiver_name;
0a7de745 1191 } else {
1c79356b 1192 name = MACH_PORT_NULL;
0a7de745 1193 }
1c79356b
A
1194
1195 assert(port->ip_srights > 0);
1196 if (--port->ip_srights == 0 &&
1197 port->ip_nsrequest != IP_NULL) {
1198 nsrequest = port->ip_nsrequest;
1199 port->ip_nsrequest = IP_NULL;
1200 mscount = port->ip_mscount;
cb323159
A
1201 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1202 /* port unlocked */
1c79356b 1203 ipc_notify_no_senders(nsrequest, mscount);
0a7de745 1204 } else {
cb323159
A
1205 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1206 /* port unlocked */
0a7de745 1207 }
cb323159
A
1208
1209 ip_release(port);
1c79356b 1210 break;
0a7de745 1211 }
1c79356b 1212
0a7de745 1213 case MACH_MSG_TYPE_PORT_SEND_ONCE: {
cb323159 1214 ipc_port_t port = ip_object_to_port(object);
1c79356b
A
1215
1216 assert(port->ip_sorights > 0);
1217
1218 if (port->ip_receiver == space) {
1219 /* quietly consume the send-once right */
1220
1221 port->ip_sorights--;
1222 name = port->ip_receiver_name;
cb323159
A
1223 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1224 /* port unlocked */
1225 ip_release(port);
1c79356b
A
1226 } else {
1227 /*
1228 * A very bizarre case. The message
1229 * was received, but before this copyout
1230 * happened the space lost receive rights.
1231 * We can't quietly consume the soright
1232 * out from underneath some other task,
1233 * so generate a send-once notification.
1234 */
1235
1c79356b
A
1236 ip_unlock(port);
1237
1238 ipc_notify_send_once(port);
1239 name = MACH_PORT_NULL;
1240 }
1241
1242 break;
0a7de745 1243 }
1c79356b 1244
0a7de745 1245 default:
1c79356b 1246 panic("ipc_object_copyout_dest: strange rights");
91447636 1247 name = MACH_PORT_DEAD;
1c79356b
A
1248 }
1249
1250 *namep = name;
1251}
1252
1253/*
cb323159 1254 * Routine: io_lock
1c79356b 1255 * Purpose:
cb323159 1256 * Validate, then acquire a lock on an ipc object
1c79356b
A
1257 */
1258
cb323159
A
1259void
1260io_lock(ipc_object_t io)
1c79356b 1261{
cb323159
A
1262 ipc_object_validate(io);
1263 lck_spin_lock_grp(&(io)->io_lock_data, &ipc_lck_grp);
1264}
1c79356b 1265
cb323159
A
1266/*
1267 * Routine: io_lock_try
1268 * Purpose:
1269 * Validate, then try to acquire a lock on an object,
1270 * fail if there is an existing busy lock
1271 */
1c79356b 1272
cb323159
A
1273boolean_t
1274io_lock_try(ipc_object_t io)
1275{
1276 ipc_object_validate(io);
1277 return lck_spin_try_lock_grp(&(io)->io_lock_data, &ipc_lck_grp);
1c79356b
A
1278}
1279
1c79356b
A
1280/*
1281 * Check whether the object is a port if so, free it. But
1282 * keep track of that fact.
1283 */
1284void
1285io_free(
0a7de745
A
1286 unsigned int otype,
1287 ipc_object_t object)
1c79356b 1288{
1c79356b 1289 if (otype == IOT_PORT) {
cb323159 1290 ipc_port_finalize(ip_object_to_port(object));
1c79356b 1291 }
b0d623f7 1292 io_lock_destroy(object);
91447636 1293 zfree(ipc_object_zones[otype], object);
1c79356b 1294}