xref: /xnu-12377.61.12/osfmk/ipc/ipc_object.h (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*
2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 /*
32  * Mach Operating System
33  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34  * All Rights Reserved.
35  *
36  * Permission to use, copy, modify and distribute this software and its
37  * documentation is hereby granted, provided that both the copyright
38  * notice and this permission notice appear in all copies of the
39  * software, derivative works or modified versions, and any portions
40  * thereof, and that both notices appear in supporting documentation.
41  *
42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45  *
46  * Carnegie Mellon requests users of this software to return to
47  *
48  *  Software Distribution Coordinator  or  [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  */
62 /*
63  */
64 /*
65  *	File:	ipc/ipc_object.h
66  *	Author:	Rich Draves
67  *	Date:	1989
68  *
69  *	Definitions for IPC objects, for which tasks have capabilities.
70  */
71 
72 #ifndef _IPC_IPC_OBJECT_H_
73 #define _IPC_IPC_OBJECT_H_
74 
75 #include <stdbool.h>
76 #include <os/atomic_private.h>
77 #include <mach/kern_return.h>
78 #include <mach/message.h>
79 #include <kern/locks.h>
80 #include <kern/macro_help.h>
81 #include <kern/assert.h>
82 #include <kern/waitq.h>
83 #include <kern/zalloc.h>
84 #include <ipc/ipc_types.h>
85 #include <libkern/OSAtomic.h>
86 
87 __BEGIN_DECLS __ASSUME_PTR_ABI_SINGLE_BEGIN
88 #pragma GCC visibility push(hidden)
89 
90 typedef natural_t ipc_object_bits_t;
91 
92 __options_closed_decl(ipc_object_copyout_flags_t, uint32_t, {
93 	IPC_OBJECT_COPYOUT_FLAGS_NONE                 = 0x0,
94 	IPC_OBJECT_COPYOUT_FLAGS_PINNED               = 0x1,
95 });
96 
97 __options_closed_decl(ipc_object_copyin_flags_t, uint16_t, {
98 	IPC_OBJECT_COPYIN_FLAGS_NONE                          = 0x0,
99 	IPC_OBJECT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND          = 0x1, /* Dest port contains an immovable send right */
100 	IPC_OBJECT_COPYIN_FLAGS_DEADOK                        = 0x2,
101 	IPC_OBJECT_COPYIN_FLAGS_DEST_EXTRA_COPY               = 0x4,
102 	IPC_OBJECT_COPYIN_FLAGS_DEST_EXTRA_MOVE               = 0x8,
103 });
104 
105 __enum_decl(ipc_copyin_op_t, uint16_t, {
106 	IPC_COPYIN_REASON_NONE,
107 	IPC_COPYIN_KMSG_DESTINATION,
108 	IPC_COPYIN_KMSG_REPLY,
109 	IPC_COPYIN_KMSG_VOUCHER,
110 	IPC_COPYIN_KMSG_PORT_DESCRIPTOR,
111 	IPC_COPYIN_KMSG_GUARDED_PORT_DESCRIPTOR,
112 	IPC_COPYIN_KMSG_OOL_PORT_ARRAY_DESCRIPTOR,
113 	IPC_COPYIN_KERNEL_DESTINATION,
114 });
115 
116 /*!
117  * @typedef ipc_object_state_t
118  *
119  * @abstract
120  *   Denotes the state of an IPC object.
121  *
122  * @const IO_STATE_INACTIVE
123  *   The object is dead.
124  *
125  *   Inactive ports have:
126  *   - the receiver union is using the ip_timestamp field,
127  *     holding a timestamp of when ipc_port_mark_inactive()
128  *     was called;
129  *   - ip_receiver_name set to MACH_PORT_NULL.
130  *
131  * @const IO_STATE_IN_SPACE
132  *   The object is owned by some IPC space.
133  *
134  *   In-space ports have:
135  *   - the receiver union is using the ip_receiver field, pointing
136  *     to the (possibly special) space holding the receive right for this port;
137  *   - ip_receiver_name set to a non MACH_PORT_NULL value corresponding to the
138  *     name of the receive right for this port within the corresponding space
139  *     (MACH_PORT_SPECIAL_DEFAULT is used for special spaces).
140  *
141  * @const IO_STATE_IN_SPACE_IMMOVABLE
142  *   The object is owned by some IPC space, and can't move out of it.
143  *
144  *   @see IO_STATE_IN_SPACE for details of the receiver fields.
145  *
146  * @const IO_STATE_IN_LIMBO
147  *   The object is a port and is currently being manipulated by the kernel
148  *   and is in between states.
149  *
150  *   In limbo ports have:
151  *   - the receiver union set to 0;
152  *   - ip_receiver_name set to MACH_PORT_NULL.
153  *
154  * @const IO_STATE_IN_LIMBO_PD
155  *   The object is a port and is currently being manipulated by the kernel
156  *   before being enqueued into a port-destroyed notification message.
157  *
158  *   @see IO_STATE_IN_LIMBO_PD for details of the receiver fields.
159  *
160  * @const IO_STATE_IN_TRANSIT
161  *   The object is a port and is enqueued on some port inside a message.
162  *
163  *   In-transit ports have:
164  *   - the receiver union using the ip_destination field, with a reference
165  *     owning pointer to a valid port;
166  *   - ip_receiver_name set to MACH_PORT_NULL.
167  *
168  * @const IO_STATE_IN_TRANSIT_PD
169  *   The object is a port and is enqueued on some port inside a port-destroyed
170  *   notification message.
171  *
172  *   @see IO_STATE_IN_TRANSIT for details on the receiver fields.
173  */
174 __enum_closed_decl(ipc_object_state_t, uint8_t, {
175 	IO_STATE_INACTIVE,
176 	IO_STATE_IN_SPACE,
177 	IO_STATE_IN_SPACE_IMMOVABLE,
178 	IO_STATE_IN_LIMBO,
179 	IO_STATE_IN_LIMBO_PD,
180 	IO_STATE_IN_TRANSIT,
181 	IO_STATE_IN_TRANSIT_PD,
182 });
183 
184 /*!
185  * @brief
186  * The header of an IPC object (port or pset).
187  *
188  * @discussion
189  * This header must be at the start of any IPC object that can be held
190  * in a port-space (currently, IPC ports and IPC port sets).
191  *
192  * @field io_type
193  * The type of the IPC object, this value is an immutable property
194  * of the IPC object and can be read without holding any locks.
195  *
196  * @field io_state
197  * This field denots the state of the object, it is mutable,
198  * and must be read under the object lock held.
199  *
200  * Furthermore, it can be autnenticated by extracting the IPC object label
201  * from the object (using @c io_label_get()), which is the preferred way
202  * to look at this field.
203  *
204  * @field io_filtered
205  * Whether this port uses IPC filtering, this is an immutable property
206  * of the object and can be consulted without holding any lock.
207  *
208  * @field io_label_lock
209  * This is used to track extent IPC object labels for this object,
210  * and should not be consulted or manipulated directly.
211  *
212  * @field io_references
213  * The refcount for this IPC object (meaningless on a IPC object label).
214  *
215  * @field iol_pointer
216  * This union holds the actual label for an IPC object, it is signed
217  * and must be read by using the @c io_label_get() accessor. The pointer
218  * is not stable during the lifecycle of the object.
219  */
220 struct ipc_object {
221 	union {
222 		struct {
223 			ipc_object_type_t       io_type;
224 			ipc_object_state_t      io_state     : 3;
225 			uint8_t                 io_filtered  : 1;
226 			uint8_t                 __io_unused1 : 4;
227 			/* dPAC modifier boundary */
228 			/*
229 			 * the io_label_lock supports io_label_get/put,
230 			 * it could be a single bit, but a full byte
231 			 * yields much better codegen, and the bits are unused.
232 			 */
233 			bool                    io_label_lock;
234 			uint8_t                 __io_unused2;
235 		};
236 		ipc_object_bits_t               io_bits;
237 	};
238 	os_ref_atomic_t                         io_references;
239 	union {
240 		/* these are dPACed when on a port header */
241 		const void                      *iol_pointer;
242 		unsigned long                    iol_value;
243 		struct ipc_service_port_label   *iol_service;
244 		struct ipc_conn_port_label      *iol_connection;
245 		struct ipc_kobject_label        *iol_kobject;
246 		struct mk_timer                 *iol_mktimer;
247 	};
248 };
249 
250 /*!
251  * @brief
252  * Type used to hold details about a resolved IPC object type and label.
253  *
254  * @discussion
255  * This is a non-copyable, movable value type which is never stored
256  * on any data structure.
257  *
258  * It is also required that at most one such structure is extant for a given
259  * port at any point in time, and that the port lock is held for the whole
260  * time this structure is live. This is enforced at runtime.
261  *
262  * The core API to acquire such a type is @c io_label_get(), and when it is
263  * no longer used, @c ip_label_put() can be used to denote it's no longer
264  * valid, and the value will be poisoned. @c ip_label_set() can also be used
265  * if the value is going to be updated, which also consumes the label.
266  *
267  * Passing this structure by value to functions that will not call
268  * @c ip_label_put() or release the port lock is a valid and even encouraged
269  * practice, as this is a much better calling convention.
270  */
271 typedef struct ipc_object       ipc_object_label_t;
272 
273 #define IPC_OBJECT_LABEL(otype, ...) \
274 	((ipc_object_label_t){ \
275 	        .io_type = otype, \
276 	        .io_state = IO_STATE_IN_SPACE, \
277 	        ## __VA_ARGS__, \
278 	})
279 
280 #define IPC_OBJECT_LABEL_INVALID \
281 	((ipc_object_label_t){ \
282 	        .io_bits = ~0u, \
283 	        .io_references = ~0u, \
284 	        .iol_value = ~0ul, \
285 	})
286 
287 #define io_type(io)             ((io)->io_type)
288 #define io_is_pset_type(t)      ((t) == IOT_PORT_SET)
289 #define io_is_any_port_type(t)  (!io_is_pset_type(t))
290 #define io_is_kobject_type(t)   ((t) >= __IKOT_FIRST)
291 #define io_is_any_port(io)      io_is_any_port_type(io_type(io))
292 #define io_is_pset(io)          io_is_pset_type(io_type(io))
293 #define io_is_kobject(io)       io_is_kobject_type(io_type(io))
294 
295 ZONE_DECLARE_ID(ZONE_ID_IPC_PORT, struct ipc_port);
296 ZONE_DECLARE_ID(ZONE_ID_IPC_PORT_SET, struct ipc_pset);
297 
298 /*
299  * Here we depend on all ipc_objects being an ipc_wait_queue
300  *
301  * this type doesn't exist and is only used to do math
302  */
303 struct ipc_object_waitq {
304 	struct ipc_object       iowq_object;
305 	struct waitq            iowq_waitq;
306 };
307 #define io_waitq(io) \
308 	(&__container_of(io, struct ipc_object_waitq, iowq_object)->iowq_waitq)
309 #define io_from_waitq(waitq) \
310 	(&__container_of(waitq, struct ipc_object_waitq, iowq_waitq)->iowq_object)
311 
312 #define io_unlock(io)                   ipc_object_unlock(io)
313 #define io_unlock_nocheck(io)           waitq_unlock(io_waitq(io))
314 #define io_lock_held(io)                assert(waitq_held(io_waitq(io)))
315 #define io_lock_held_kdp(io)            waitq_held(io_waitq(io))
316 #define io_lock_allow_invalid(io)       ipc_object_lock_allow_invalid(io)
317 
318 #define io_reference(io)                ipc_object_reference(io)
319 #define io_release(io)                  ipc_object_release(io)
320 #define io_release_safe(io)             ipc_object_release_safe(io)
321 #define io_release_live(io)             ipc_object_release_live(io)
322 
323 static inline bool
io_state_active(ipc_object_state_t state)324 io_state_active(ipc_object_state_t state)
325 {
326 	return state != IO_STATE_INACTIVE;
327 }
328 
329 static inline bool
io_state_in_space(ipc_object_state_t state)330 io_state_in_space(ipc_object_state_t state)
331 {
332 	switch (state) {
333 	case IO_STATE_IN_SPACE:
334 	case IO_STATE_IN_SPACE_IMMOVABLE:
335 		return true;
336 	default:
337 		return false;
338 	}
339 }
340 
341 static inline bool
io_state_in_limbo(ipc_object_state_t state)342 io_state_in_limbo(ipc_object_state_t state)
343 {
344 	switch (state) {
345 	case IO_STATE_IN_LIMBO:
346 	case IO_STATE_IN_LIMBO_PD:
347 		return true;
348 	default:
349 		return false;
350 	}
351 }
352 
353 static inline bool
io_state_in_transit(ipc_object_state_t state)354 io_state_in_transit(ipc_object_state_t state)
355 {
356 	switch (state) {
357 	case IO_STATE_IN_TRANSIT:
358 	case IO_STATE_IN_TRANSIT_PD:
359 		return true;
360 	default:
361 		return false;
362 	}
363 }
364 
365 static inline bool
io_state_is_moving(ipc_object_state_t state)366 io_state_is_moving(ipc_object_state_t state)
367 {
368 	switch (state) {
369 	case IO_STATE_IN_LIMBO:
370 	case IO_STATE_IN_LIMBO_PD:
371 	case IO_STATE_IN_TRANSIT:
372 	case IO_STATE_IN_TRANSIT_PD:
373 		return true;
374 	default:
375 		return false;
376 	}
377 }
378 
379 __result_use_check
380 __attribute__((always_inline))
381 static inline ipc_object_label_t
__io_label_validate(ipc_object_t io,ipc_object_label_t label,bool lock)382 __io_label_validate(ipc_object_t io, ipc_object_label_t label, bool lock)
383 {
384 	if (lock) {
385 		io_lock_held(io);
386 		release_assert(!io->io_label_lock);
387 		io->io_label_lock = true;
388 	}
389 
390 	label.iol_pointer = ptrauth_auth_data(label.iol_pointer,
391 	    ptrauth_key_process_independent_data,
392 	    ptrauth_blend_discriminator(io, (uint32_t)(label.io_bits +
393 	    ptrauth_string_discriminator("ipc_object.iol_pointer"))));
394 
395 #if __has_feature(ptrauth_calls)
396 	/*
397 	 * io_label() must guarantee that we always do the PAC evaluation,
398 	 * as callers even if they do not use bits or the pointer value,
399 	 * expect this validation to take place.
400 	 */
401 	__compiler_materialize_and_prevent_reordering_on(label.iol_pointer);
402 #endif
403 
404 	return label;
405 }
406 
407 __result_use_check
408 __attribute__((always_inline, overloadable))
409 static inline ipc_object_label_t
io_label_get(ipc_object_t io,ipc_object_type_t otype)410 io_label_get(ipc_object_t io, ipc_object_type_t otype)
411 {
412 	ipc_object_label_t label;
413 
414 	label = *io;
415 	label.io_type = otype;
416 
417 	return __io_label_validate(io, label, true);
418 }
419 
420 __result_use_check
421 __attribute__((always_inline, overloadable))
422 static inline ipc_object_label_t
io_label_get(ipc_object_t io)423 io_label_get(ipc_object_t io)
424 {
425 	return __io_label_validate(io, *io, true);
426 }
427 
428 __attribute__((always_inline, overloadable))
429 static inline ipc_object_label_t
io_label_peek_kdp(ipc_object_t io)430 io_label_peek_kdp(ipc_object_t io)
431 {
432 	assert(!io_lock_held_kdp(io));
433 	return __io_label_validate(io, *io, false);
434 }
435 
436 __attribute__((always_inline))
437 static inline void
io_label_init(ipc_object_t io,ipc_object_label_t label)438 io_label_init(ipc_object_t io, ipc_object_label_t label)
439 {
440 	atomic_store_explicit(os_cast_to_atomic_pointer(&io->io_bits),
441 	    label.io_bits, memory_order_relaxed);
442 
443 	io->iol_pointer = ptrauth_sign_unauthenticated(label.iol_pointer,
444 	    ptrauth_key_process_independent_data,
445 	    ptrauth_blend_discriminator(io, (uint32_t)(label.io_bits +
446 	    ptrauth_string_discriminator("ipc_object.iol_pointer"))));
447 }
448 
449 __attribute__((always_inline))
450 static inline void
io_label_set_and_put(ipc_object_t io,ipc_object_label_t * label)451 io_label_set_and_put(ipc_object_t io, ipc_object_label_t *label)
452 {
453 	release_assert(io->io_label_lock);
454 	io_lock_held(io);
455 
456 	io_label_init(io, *label);
457 	*label = IPC_OBJECT_LABEL_INVALID;
458 }
459 
460 __attribute__((always_inline))
461 static inline void
io_label_put(ipc_object_t io,ipc_object_label_t * label)462 io_label_put(ipc_object_t io, ipc_object_label_t *label)
463 {
464 	assert(io->io_type == label->io_type &&
465 	    io->io_state == label->io_state);
466 	release_assert(io->io_label_lock);
467 
468 	io->io_label_lock = false;
469 	*label = IPC_OBJECT_LABEL_INVALID;
470 }
471 
472 /*
473  * Exported interfaces
474  */
475 
476 extern bool ipc_object_lock_allow_invalid(
477 	ipc_object_t            object) __result_use_check;
478 
479 extern void ipc_object_unlock(
480 	ipc_object_t            object);
481 
482 extern void ipc_object_deallocate_register_queue(void);
483 
484 /* Take a reference to an object */
485 extern void ipc_object_reference(
486 	ipc_object_t            object);
487 
488 /* Release a reference to an object */
489 extern void ipc_object_release(
490 	ipc_object_t            object);
491 
492 extern void ipc_object_release_safe(
493 	ipc_object_t            object);
494 
495 /* Release a reference to an object that isn't the last one */
496 extern void ipc_object_release_live(
497 	ipc_object_t            object);
498 
499 /* Look up an object in a space */
500 extern kern_return_t ipc_object_translate(
501 	ipc_space_t             space,
502 	mach_port_name_t        name,
503 	mach_port_right_t       right,
504 	ipc_object_t           *objectp);
505 
506 /* Look up two objects in a space, locking them in the order described */
507 extern kern_return_t ipc_object_translate_port_pset(
508 	ipc_space_t             space,
509 	mach_port_name_t        port_name,
510 	ipc_port_t             *port,
511 	mach_port_name_t        pset_name,
512 	ipc_pset_t             *pset);
513 
514 /* Validate an object as belonging to the correct zone */
515 extern void ipc_object_validate(
516 	ipc_object_t            object,
517 	ipc_object_type_t       type);
518 
519 /* Allocate a dead-name entry */
520 extern kern_return_t ipc_object_alloc_dead(
521 	ipc_space_t         space,
522 	mach_port_name_t    *namep);
523 
524 /* Allocate an object */
525 extern kern_return_t ipc_object_alloc_entry(
526 	ipc_space_t         space,
527 	ipc_object_t        object,
528 	mach_port_name_t    *namep,
529 	ipc_entry_t         *entry);
530 
531 /* Allocate an object, with a specific name */
532 extern kern_return_t ipc_object_alloc_entry_with_name(
533 	ipc_space_t         space,
534 	mach_port_name_t    name,
535 	ipc_entry_t         *entry);
536 
537 /* Convert a send type name to a received type name */
538 extern mach_msg_type_name_t ipc_object_copyin_type(
539 	mach_msg_type_name_t    msgt_name);
540 
541 /* Copyin a capability from a space */
542 extern kern_return_t ipc_object_copyin(
543 	ipc_space_t             space,
544 	mach_port_name_t        name,
545 	mach_msg_type_name_t    msgt_name,
546 	ipc_object_copyin_flags_t copyin_flags,
547 	ipc_copyin_op_t         copyin_reason,
548 	mach_msg_guarded_port_descriptor_t *gdesc,
549 	ipc_port_t             *portp);
550 
551 /* Copyin a naked capability from the kernel */
552 extern void ipc_object_copyin_from_kernel(
553 	ipc_port_t              port,
554 	mach_msg_type_name_t    msgt_name);
555 
556 /* Destroy a naked capability */
557 extern void ipc_object_destroy(
558 	ipc_port_t              port,
559 	mach_msg_type_name_t    msgt_name);
560 
561 /* Destroy a naked destination capability */
562 extern void ipc_object_destroy_dest(
563 	ipc_port_t              port,
564 	mach_msg_type_name_t    msgt_name);
565 
566 /* Insert a send right into an object already in the current space */
567 extern kern_return_t ipc_object_insert_send_right(
568 	ipc_space_t             space,
569 	mach_port_name_t        name,
570 	mach_msg_type_name_t    msgt_name);
571 
572 /* Copyout a capability, placing it into a space */
573 extern kern_return_t ipc_object_copyout(
574 	ipc_space_t             space,
575 	ipc_port_t              port,
576 	mach_msg_type_name_t    msgt_name,
577 	ipc_object_copyout_flags_t flags,
578 	mach_msg_guarded_port_descriptor_t *gdesc,
579 	mach_port_name_t        *namep);
580 
581 /* Copyout a capability with a name, placing it into a space */
582 extern kern_return_t ipc_object_copyout_name(
583 	ipc_space_t             space,
584 	ipc_port_t              port,
585 	mach_msg_type_name_t    msgt_name,
586 	mach_port_name_t        name);
587 
588 /* Translate/consume the destination right of a message */
589 extern void ipc_object_copyout_dest(
590 	ipc_space_t             space,
591 	ipc_port_t              port,
592 	mach_msg_type_name_t    msgt_name,
593 	mach_port_name_t        *namep);
594 
595 /* Unpin the entry for a send right pointing to "object" */
596 extern void ipc_object_unpin(
597 	ipc_space_t             space,
598 	ipc_port_t              port);
599 
600 #pragma GCC visibility pop
601 __ASSUME_PTR_ABI_SINGLE_END __END_DECLS
602 
603 #endif  /* _IPC_IPC_OBJECT_H_ */
604