/* * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * NOTICE: This file was modified by McAfee Research in 2004 to introduce * support for mandatory and extensible security protections. This notice * is included in support of clause 2.2 (b) of the Apple Public License, * Version 2.0. * Copyright (c) 2005 SPARTA, Inc. */ /* */ /* * File: ipc/ipc_kmsg.h * Author: Rich Draves * Date: 1989 * * Definitions for kernel messages. */ #ifndef _IPC_IPC_KMSG_H_ #define _IPC_IPC_KMSG_H_ #include #include #include #include #include #include #include #include #include #include /* * This structure is only the header for a kmsg buffer; * the actual buffer is normally larger. The rest of the buffer * holds the body of the message. * * In a kmsg, the port fields hold pointers to ports instead * of port names. These pointers hold references. * * The ikm_header.msgh_remote_port field is the destination * of the message. */ /* * A kmsg can be in one of the following four layouts * * @see for a visual representation. */ __enum_decl(ipc_kmsg_type_t, uint8_t, { /* * IKM_TYPE_ALL_INLINED: The entire message (and aux) is allocated inline. * mach_msg_header_t is immediately after the kmsg header. An optional aux * may be following the inline message proper. */ IKM_TYPE_ALL_INLINED = 0, /* * IKM_TYPE_UDATA_OOL: Message header and descriptors are allocated inline, * and message data, trailer, and aux are in buffer pointed to by ikm_udata. * mach_msg_header_t is immediately after the kmsg header. */ IKM_TYPE_UDATA_OOL = 1, /* * IKM_TYPE_KDATA_OOL: The entire message is allocated out-of-line. * {ikm_kdata, ikm_kdata_size} specifies the address and size * of the allocation. * * There is no aux data. */ IKM_TYPE_KDATA_OOL = 2, /* * IKM_TYPE_ALL_OOL: Everything is allocated out-of-line. Message header * and descriptors are allocated from typed kernel heap (kalloc_type) * and pointed at by ikm_kdata. The message data, trailer, and aux are * in data buffer pointed to by ikm_udata. */ IKM_TYPE_ALL_OOL = 3 }); #define IKM_ALLOC_SIZE 256 #define IKM_SMALL_MSG_SIZE 168 /* for !IKM_TYPE_ALL_INLINED */ #define IKM_BIG_MSG_SIZE 192 /* for IKM_TYPE_ALL_INLINED */ /* used by mk_timer to prevent the message from being freed */ __options_closed_decl(ipc_kmsg_keep_alive_t, uint8_t, { IKM_KEEP_ALIVE_NONE = 0x0, /* keep-alive not used on this message */ IKM_KEEP_ALIVE_OWNED = 0x1, /* keep-alive used, owned by the subsystem */ IKM_KEEP_ALIVE_IN_USE = 0x2, /* keep-alive used, message is in flight */ }); struct ipc_kmsg { queue_chain_t ikm_link; ipc_port_t XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_voucher_port") ikm_voucher_port; /* voucher port carried */ struct ipc_importance_elem *ikm_importance; /* inherited from */ queue_chain_t ikm_inheritance; /* inherited from link */ #if MACH_FLIPC struct mach_node *ikm_node; /* originating node - needed for ack */ #endif uint16_t ikm_aux_size; /* size reserved for auxiliary data */ ipc_kmsg_keep_alive_t ikm_keep_alive; /* only used for IKM_TYPE_ALL_INLINED */ uint8_t __ikm_padding; uint32_t ikm_ppriority; /* pthread priority of this kmsg */ uint32_t ikm_signature; /* sig for all kernel-processed data */ ipc_object_copyin_flags_t ikm_flags; mach_msg_qos_t ikm_qos_override; /* qos override on this kmsg */ mach_msg_type_name_t ikm_voucher_type: 6; /* disposition type the voucher came in with */ ipc_kmsg_type_t ikm_type: 2; union { /* * - ikm_big_data (IKM_TYPE_ALL_INLINED) * inline buffer used for everything * * - ikm_small_data (IKM_TYPE_UDATA_OOL) * inline buffer used for the kernel data/header * * - ikm_kdata{,_size} (IKM_TYPE_KDATA_OOL, IKM_TYPE_ALL_OOL) * kernel data buffer and size (with kernel pointers). * * - ikm_udata{,_size} (IKM_TYPE_UDATA_OOL, IKM_TYPE_ALL_OOL) * user data buffer and size (no kernel pointers). * * Note: ikm_big_data and ikm_small_data are at the same address * so that `ikm_header()` only has two cases. * * dPAC-ed pointers follow so that linear overflows are * unlikely to be exploitable. */ uint32_t ikm_big_data[IKM_BIG_MSG_SIZE / 4]; struct { uint32_t ikm_small_data[IKM_SMALL_MSG_SIZE / 4]; void *XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_kdata") ikm_kdata; void *XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_udata") ikm_udata; mach_msg_size_t ikm_kdata_size; mach_msg_size_t ikm_udata_size; } __attribute__((packed, aligned(4))); }; }; static_assert(sizeof(struct ipc_kmsg) == IKM_ALLOC_SIZE); static_assert(offsetof(struct ipc_kmsg, ikm_big_data) + IKM_BIG_MSG_SIZE == IKM_ALLOC_SIZE); static_assert(offsetof(struct ipc_kmsg, ikm_small_data) + IKM_SMALL_MSG_SIZE + 2 * sizeof(void *) + 2 * sizeof(mach_msg_size_t) == IKM_ALLOC_SIZE); KALLOC_TYPE_VAR_DECLARE(KT_IPC_KMSG_KDATA_OOL); /* * Exported interfaces */ typedef circle_queue_t ipc_kmsg_queue_t; #define ipc_kmsg_queue_init(queue) circle_queue_init(queue) #define ipc_kmsg_queue_empty(queue) circle_queue_empty(queue) #define ipc_kmsg_queue_element(elem) \ cqe_element(elem, struct ipc_kmsg, ikm_link) #define ipc_kmsg_queue_first(queue) \ cqe_queue_first(queue, struct ipc_kmsg, ikm_link) #define ipc_kmsg_queue_next(queue, elt) \ cqe_queue_next(&(elt)->ikm_link, queue, struct ipc_kmsg, ikm_link) #define ipc_kmsg_enqueue(queue, kmsg) \ circle_enqueue_tail(queue, &(kmsg)->ikm_link) #define ipc_kmsg_rmqueue(queue, kmsg) \ circle_dequeue(queue, &(kmsg)->ikm_link) extern bool ipc_kmsg_enqueue_qos( ipc_kmsg_queue_t queue, ipc_kmsg_t kmsg); extern bool ipc_kmsg_override_qos( ipc_kmsg_queue_t queue, ipc_kmsg_t kmsg, mach_msg_qos_t qos_ovr); /* Pull the (given) first kmsg out of a queue */ extern void ipc_kmsg_rmqueue_first( ipc_kmsg_queue_t queue, ipc_kmsg_t kmsg); __options_decl(ipc_kmsg_alloc_flags_t, uint32_t, { /* specify either user or kernel flag */ IPC_KMSG_ALLOC_USER = 0x0000, IPC_KMSG_ALLOC_KERNEL = 0x0001, IPC_KMSG_ALLOC_ZERO = 0x0002, IPC_KMSG_ALLOC_ALL_INLINE = 0x0004, IPC_KMSG_ALLOC_NOFAIL = 0x0008, IPC_KMSG_ALLOC_LINEAR = 0x0010, IPC_KMSG_ALLOC_USE_KEEP_ALIVE = 0x0020, /* must call ipc_kmsg_keep_alive_abandon () */ }); /* Allocate a kernel message */ extern ipc_kmsg_t ipc_kmsg_alloc( mach_msg_size_t msg_size, mach_msg_size_t aux_size, mach_msg_size_t desc_count, ipc_kmsg_alloc_flags_t flags); /* Free a kernel message buffer */ extern void ipc_kmsg_free( ipc_kmsg_t kmsg); extern void ipc_kmsg_clean_descriptors( mach_msg_kdescriptor_t * kdesc __counted_by(number), mach_msg_type_number_t number); extern void ipc_kmsg_sign_descriptors( mach_msg_kdescriptor_t *kdesc, mach_msg_size_t dsc_count); __options_decl(ipc_kmsg_destroy_flags_t, uint32_t, { IPC_KMSG_DESTROY_ALL = 0x0000, IPC_KMSG_DESTROY_SKIP_REMOTE = 0x0001, IPC_KMSG_DESTROY_SKIP_LOCAL = 0x0002, IPC_KMSG_DESTROY_NOT_SIGNED = 0x0004, }); /* Destroy kernel message */ extern void ipc_kmsg_destroy( ipc_kmsg_t kmsg, ipc_kmsg_destroy_flags_t flags); /* Enqueue kernel message for deferred destruction */ extern bool ipc_kmsg_delayed_destroy( ipc_kmsg_t kmsg); /* Enqueue queue of kernel messages for deferred destruction */ extern bool ipc_kmsg_delayed_destroy_queue( ipc_kmsg_queue_t queue); /* Process all the delayed message destroys */ extern void ipc_kmsg_reap_delayed(void); /* Try to mark a message as in use (setting IKM_KEEP_ALIVE_IN_USE). */ extern bool ipc_kmsg_keep_alive_try_reusing( ipc_kmsg_t kmsg); /* Abandons a message that was allocated with IPC_KMSG_ALLOC_USE_KEEP_ALIVE. */ extern void ipc_kmsg_keep_alive_abandon( ipc_kmsg_t kmsg); /* get the unshifted message header of a kmsg */ extern mach_msg_header_t *ikm_header( ipc_kmsg_t kmsg); /* get the start address of user data (after the last descriptor) for a kmsg */ extern void *ikm_udata( ipc_kmsg_t kmsg, mach_msg_size_t desc_count, bool complex); extern void * ikm_udata_from_header( ipc_kmsg_t kmsg); /* Allocate a kernel message buffer and copy a kernel message to the buffer */ extern mach_msg_return_t ipc_kmsg_get_from_kernel( mach_msg_header_t *msg, mach_msg_size_t size, mach_msg_option64_t options, ipc_kmsg_t *kmsgp); /* Send a message to a port */ extern mach_msg_return_t ipc_kmsg_send( ipc_kmsg_t kmsg, mach_msg_option64_t options, mach_msg_timeout_t timeout_val); /* Copy a kernel message buffer to a user message */ extern mach_msg_return_t ipc_kmsg_put_to_user( ipc_kmsg_t kmsg, /* scalar or vector */ mach_msg_recv_bufs_t *recv_bufs, mach_msg_recv_result_t *msgr, mach_msg_option64_t option, vm_map_t map, mach_msg_return_t mr); /* Copy a kernel message buffer to a kernel message */ extern void ipc_kmsg_put_to_kernel( mach_msg_header_t *msg, mach_msg_option64_t options, ipc_kmsg_t kmsg, mach_msg_size_t size); /* Copyin data, port rights and out-of-line memory from a user message */ extern mach_msg_return_t ipc_kmsg_copyin_from_user( ipc_kmsg_t kmsg, mach_msg_send_uctx_t *send_uctx, ipc_space_t space, vm_map_t map, mach_msg_priority_t priority, mach_msg_option64_t *optionp); /* Copyin port rights and out-of-line memory from a kernel message */ extern mach_msg_return_t ipc_kmsg_copyin_from_kernel( ipc_kmsg_t kmsg); /* Copyout the header and body to a user message */ extern mach_msg_return_t ipc_kmsg_copyout( ipc_kmsg_t kmsg, ipc_space_t space, vm_map_t map, mach_msg_option64_t option); /* Copyout port rights and out-of-line memory to a user message, * not reversing the ports in the header */ extern mach_msg_return_t ipc_kmsg_copyout_pseudo( ipc_kmsg_t kmsg, ipc_space_t space, vm_map_t map); /* Compute size of message as copied out to the specified space/map */ extern mach_msg_size_t ipc_kmsg_copyout_size( ipc_kmsg_t kmsg, vm_map_t map); /* Copyout the destination port in the message */ extern void ipc_kmsg_copyout_dest_to_user( ipc_kmsg_t kmsg, ipc_space_t space); /* kernel's version of ipc_kmsg_copyout_dest_to_user */ extern void ipc_kmsg_copyout_dest_to_kernel( ipc_kmsg_t kmsg, ipc_space_t space); /* Returns a pointer to a thread group in the kmsg if any. Caller has a * reference to the kmsg */ extern struct thread_group *ipc_kmsg_get_thread_group( ipc_kmsg_t kmsg); extern mach_msg_trailer_size_t ipc_kmsg_trailer_size( mach_msg_option64_t option, vm_map_t map); extern mach_msg_max_trailer_t *ipc_kmsg_get_trailer( ipc_kmsg_t kmsg); extern void ipc_kmsg_set_voucher_port( ipc_kmsg_t kmsg, ipc_port_t voucher, mach_msg_type_name_t type); extern ipc_port_t ipc_kmsg_get_voucher_port( ipc_kmsg_t kmsg); extern void ipc_kmsg_clear_voucher_port( ipc_kmsg_t kmsg); /* checks signature and returns descriptor count */ extern mach_msg_size_t ipc_kmsg_validate_signature( ipc_kmsg_t kmsg) __result_use_check; #define moved_provisional_reply_port(port_type, port) \ (port_type == MACH_MSG_TYPE_MOVE_RECEIVE && IP_VALID(port) && ip_is_provisional_reply_port(port)) \ extern void send_prp_telemetry(int msgh_id); #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) extern void ipc_kmsg_trace_send( ipc_kmsg_t kmsg, mach_msg_option64_t option); #else #define ipc_kmsg_trace_send(a, b) do { } while (0) #endif #if (DEVELOPMENT || DEBUG) vm_offset_t ikm_kdata_end(ipc_kmsg_t kmsg); #endif #endif /* _IPC_IPC_KMSG_H_ */