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 [email protected]
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 #include <kern/zalloc_internal.h> // zone_id_for_element
83
84 #include <ipc/ipc_types.h>
85 #include <ipc/ipc_importance.h>
86 #include <ipc/port.h>
87 #include <ipc/ipc_space.h>
88 #include <ipc/ipc_entry.h>
89 #include <ipc/ipc_object.h>
90 #include <ipc/ipc_hash.h>
91 #include <ipc/ipc_right.h>
92 #include <ipc/ipc_notify.h>
93 #include <ipc/ipc_port.h>
94 #include <ipc/ipc_pset.h>
95
96 #include <security/mac_mach_internal.h>
97
98 static struct mpsc_daemon_queue ipc_object_deallocate_queue;
99 SECURITY_READ_ONLY_LATE(zone_t) ipc_object_zones[IOT_NUMBER];
100
101 /*
102 * In order to do lockfree lookups in the IPC space, we combine two schemes:
103 *
104 * - the ipc table pointer is protected with hazard pointers to allow
105 * dereferencing it with only holding a ref on a task or space;
106 *
107 * - we use ipc_object_lock_allow_invalid in order to lock locks and validate
108 * that they are the droid we're looking for.
109 *
110 * The second half requires that virtual addresses assigned that ever held
111 * a port, either hold a port, or nothing, forever. To get this property,
112 * we just piggy back on the zone sequestering security feature which gives
113 * us exactly that.
114 *
115 * However, sequestering really only "works" on a sufficiently large address
116 * space, especially for a resource that can be made by userspace at will,
117 * so we can't do lockless lookups on ILP32.
118 *
119 * Note: this scheme is incompatible with kasan quarantines
120 * (because it uses elements to store backtraces in them
121 * which lets the waitq lock appear "valid" by accident when
122 * elements are freed).
123 */
124 #define IPC_OBJECT_ZC_BASE (ZC_ZFREE_CLEARMEM | ZC_SEQUESTER | \
125 ZC_KASAN_NOQUARANTINE)
126
127 ZONE_INIT(&ipc_object_zones[IOT_PORT],
128 "ipc ports", sizeof(struct ipc_port),
129 IPC_OBJECT_ZC_BASE | ZC_CACHING, ZONE_ID_IPC_PORT, NULL);
130
131 ZONE_INIT(&ipc_object_zones[IOT_PORT_SET],
132 "ipc port sets", sizeof(struct ipc_pset),
133 IPC_OBJECT_ZC_BASE, ZONE_ID_IPC_PORT_SET, NULL);
134
135 __attribute__((noinline))
136 static void
ipc_object_free(unsigned int otype,ipc_object_t object,bool last_ref)137 ipc_object_free(unsigned int otype, ipc_object_t object, bool last_ref)
138 {
139 if (last_ref) {
140 if (otype == IOT_PORT) {
141 ipc_port_finalize(ip_object_to_port(object));
142 } else {
143 ipc_pset_finalize(ips_object_to_pset(object));
144 }
145 }
146 zfree(ipc_object_zones[otype], object);
147 }
148
149 __attribute__((noinline))
150 static void
ipc_object_free_safe(ipc_object_t object)151 ipc_object_free_safe(ipc_object_t object)
152 {
153 struct waitq *wq = io_waitq(object);
154
155 assert(!waitq_is_valid(wq));
156 assert(os_atomic_load(&wq->waitq_defer.mpqc_next, relaxed) == NULL);
157 mpsc_daemon_enqueue(&ipc_object_deallocate_queue,
158 &wq->waitq_defer, MPSC_QUEUE_NONE);
159 }
160
161 static void
ipc_object_deallocate_queue_invoke(mpsc_queue_chain_t e,__assert_only mpsc_daemon_queue_t dq)162 ipc_object_deallocate_queue_invoke(mpsc_queue_chain_t e,
163 __assert_only mpsc_daemon_queue_t dq)
164 {
165 struct waitq *wq = __container_of(e, struct waitq, waitq_defer);
166 ipc_object_t io = io_from_waitq(wq);
167
168 assert(dq == &ipc_object_deallocate_queue);
169
170 os_atomic_store(&wq->waitq_defer.mpqc_next, NULL, relaxed);
171 ipc_object_free(io_otype(io), io, true);
172 }
173
174 void
ipc_object_deallocate_register_queue(void)175 ipc_object_deallocate_register_queue(void)
176 {
177 thread_deallocate_daemon_register_queue(&ipc_object_deallocate_queue,
178 ipc_object_deallocate_queue_invoke);
179 }
180
181 /*
182 * Routine: ipc_object_reference
183 * Purpose:
184 * Take a reference to an object.
185 */
186
187 void
ipc_object_reference(ipc_object_t io)188 ipc_object_reference(
189 ipc_object_t io)
190 {
191 static_assert(sizeof(os_ref_atomic_t) == sizeof(io->io_references));
192 os_ref_retain_raw((os_ref_atomic_t *)&io->io_references, NULL);
193 }
194
195 /*
196 * Routine: ipc_object_release
197 * Purpose:
198 * Release a reference to an object.
199 */
200
201 void
ipc_object_release(ipc_object_t io)202 ipc_object_release(
203 ipc_object_t io)
204 {
205 #if DEBUG
206 assert(get_preemption_level() == 0);
207 #endif
208
209 if (os_ref_release_raw((os_ref_atomic_t *)&io->io_references, NULL) == 0) {
210 /* Free the object */
211 ipc_object_free(io_otype(io), io, true);
212 }
213 }
214
215 /*
216 * Routine: ipc_object_release_safe
217 * Purpose:
218 * Release a reference to an object safely
219 */
220
221 void
ipc_object_release_safe(ipc_object_t io)222 ipc_object_release_safe(
223 ipc_object_t io)
224 {
225 if (os_ref_release_raw((os_ref_atomic_t *)&io->io_references, NULL) == 0) {
226 if (get_preemption_level() == 0) {
227 ipc_object_free(io_otype(io), io, true);
228 } else {
229 ipc_object_free_safe(io);
230 }
231 }
232 }
233
234 /*
235 * Routine: ipc_object_release_live
236 * Purpose:
237 * Release a reference to an object that isn't the last one.
238 */
239
240 void
ipc_object_release_live(ipc_object_t io)241 ipc_object_release_live(
242 ipc_object_t io)
243 {
244 os_ref_release_live_raw((os_ref_atomic_t *)&io->io_references, NULL);
245 }
246
247 /*
248 * Routine: ipc_object_translate
249 * Purpose:
250 * Look up an object in a space.
251 * Conditions:
252 * Nothing locked before. If successful, the object
253 * is returned active and locked. The caller doesn't get a ref.
254 * Returns:
255 * KERN_SUCCESS Object returned locked.
256 * KERN_INVALID_TASK The space is dead.
257 * KERN_INVALID_NAME The name doesn't denote a right
258 * KERN_INVALID_RIGHT Name doesn't denote the correct right
259 */
260 kern_return_t
ipc_object_translate(ipc_space_t space,mach_port_name_t name,mach_port_right_t right,ipc_object_t * objectp)261 ipc_object_translate(
262 ipc_space_t space,
263 mach_port_name_t name,
264 mach_port_right_t right,
265 ipc_object_t *objectp)
266 {
267 ipc_entry_bits_t bits;
268 ipc_object_t object;
269 kern_return_t kr;
270
271 if (!MACH_PORT_RIGHT_VALID_TRANSLATE(right)) {
272 return KERN_INVALID_RIGHT;
273 }
274
275 kr = ipc_right_lookup_read(space, name, &bits, &object);
276 if (kr != KERN_SUCCESS) {
277 return kr;
278 }
279 /* object is locked and active */
280
281 if ((bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
282 io_unlock(object);
283 return KERN_INVALID_RIGHT;
284 }
285
286 *objectp = object;
287 return KERN_SUCCESS;
288 }
289
290 /*
291 * Routine: ipc_object_translate_two
292 * Purpose:
293 * Look up two objects in a space.
294 * Conditions:
295 * Nothing locked before. If successful, the objects
296 * are returned locked. The caller doesn't get a ref.
297 * Returns:
298 * KERN_SUCCESS Objects returned locked.
299 * KERN_INVALID_TASK The space is dead.
300 * KERN_INVALID_NAME A name doesn't denote a right.
301 * KERN_INVALID_RIGHT A name doesn't denote the correct right.
302 */
303
304 kern_return_t
ipc_object_translate_two(ipc_space_t space,mach_port_name_t name1,mach_port_right_t right1,ipc_object_t * objectp1,mach_port_name_t name2,mach_port_right_t right2,ipc_object_t * objectp2)305 ipc_object_translate_two(
306 ipc_space_t space,
307 mach_port_name_t name1,
308 mach_port_right_t right1,
309 ipc_object_t *objectp1,
310 mach_port_name_t name2,
311 mach_port_right_t right2,
312 ipc_object_t *objectp2)
313 {
314 ipc_entry_t entry1;
315 ipc_entry_t entry2;
316 ipc_object_t object1, object2;
317 kern_return_t kr;
318 boolean_t doguard = TRUE;
319
320 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
321 if (kr != KERN_SUCCESS) {
322 return kr;
323 }
324 /* space is read-locked and active */
325
326 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
327 /* If looking for receive, and the entry used to hold one, give a pass on EXC_GUARD */
328 if ((right1 & MACH_PORT_RIGHT_RECEIVE) == MACH_PORT_RIGHT_RECEIVE &&
329 (entry1->ie_bits & MACH_PORT_TYPE_EX_RECEIVE) == MACH_PORT_TYPE_EX_RECEIVE) {
330 doguard = FALSE;
331 }
332 is_read_unlock(space);
333 if (doguard) {
334 mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT);
335 }
336 return KERN_INVALID_RIGHT;
337 }
338
339 if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
340 /* If looking for receive, and the entry used to hold one, give a pass on EXC_GUARD */
341 if ((right2 & MACH_PORT_RIGHT_RECEIVE) == MACH_PORT_RIGHT_RECEIVE &&
342 (entry2->ie_bits & MACH_PORT_TYPE_EX_RECEIVE) == MACH_PORT_TYPE_EX_RECEIVE) {
343 doguard = FALSE;
344 }
345 is_read_unlock(space);
346 if (doguard) {
347 mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT);
348 }
349 return KERN_INVALID_RIGHT;
350 }
351
352 object1 = entry1->ie_object;
353 assert(object1 != IO_NULL);
354 io_lock(object1);
355 if (!io_active(object1)) {
356 io_unlock(object1);
357 is_read_unlock(space);
358 return KERN_INVALID_NAME;
359 }
360
361 object2 = entry2->ie_object;
362 assert(object2 != IO_NULL);
363 io_lock(object2);
364 if (!io_active(object2)) {
365 io_unlock(object1);
366 io_unlock(object2);
367 is_read_unlock(space);
368 return KERN_INVALID_NAME;
369 }
370
371 *objectp1 = object1;
372 *objectp2 = object2;
373
374 is_read_unlock(space);
375 return KERN_SUCCESS;
376 }
377
378 /*
379 * Routine: ipc_object_alloc_dead
380 * Purpose:
381 * Allocate a dead-name entry.
382 * Conditions:
383 * Nothing locked.
384 * Returns:
385 * KERN_SUCCESS The dead name is allocated.
386 * KERN_INVALID_TASK The space is dead.
387 * KERN_NO_SPACE No room for an entry in the space.
388 */
389
390 kern_return_t
ipc_object_alloc_dead(ipc_space_t space,mach_port_name_t * namep)391 ipc_object_alloc_dead(
392 ipc_space_t space,
393 mach_port_name_t *namep)
394 {
395 ipc_entry_t entry;
396 kern_return_t kr;
397
398 kr = ipc_entry_alloc(space, IO_NULL, namep, &entry);
399 if (kr != KERN_SUCCESS) {
400 return kr;
401 }
402 /* space is write-locked */
403
404 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
405
406 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
407 ipc_entry_modified(space, *namep, entry);
408 is_write_unlock(space);
409 return KERN_SUCCESS;
410 }
411
412 /*
413 * Routine: ipc_object_alloc
414 * Purpose:
415 * Allocate an object.
416 * Conditions:
417 * Nothing locked.
418 * The space is write locked on successful return.
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_NO_SPACE No room for an entry in the space.
424 */
425
426 kern_return_t
ipc_object_alloc(ipc_space_t space,ipc_object_type_t otype,mach_port_type_t type,mach_port_urefs_t urefs,mach_port_name_t * namep,ipc_object_t * objectp)427 ipc_object_alloc(
428 ipc_space_t space,
429 ipc_object_type_t otype,
430 mach_port_type_t type,
431 mach_port_urefs_t urefs,
432 mach_port_name_t *namep,
433 ipc_object_t *objectp)
434 {
435 ipc_object_t object;
436 ipc_entry_t entry;
437 kern_return_t kr;
438
439 assert(otype < IOT_NUMBER);
440 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
441 assert(type != MACH_PORT_TYPE_NONE);
442 assert(urefs <= MACH_PORT_UREFS_MAX);
443
444 object = io_alloc(otype, Z_WAITOK | Z_ZERO | Z_NOFAIL);
445 os_atomic_init(&object->io_bits, io_makebits(otype));
446 os_atomic_init(&object->io_references, 1); /* for entry, not caller */
447
448 *namep = CAST_MACH_PORT_TO_NAME(object);
449 kr = ipc_entry_alloc(space, object, namep, &entry);
450 if (kr != KERN_SUCCESS) {
451 ipc_object_free(otype, object, false);
452 return kr;
453 }
454 /* space is write-locked */
455
456 entry->ie_bits |= type | urefs;
457 ipc_entry_modified(space, *namep, entry);
458
459 *objectp = object;
460 return KERN_SUCCESS;
461 }
462
463 /*
464 * Routine: ipc_object_alloc_name
465 * Purpose:
466 * Allocate an object, with a specific name.
467 * Conditions:
468 * Nothing locked. If successful, the object is returned locked.
469 * The caller doesn't get a reference for the object.
470 *
471 * finish_init() must call an ipc_*_init function
472 * that will return the object locked (using IPC_PORT_INIT_LOCKED,
473 * or SYNC_POLICY_INIT_LOCKED, or equivalent).
474 *
475 * Returns:
476 * KERN_SUCCESS The object is allocated.
477 * KERN_INVALID_TASK The space is dead.
478 * KERN_NAME_EXISTS The name already denotes a right.
479 */
480
481 kern_return_t
482 ipc_object_alloc_name(
483 ipc_space_t space,
484 ipc_object_type_t otype,
485 mach_port_type_t type,
486 mach_port_urefs_t urefs,
487 mach_port_name_t name,
488 ipc_object_t *objectp,
489 void (^finish_init)(ipc_object_t))
490 {
491 ipc_object_t object;
492 ipc_entry_t entry;
493 kern_return_t kr;
494
495 assert(otype < IOT_NUMBER);
496 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
497 assert(type != MACH_PORT_TYPE_NONE);
498 assert(urefs <= MACH_PORT_UREFS_MAX);
499
500 object = io_alloc(otype, Z_WAITOK | Z_ZERO | Z_NOFAIL);
501 os_atomic_init(&object->io_bits, io_makebits(otype));
502 os_atomic_init(&object->io_references, 1); /* for entry, not caller */
503
504 kr = ipc_entry_alloc_name(space, name, &entry);
505 if (kr != KERN_SUCCESS) {
506 ipc_object_free(otype, object, false);
507 return kr;
508 }
509 /* space is write-locked */
510
511 if (ipc_right_inuse(entry)) {
512 is_write_unlock(space);
513 ipc_object_free(otype, object, false);
514 return KERN_NAME_EXISTS;
515 }
516
517 entry->ie_bits |= type | urefs;
518 entry->ie_object = object;
519
520 finish_init(object);
521 /* object is locked */
522 io_lock_held(object);
523
524 ipc_entry_modified(space, name, entry);
525 is_write_unlock(space);
526
527 *objectp = object;
528 return KERN_SUCCESS;
529 }
530
531 /* Routine: ipc_object_validate
532 * Purpose:
533 * Validates an ipc port or port set as belonging to the correct
534 * zone.
535 */
536
537 void
ipc_object_validate(ipc_object_t object)538 ipc_object_validate(
539 ipc_object_t object)
540 {
541 if (io_otype(object) != IOT_PORT_SET) {
542 ip_validate(object);
543 } else {
544 ips_validate(object);
545 }
546 }
547
548 /*
549 * Routine: ipc_object_copyin_type
550 * Purpose:
551 * Convert a send type name to a received type name.
552 */
553
554 mach_msg_type_name_t
ipc_object_copyin_type(mach_msg_type_name_t msgt_name)555 ipc_object_copyin_type(
556 mach_msg_type_name_t msgt_name)
557 {
558 switch (msgt_name) {
559 case MACH_MSG_TYPE_MOVE_RECEIVE:
560 return MACH_MSG_TYPE_PORT_RECEIVE;
561
562 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
563 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
564 return MACH_MSG_TYPE_PORT_SEND_ONCE;
565
566 case MACH_MSG_TYPE_MOVE_SEND:
567 case MACH_MSG_TYPE_MAKE_SEND:
568 case MACH_MSG_TYPE_COPY_SEND:
569 return MACH_MSG_TYPE_PORT_SEND;
570
571 case MACH_MSG_TYPE_DISPOSE_RECEIVE:
572 case MACH_MSG_TYPE_DISPOSE_SEND:
573 case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
574 /* fall thru */
575 default:
576 return MACH_MSG_TYPE_PORT_NONE;
577 }
578 }
579
580 /*
581 * Routine: ipc_object_copyin
582 * Purpose:
583 * Copyin a capability from a space.
584 * If successful, the caller gets a ref
585 * for the resulting object, unless it is IO_DEAD.
586 * Conditions:
587 * Nothing locked.
588 * Returns:
589 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
590 * KERN_INVALID_TASK The space is dead.
591 * KERN_INVALID_NAME Name doesn't exist in space.
592 * KERN_INVALID_RIGHT Name doesn't denote correct right.
593 */
594
595 kern_return_t
ipc_object_copyin(ipc_space_t space,mach_port_name_t name,mach_msg_type_name_t msgt_name,ipc_object_t * objectp,mach_port_context_t context,mach_msg_guard_flags_t * guard_flags,ipc_object_copyin_flags_t copyin_flags)596 ipc_object_copyin(
597 ipc_space_t space,
598 mach_port_name_t name,
599 mach_msg_type_name_t msgt_name,
600 ipc_object_t *objectp,
601 mach_port_context_t context,
602 mach_msg_guard_flags_t *guard_flags,
603 ipc_object_copyin_flags_t copyin_flags)
604 {
605 ipc_entry_t entry;
606 ipc_port_t soright;
607 ipc_port_t release_port;
608 kern_return_t kr;
609 int assertcnt = 0;
610
611 ipc_object_copyin_flags_t copyin_mask = IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND
612 | IPC_OBJECT_COPYIN_FLAGS_ALLOW_CONN_IMMOVABLE_RECEIVE;
613 copyin_mask = (copyin_flags & copyin_mask) | IPC_OBJECT_COPYIN_FLAGS_DEADOK;
614
615 /*
616 * We allow moving of immovable receive right of a service port when it is from launchd.
617 */
618 task_t task = current_task_early();
619 #ifdef MACH_BSD
620 if (task && proc_isinitproc(get_bsdtask_info(task))) {
621 copyin_mask |= IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_RECEIVE;
622 }
623 #endif
624
625 /*
626 * Could first try a read lock when doing
627 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
628 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
629 */
630
631 kr = ipc_right_lookup_write(space, name, &entry);
632 if (kr != KERN_SUCCESS) {
633 return kr;
634 }
635 /* space is write-locked and active */
636
637 release_port = IP_NULL;
638 kr = ipc_right_copyin(space, name, entry,
639 msgt_name, copyin_mask,
640 objectp, &soright,
641 &release_port,
642 &assertcnt,
643 context,
644 guard_flags);
645 is_write_unlock(space);
646
647 #if IMPORTANCE_INHERITANCE
648 if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
649 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
650 }
651 #endif /* IMPORTANCE_INHERITANCE */
652
653 if (release_port != IP_NULL) {
654 ip_release(release_port);
655 }
656
657 if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) {
658 ipc_notify_port_deleted(soright, name);
659 }
660
661 return kr;
662 }
663
664 /*
665 * Routine: ipc_object_copyin_from_kernel
666 * Purpose:
667 * Copyin a naked capability from the kernel.
668 *
669 * MACH_MSG_TYPE_MOVE_RECEIVE
670 * The receiver must be ipc_space_kernel
671 * or the receive right must already be in limbo.
672 * Consumes the naked receive right.
673 * MACH_MSG_TYPE_COPY_SEND
674 * A naked send right must be supplied.
675 * The port gains a reference, and a send right
676 * if the port is still active.
677 * MACH_MSG_TYPE_MAKE_SEND
678 * The receiver must be ipc_space_kernel.
679 * The port gains a reference and a send right.
680 * MACH_MSG_TYPE_MOVE_SEND
681 * Consumes a naked send right.
682 * MACH_MSG_TYPE_MAKE_SEND_ONCE
683 * The port gains a reference and a send-once right.
684 * Receiver also be the caller of device subsystem,
685 * so no assertion.
686 * MACH_MSG_TYPE_MOVE_SEND_ONCE
687 * Consumes a naked send-once right.
688 * Conditions:
689 * Nothing locked.
690 */
691
692 void
ipc_object_copyin_from_kernel(ipc_object_t object,mach_msg_type_name_t msgt_name)693 ipc_object_copyin_from_kernel(
694 ipc_object_t object,
695 mach_msg_type_name_t msgt_name)
696 {
697 assert(IO_VALID(object));
698
699 switch (msgt_name) {
700 case MACH_MSG_TYPE_MOVE_RECEIVE: {
701 ipc_port_t port = ip_object_to_port(object);
702
703 ip_mq_lock(port);
704 require_ip_active(port);
705 if (ip_in_a_space(port)) {
706 assert(ip_in_space(port, ipc_space_kernel));
707 assert(port->ip_immovable_receive == 0);
708
709 /* relevant part of ipc_port_clear_receiver */
710 port->ip_mscount = 0;
711
712 /* port transtions to IN-LIMBO state */
713 port->ip_receiver_name = MACH_PORT_NULL;
714 port->ip_destination = IP_NULL;
715 }
716 ip_mq_unlock(port);
717 break;
718 }
719
720 case MACH_MSG_TYPE_COPY_SEND: {
721 ipc_port_t port = ip_object_to_port(object);
722
723 ip_mq_lock(port);
724 if (ip_active(port)) {
725 assert(port->ip_srights > 0);
726 }
727 port->ip_srights++;
728 ip_reference(port);
729 ip_mq_unlock(port);
730 break;
731 }
732
733 case MACH_MSG_TYPE_MAKE_SEND: {
734 ipc_port_t port = ip_object_to_port(object);
735
736 ip_mq_lock(port);
737 if (ip_active(port)) {
738 assert(ip_in_a_space(port));
739 assert((ip_in_space(port, ipc_space_kernel)) ||
740 (port->ip_receiver->is_node_id != HOST_LOCAL_NODE));
741 port->ip_mscount++;
742 }
743
744 port->ip_srights++;
745 ip_reference(port);
746 ip_mq_unlock(port);
747 break;
748 }
749
750 case MACH_MSG_TYPE_MOVE_SEND: {
751 /* move naked send right into the message */
752 assert(ip_object_to_port(object)->ip_srights);
753 break;
754 }
755
756 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
757 ipc_port_t port = ip_object_to_port(object);
758
759 ip_mq_lock(port);
760 if (ip_active(port)) {
761 assert(ip_in_a_space(port));
762 }
763 ipc_port_make_sonce_locked(port);
764 ip_mq_unlock(port);
765 break;
766 }
767
768 case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
769 /* move naked send-once right into the message */
770 assert(ip_object_to_port(object)->ip_sorights);
771 break;
772 }
773
774 default:
775 panic("ipc_object_copyin_from_kernel: strange rights");
776 }
777 }
778
779 /*
780 * Routine: ipc_object_destroy
781 * Purpose:
782 * Destroys a naked capability.
783 * Consumes a ref for the object.
784 *
785 * A receive right should be in limbo or in transit.
786 * Conditions:
787 * Nothing locked.
788 */
789
790 void
ipc_object_destroy(ipc_object_t object,mach_msg_type_name_t msgt_name)791 ipc_object_destroy(
792 ipc_object_t object,
793 mach_msg_type_name_t msgt_name)
794 {
795 assert(IO_VALID(object));
796 assert(io_otype(object) == IOT_PORT);
797
798 switch (msgt_name) {
799 case MACH_MSG_TYPE_PORT_SEND:
800 ipc_port_release_send(ip_object_to_port(object));
801 break;
802
803 case MACH_MSG_TYPE_PORT_SEND_ONCE:
804 io_lock(object);
805 ipc_notify_send_once_and_unlock(ip_object_to_port(object));
806 break;
807
808 case MACH_MSG_TYPE_PORT_RECEIVE:
809 ipc_port_release_receive(ip_object_to_port(object));
810 break;
811
812 default:
813 panic("ipc_object_destroy: strange rights");
814 }
815 }
816
817 /*
818 * Routine: ipc_object_destroy_dest
819 * Purpose:
820 * Destroys a naked capability for the destination of
821 * of a message. Consumes a ref for the object.
822 *
823 * Conditions:
824 * Nothing locked.
825 */
826
827 void
ipc_object_destroy_dest(ipc_object_t object,mach_msg_type_name_t msgt_name)828 ipc_object_destroy_dest(
829 ipc_object_t object,
830 mach_msg_type_name_t msgt_name)
831 {
832 ipc_port_t port = ip_object_to_port(object);
833
834 assert(IO_VALID(object));
835 assert(io_otype(object) == IOT_PORT);
836
837 switch (msgt_name) {
838 case MACH_MSG_TYPE_PORT_SEND:
839 ipc_port_release_send(port);
840 break;
841
842 case MACH_MSG_TYPE_PORT_SEND_ONCE:
843 ip_mq_lock(port);
844 ipc_notify_send_once_and_unlock(port);
845 break;
846
847 default:
848 panic("ipc_object_destroy_dest: strange rights");
849 }
850 }
851
852 /*
853 * Routine: ipc_object_insert_send_right
854 * Purpose:
855 * Insert a send right into an object already in the space.
856 * The specified name must already point to a valid object.
857 *
858 * Note: This really is a combined copyin()/copyout(),
859 * that avoids most of the overhead of being implemented that way.
860 *
861 * This is the fastpath for mach_port_insert_right.
862 *
863 * Conditions:
864 * Nothing locked.
865 *
866 * msgt_name must be MACH_MSG_TYPE_MAKE_SEND_ONCE or
867 * MACH_MSG_TYPE_MOVE_SEND_ONCE.
868 *
869 * Returns:
870 * KERN_SUCCESS Copied out object, consumed ref.
871 * KERN_INVALID_TASK The space is dead.
872 * KERN_INVALID_NAME Name doesn't exist in space.
873 * KERN_INVALID_CAPABILITY The object is dead.
874 * KERN_RIGHT_EXISTS Space has rights under another name.
875 */
876 kern_return_t
ipc_object_insert_send_right(ipc_space_t space,mach_port_name_t name,mach_msg_type_name_t msgt_name)877 ipc_object_insert_send_right(
878 ipc_space_t space,
879 mach_port_name_t name,
880 mach_msg_type_name_t msgt_name)
881 {
882 ipc_entry_bits_t bits;
883 ipc_object_t object;
884 ipc_entry_t entry;
885 kern_return_t kr;
886
887 assert(msgt_name == MACH_MSG_TYPE_MAKE_SEND ||
888 msgt_name == MACH_MSG_TYPE_COPY_SEND);
889
890 kr = ipc_right_lookup_write(space, name, &entry);
891 if (kr != KERN_SUCCESS) {
892 return kr;
893 }
894 /* space is write-locked and active */
895
896 if (!IO_VALID(entry->ie_object)) {
897 is_write_unlock(space);
898 return KERN_INVALID_CAPABILITY;
899 }
900
901 bits = entry->ie_bits;
902 object = entry->ie_object;
903
904 io_lock(object);
905 if (!io_active(object)) {
906 kr = KERN_INVALID_CAPABILITY;
907 } else if (msgt_name == MACH_MSG_TYPE_MAKE_SEND) {
908 if (bits & MACH_PORT_TYPE_RECEIVE) {
909 ipc_port_t port = ip_object_to_port(object);
910 port->ip_mscount++;
911 if ((bits & MACH_PORT_TYPE_SEND) == 0) {
912 port->ip_srights++;
913 bits |= MACH_PORT_TYPE_SEND;
914 }
915 /* leave urefs pegged to maximum if it overflowed */
916 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
917 bits += 1; /* increment urefs */
918 }
919 entry->ie_bits = bits;
920 ipc_entry_modified(space, name, entry);
921 kr = KERN_SUCCESS;
922 } else {
923 kr = KERN_INVALID_RIGHT;
924 }
925 } else { // MACH_MSG_TYPE_COPY_SEND
926 if (bits & MACH_PORT_TYPE_SEND) {
927 /* leave urefs pegged to maximum if it overflowed */
928 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
929 entry->ie_bits = bits + 1; /* increment urefs */
930 }
931 ipc_entry_modified(space, name, entry);
932 kr = KERN_SUCCESS;
933 } else {
934 kr = KERN_INVALID_RIGHT;
935 }
936 }
937
938 io_unlock(object);
939 is_write_unlock(space);
940
941 return kr;
942 }
943
944 /*
945 * Routine: ipc_object_copyout
946 * Purpose:
947 * Copyout a capability, placing it into a space.
948 * Always consumes a ref for the object.
949 * Conditions:
950 * Nothing locked.
951 * Returns:
952 * KERN_SUCCESS Copied out object, consumed ref.
953 * KERN_INVALID_TASK The space is dead.
954 * KERN_INVALID_CAPABILITY The object is dead.
955 * KERN_NO_SPACE No room in space for another right.
956 * KERN_UREFS_OVERFLOW Urefs limit exceeded
957 * and overflow wasn't specified.
958 */
959
960 kern_return_t
ipc_object_copyout(ipc_space_t space,ipc_object_t object,mach_msg_type_name_t msgt_name,ipc_object_copyout_flags_t flags,mach_port_context_t * context,mach_msg_guard_flags_t * guard_flags,mach_port_name_t * namep)961 ipc_object_copyout(
962 ipc_space_t space,
963 ipc_object_t object,
964 mach_msg_type_name_t msgt_name,
965 ipc_object_copyout_flags_t flags,
966 mach_port_context_t *context,
967 mach_msg_guard_flags_t *guard_flags,
968 mach_port_name_t *namep)
969 {
970 struct knote *kn = current_thread()->ith_knote;
971 mach_port_name_t name;
972 ipc_port_t port = ip_object_to_port(object);
973 ipc_entry_t entry;
974 kern_return_t kr;
975
976 assert(IO_VALID(object));
977 assert(io_otype(object) == IOT_PORT);
978
979 if (ITH_KNOTE_VALID(kn, msgt_name)) {
980 filt_machport_turnstile_prepare_lazily(kn, msgt_name, port);
981 }
982
983 is_write_lock(space);
984
985 for (;;) {
986 ipc_port_t port_subst = IP_NULL;
987
988 if (!is_active(space)) {
989 is_write_unlock(space);
990 kr = KERN_INVALID_TASK;
991 goto out;
992 }
993
994 kr = ipc_entries_hold(space, 1);
995 if (kr != KERN_SUCCESS) {
996 /* unlocks/locks space, so must start again */
997
998 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
999 if (kr != KERN_SUCCESS) {
1000 /* space is unlocked */
1001 goto out;
1002 }
1003 continue;
1004 }
1005
1006 io_lock(object);
1007 if (!io_active(object)) {
1008 io_unlock(object);
1009 is_write_unlock(space);
1010 kr = KERN_INVALID_CAPABILITY;
1011 goto out;
1012 }
1013
1014 /* Don't actually copyout rights we aren't allowed to */
1015 if (!ip_label_check(space, port, msgt_name, &flags, &port_subst)) {
1016 io_unlock(object);
1017 is_write_unlock(space);
1018 assert(port_subst == IP_NULL);
1019 kr = KERN_INVALID_CAPABILITY;
1020 goto out;
1021 }
1022
1023 /* is the kolabel requesting a substitution */
1024 if (port_subst != IP_NULL) {
1025 /*
1026 * port is unlocked, its right consumed
1027 * space is unlocked
1028 */
1029 assert(msgt_name == MACH_MSG_TYPE_PORT_SEND);
1030 port = port_subst;
1031 if (!IP_VALID(port)) {
1032 object = IO_DEAD;
1033 kr = KERN_INVALID_CAPABILITY;
1034 goto out;
1035 }
1036
1037 object = ip_to_object(port);
1038 is_write_lock(space);
1039 continue;
1040 }
1041
1042 break;
1043 }
1044
1045 /* space is write-locked and active, object is locked and active */
1046
1047 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1048 ipc_right_reverse(space, object, &name, &entry)) {
1049 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
1050 } else {
1051 ipc_entry_claim(space, object, &name, &entry);
1052 }
1053
1054 kr = ipc_right_copyout(space, name, entry,
1055 msgt_name, flags, context, guard_flags, object);
1056
1057 /* object is unlocked */
1058 is_write_unlock(space);
1059
1060 out:
1061 if (kr == KERN_SUCCESS) {
1062 *namep = name;
1063 } else if (IO_VALID(object)) {
1064 ipc_object_destroy(object, msgt_name);
1065 }
1066
1067 return kr;
1068 }
1069
1070 /*
1071 * Routine: ipc_object_copyout_name
1072 * Purpose:
1073 * Copyout a capability, placing it into a space.
1074 * The specified name is used for the capability.
1075 * If successful, consumes a ref for the object.
1076 * Conditions:
1077 * Nothing locked.
1078 * Returns:
1079 * KERN_SUCCESS Copied out object, consumed ref.
1080 * KERN_INVALID_TASK The space is dead.
1081 * KERN_INVALID_CAPABILITY The object is dead.
1082 * KERN_UREFS_OVERFLOW Urefs limit exceeded
1083 * and overflow wasn't specified.
1084 * KERN_RIGHT_EXISTS Space has rights under another name.
1085 * KERN_NAME_EXISTS Name is already used.
1086 * KERN_INVALID_VALUE Supplied port name is invalid.
1087 */
1088
1089 kern_return_t
ipc_object_copyout_name(ipc_space_t space,ipc_object_t object,mach_msg_type_name_t msgt_name,mach_port_name_t name)1090 ipc_object_copyout_name(
1091 ipc_space_t space,
1092 ipc_object_t object,
1093 mach_msg_type_name_t msgt_name,
1094 mach_port_name_t name)
1095 {
1096 ipc_port_t port = ip_object_to_port(object);
1097 mach_port_name_t oname;
1098 ipc_entry_t oentry;
1099 ipc_entry_t entry;
1100 kern_return_t kr;
1101
1102 #if IMPORTANCE_INHERITANCE
1103 int assertcnt = 0;
1104 ipc_importance_task_t task_imp = IIT_NULL;
1105 #endif /* IMPORTANCE_INHERITANCE */
1106
1107 assert(IO_VALID(object));
1108 assert(io_otype(object) == IOT_PORT);
1109
1110 kr = ipc_entry_alloc_name(space, name, &entry);
1111 if (kr != KERN_SUCCESS) {
1112 return kr;
1113 }
1114 /* space is write-locked and active */
1115
1116 io_lock(object);
1117
1118 /*
1119 * Don't actually copyout rights we aren't allowed to
1120 *
1121 * In particular, kolabel-ed objects do not allow callers
1122 * to pick the name they end up with.
1123 */
1124 if (!io_active(object) || ip_is_kolabeled(port)) {
1125 io_unlock(object);
1126 if (!ipc_right_inuse(entry)) {
1127 ipc_entry_dealloc(space, IO_NULL, name, entry);
1128 }
1129 is_write_unlock(space);
1130 return KERN_INVALID_CAPABILITY;
1131 }
1132
1133 /* space is write-locked and active, object is locked and active */
1134
1135 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1136 ipc_right_reverse(space, object, &oname, &oentry)) {
1137 if (name != oname) {
1138 io_unlock(object);
1139 if (!ipc_right_inuse(entry)) {
1140 ipc_entry_dealloc(space, IO_NULL, name, entry);
1141 }
1142 is_write_unlock(space);
1143 return KERN_RIGHT_EXISTS;
1144 }
1145
1146 assert(entry == oentry);
1147 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
1148 } else if (ipc_right_inuse(entry)) {
1149 io_unlock(object);
1150 is_write_unlock(space);
1151 return KERN_NAME_EXISTS;
1152 } else {
1153 assert(entry->ie_object == IO_NULL);
1154
1155 entry->ie_object = object;
1156 }
1157
1158 #if IMPORTANCE_INHERITANCE
1159 /*
1160 * We are slamming a receive right into the space, without
1161 * first having been enqueued on a port destined there. So,
1162 * we have to arrange to boost the task appropriately if this
1163 * port has assertions (and the task wants them).
1164 */
1165 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
1166 if (space->is_task != TASK_NULL) {
1167 task_imp = space->is_task->task_imp_base;
1168 if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1169 assertcnt = port->ip_impcount;
1170 ipc_importance_task_reference(task_imp);
1171 } else {
1172 task_imp = IIT_NULL;
1173 }
1174 }
1175
1176 /* take port out of limbo */
1177 port->ip_tempowner = 0;
1178 }
1179
1180 #endif /* IMPORTANCE_INHERITANCE */
1181
1182 kr = ipc_right_copyout(space, name, entry,
1183 msgt_name, IPC_OBJECT_COPYOUT_FLAGS_NONE, NULL, NULL, object);
1184
1185 /* object is unlocked */
1186 is_write_unlock(space);
1187
1188 #if IMPORTANCE_INHERITANCE
1189 /*
1190 * Add the assertions to the task that we captured before
1191 */
1192 if (task_imp != IIT_NULL) {
1193 ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
1194 ipc_importance_task_release(task_imp);
1195 }
1196 #endif /* IMPORTANCE_INHERITANCE */
1197
1198 return kr;
1199 }
1200
1201 /*
1202 * Routine: ipc_object_copyout_dest
1203 * Purpose:
1204 * Translates/consumes the destination right of a message.
1205 * This is unlike normal copyout because the right is consumed
1206 * in a funny way instead of being given to the receiving space.
1207 * The receiver gets his name for the port, if he has receive
1208 * rights, otherwise MACH_PORT_NULL.
1209 * Conditions:
1210 * The object is locked and active. Nothing else locked.
1211 * The object is unlocked and loses a reference.
1212 */
1213
1214 void
ipc_object_copyout_dest(ipc_space_t space,ipc_object_t object,mach_msg_type_name_t msgt_name,mach_port_name_t * namep)1215 ipc_object_copyout_dest(
1216 ipc_space_t space,
1217 ipc_object_t object,
1218 mach_msg_type_name_t msgt_name,
1219 mach_port_name_t *namep)
1220 {
1221 mach_port_name_t name;
1222
1223 assert(IO_VALID(object));
1224 assert(io_active(object));
1225
1226 /*
1227 * If the space is the receiver/owner of the object,
1228 * then we quietly consume the right and return
1229 * the space's name for the object. Otherwise
1230 * we destroy the right and return MACH_PORT_NULL.
1231 */
1232
1233 switch (msgt_name) {
1234 case MACH_MSG_TYPE_PORT_SEND: {
1235 ipc_port_t port = ip_object_to_port(object);
1236 ipc_notify_nsenders_t nsrequest = { };
1237
1238 if (ip_in_space(port, space)) {
1239 name = ip_get_receiver_name(port);
1240 } else {
1241 name = MACH_PORT_NULL;
1242 }
1243
1244 assert(port->ip_srights > 0);
1245 if (--port->ip_srights == 0) {
1246 nsrequest = ipc_notify_no_senders_prepare(port);
1247 }
1248 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1249 /* port unlocked */
1250
1251 ipc_notify_no_senders_emit(nsrequest);
1252
1253 ip_release(port);
1254 break;
1255 }
1256
1257 case MACH_MSG_TYPE_PORT_SEND_ONCE: {
1258 ipc_port_t port = ip_object_to_port(object);
1259
1260 assert(port->ip_sorights > 0);
1261
1262 if (ip_in_space(port, space)) {
1263 /* quietly consume the send-once right */
1264 port->ip_sorights--;
1265 name = ip_get_receiver_name(port);
1266 ipc_port_clear_sync_rcv_thread_boost_locked(port);
1267 /* port unlocked */
1268 ip_release(port);
1269 } else {
1270 /*
1271 * A very bizarre case. The message
1272 * was received, but before this copyout
1273 * happened the space lost receive rights.
1274 * We can't quietly consume the soright
1275 * out from underneath some other task,
1276 * so generate a send-once notification.
1277 */
1278
1279 ipc_notify_send_once_and_unlock(port);
1280 name = MACH_PORT_NULL;
1281 }
1282
1283 break;
1284 }
1285
1286 default:
1287 panic("ipc_object_copyout_dest: strange rights");
1288 name = MACH_PORT_DEAD;
1289 }
1290
1291 *namep = name;
1292 }
1293
1294 static_assert(offsetof(struct ipc_object_waitq, iowq_waitq) ==
1295 offsetof(struct ipc_port, ip_waitq));
1296 static_assert(offsetof(struct ipc_object_waitq, iowq_waitq) ==
1297 offsetof(struct ipc_pset, ips_wqset));
1298
1299 /*
1300 * Routine: ipc_object_lock
1301 * Purpose:
1302 * Validate, then acquire a lock on an ipc object
1303 */
1304 void
ipc_object_lock(ipc_object_t io)1305 ipc_object_lock(ipc_object_t io)
1306 {
1307 ipc_object_validate(io);
1308 waitq_lock(io_waitq(io));
1309 }
1310
1311 __abortlike
1312 static void
ipc_object_validate_preflight_panic(ipc_object_t io)1313 ipc_object_validate_preflight_panic(ipc_object_t io)
1314 {
1315 panic("ipc object %p is neither a port or a port-set", io);
1316 }
1317
1318 /*
1319 * Routine: ipc_object_lock_allow_invalid
1320 * Purpose:
1321 * Speculatively try to lock an object in an undefined state.
1322 *
1323 * This relies on the fact that IPC object memory is allocated
1324 * from sequestered zones, so at a given address, one can find:
1325 * 1. a valid object,
1326 * 2. a freed or invalid (uninitialized) object,
1327 * 3. unmapped memory.
1328 *
1329 * (2) is possible because the zone is made with ZC_ZFREE_CLEARMEM which
1330 * ensures freed elements are always zeroed.
1331 *
1332 * (3) is a direct courtesy of waitq_lock_allow_invalid().
1333 *
1334 * In order to disambiguate (1) from (2), we use the "waitq valid"
1335 * bit which is part of the lock. When that bit is absent,
1336 * waitq_lock() will function as expected, but
1337 * waitq_lock_allow_invalid() will not.
1338 *
1339 * Objects are then initialized and destroyed carefully so that
1340 * this "valid bit" is only set when the object invariants are
1341 * respected.
1342 *
1343 * Returns:
1344 * true: the lock was acquired
1345 * false: the object was freed or not initialized.
1346 */
1347 bool
ipc_object_lock_allow_invalid(ipc_object_t orig_io)1348 ipc_object_lock_allow_invalid(ipc_object_t orig_io)
1349 {
1350 struct waitq *orig_wq = io_waitq(orig_io);
1351 struct waitq *wq = pgz_decode_allow_invalid(orig_wq, ZONE_ID_ANY);
1352
1353 switch (zone_id_for_element(wq, sizeof(*wq))) {
1354 case ZONE_ID_IPC_PORT:
1355 case ZONE_ID_IPC_PORT_SET:
1356 break;
1357 default:
1358 #if CONFIG_PROB_GZALLOC
1359 if (orig_wq != wq) {
1360 /*
1361 * The element was PGZ protected, and the translation
1362 * returned another type than port or port-set, or
1363 * ZONE_ID_INVALID (wq is NULL).
1364 *
1365 * We have to allow this skew, and assumed the slot
1366 * has held a now freed port/port-set.
1367 */
1368 return false;
1369 }
1370 #endif /* CONFIG_PROB_GZALLOC */
1371 ipc_object_validate_preflight_panic(orig_io);
1372 }
1373
1374 if (__probable(waitq_lock_allow_invalid(wq))) {
1375 ipc_object_validate(io_from_waitq(wq));
1376 #if CONFIG_PROB_GZALLOC
1377 if (__improbable(wq != orig_wq &&
1378 wq != pgz_decode_allow_invalid(orig_wq, ZONE_ID_ANY))) {
1379 /*
1380 * This object is no longer held in the slot,
1381 * whatever this object is, it's not the droid
1382 * we're looking for. Pretend we failed the lock.
1383 */
1384 waitq_unlock(wq);
1385 return false;
1386 }
1387 #endif /* CONFIG_PROB_GZALLOC */
1388 return true;
1389 }
1390 return false;
1391 }
1392
1393 /*
1394 * Routine: ipc_object_lock_try
1395 * Purpose:
1396 * Validate, then try to acquire a lock on an object,
1397 * fail if there is an existing busy lock
1398 */
1399 bool
ipc_object_lock_try(ipc_object_t io)1400 ipc_object_lock_try(ipc_object_t io)
1401 {
1402 ipc_object_validate(io);
1403 return waitq_lock_try(io_waitq(io));
1404 }
1405
1406 /*
1407 * Routine: ipc_object_unlock
1408 * Purpose:
1409 * Unlocks the given object.
1410 */
1411 void
ipc_object_unlock(ipc_object_t io)1412 ipc_object_unlock(ipc_object_t io)
1413 {
1414 waitq_unlock(io_waitq(io));
1415 }
1416