1 /* 2 * Copyright (c) 2000-2004 Apple Computer, 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 SPARTA, Inc. 62 */ 63 /* 64 */ 65 /* 66 * File: ipc/ipc_kmsg.h 67 * Author: Rich Draves 68 * Date: 1989 69 * 70 * Definitions for kernel messages. 71 */ 72 73 #ifndef _IPC_IPC_KMSG_H_ 74 #define _IPC_IPC_KMSG_H_ 75 76 #include <mach/vm_types.h> 77 #include <mach/message.h> 78 #include <kern/kern_types.h> 79 #include <kern/assert.h> 80 #include <kern/macro_help.h> 81 #include <kern/kalloc.h> 82 #include <kern/circle_queue.h> 83 #include <ipc/ipc_types.h> 84 #include <ipc/ipc_object.h> 85 #include <sys/kdebug.h> 86 87 /* 88 * This structure is only the header for a kmsg buffer; 89 * the actual buffer is normally larger. The rest of the buffer 90 * holds the body of the message. 91 * 92 * In a kmsg, the port fields hold pointers to ports instead 93 * of port names. These pointers hold references. 94 * 95 * The ikm_header.msgh_remote_port field is the destination 96 * of the message. 97 */ 98 99 /* 100 * A kmsg can be in one of the following four layouts 101 * 102 * @see <doc/mach_ipc/kmsg.md> for a visual representation. 103 */ 104 __enum_decl(ipc_kmsg_type_t, uint8_t, { 105 /* 106 * IKM_TYPE_ALL_INLINED: The entire message (and aux) is allocated inline. 107 * mach_msg_header_t is immediately after the kmsg header. An optional aux 108 * may be following the inline message proper. 109 */ 110 IKM_TYPE_ALL_INLINED = 0, 111 /* 112 * IKM_TYPE_UDATA_OOL: Message header and descriptors are allocated inline, 113 * and message data, trailer, and aux are in buffer pointed to by ikm_udata. 114 * mach_msg_header_t is immediately after the kmsg header. 115 */ 116 IKM_TYPE_UDATA_OOL = 1, 117 /* 118 * IKM_TYPE_KDATA_OOL: The entire message is allocated out-of-line. 119 * {ikm_kdata, ikm_kdata_size} specifies the address and size 120 * of the allocation. 121 * 122 * There is no aux data. 123 */ 124 IKM_TYPE_KDATA_OOL = 2, 125 /* 126 * IKM_TYPE_ALL_OOL: Everything is allocated out-of-line. Message header 127 * and descriptors are allocated from typed kernel heap (kalloc_type) 128 * and pointed at by ikm_kdata. The message data, trailer, and aux are 129 * in data buffer pointed to by ikm_udata. 130 */ 131 IKM_TYPE_ALL_OOL = 3 132 }); 133 134 #define IKM_ALLOC_SIZE 256 135 #define IKM_SMALL_MSG_SIZE 168 /* for !IKM_TYPE_ALL_INLINED */ 136 #define IKM_BIG_MSG_SIZE 192 /* for IKM_TYPE_ALL_INLINED */ 137 138 /* used by mk_timer to prevent the message from being freed */ 139 __options_closed_decl(ipc_kmsg_keep_alive_t, uint8_t, { 140 IKM_KEEP_ALIVE_NONE = 0x0, /* keep-alive not used on this message */ 141 IKM_KEEP_ALIVE_OWNED = 0x1, /* keep-alive used, owned by the subsystem */ 142 IKM_KEEP_ALIVE_IN_USE = 0x2, /* keep-alive used, message is in flight */ 143 }); 144 145 struct ipc_kmsg { 146 queue_chain_t ikm_link; 147 ipc_port_t XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_voucher_port") ikm_voucher_port; /* voucher port carried */ 148 struct ipc_importance_elem *ikm_importance; /* inherited from */ 149 queue_chain_t ikm_inheritance; /* inherited from link */ 150 #if MACH_FLIPC 151 struct mach_node *ikm_node; /* originating node - needed for ack */ 152 #endif 153 uint16_t ikm_aux_size; /* size reserved for auxiliary data */ 154 ipc_kmsg_keep_alive_t ikm_keep_alive; /* only used for IKM_TYPE_ALL_INLINED */ 155 uint8_t __ikm_padding; 156 uint32_t ikm_ppriority; /* pthread priority of this kmsg */ 157 uint32_t ikm_signature; /* sig for all kernel-processed data */ 158 ipc_object_copyin_flags_t ikm_flags; 159 mach_msg_qos_t ikm_qos_override; /* qos override on this kmsg */ 160 161 mach_msg_type_name_t ikm_voucher_type: 6; /* disposition type the voucher came in with */ 162 ipc_kmsg_type_t ikm_type: 2; 163 164 union { 165 /* 166 * - ikm_big_data (IKM_TYPE_ALL_INLINED) 167 * inline buffer used for everything 168 * 169 * - ikm_small_data (IKM_TYPE_UDATA_OOL) 170 * inline buffer used for the kernel data/header 171 * 172 * - ikm_kdata{,_size} (IKM_TYPE_KDATA_OOL, IKM_TYPE_ALL_OOL) 173 * kernel data buffer and size (with kernel pointers). 174 * 175 * - ikm_udata{,_size} (IKM_TYPE_UDATA_OOL, IKM_TYPE_ALL_OOL) 176 * user data buffer and size (no kernel pointers). 177 * 178 * Note: ikm_big_data and ikm_small_data are at the same address 179 * so that `ikm_header()` only has two cases. 180 * 181 * dPAC-ed pointers follow so that linear overflows are 182 * unlikely to be exploitable. 183 */ 184 uint32_t ikm_big_data[IKM_BIG_MSG_SIZE / 4]; 185 struct { 186 uint32_t ikm_small_data[IKM_SMALL_MSG_SIZE / 4]; 187 void *XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_kdata") ikm_kdata; 188 void *XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_udata") ikm_udata; 189 mach_msg_size_t ikm_kdata_size; 190 mach_msg_size_t ikm_udata_size; 191 } __attribute__((packed, aligned(4))); 192 }; 193 }; 194 195 static_assert(sizeof(struct ipc_kmsg) == IKM_ALLOC_SIZE); 196 static_assert(offsetof(struct ipc_kmsg, ikm_big_data) + 197 IKM_BIG_MSG_SIZE == IKM_ALLOC_SIZE); 198 static_assert(offsetof(struct ipc_kmsg, ikm_small_data) + IKM_SMALL_MSG_SIZE + 199 2 * sizeof(void *) + 2 * sizeof(mach_msg_size_t) == IKM_ALLOC_SIZE); 200 201 KALLOC_TYPE_VAR_DECLARE(KT_IPC_KMSG_KDATA_OOL); 202 203 /* 204 * Exported interfaces 205 */ 206 207 typedef circle_queue_t ipc_kmsg_queue_t; 208 209 #define ipc_kmsg_queue_init(queue) circle_queue_init(queue) 210 211 #define ipc_kmsg_queue_empty(queue) circle_queue_empty(queue) 212 213 #define ipc_kmsg_queue_element(elem) \ 214 cqe_element(elem, struct ipc_kmsg, ikm_link) 215 216 #define ipc_kmsg_queue_first(queue) \ 217 cqe_queue_first(queue, struct ipc_kmsg, ikm_link) 218 219 #define ipc_kmsg_queue_next(queue, elt) \ 220 cqe_queue_next(&(elt)->ikm_link, queue, struct ipc_kmsg, ikm_link) 221 222 #define ipc_kmsg_enqueue(queue, kmsg) \ 223 circle_enqueue_tail(queue, &(kmsg)->ikm_link) 224 225 #define ipc_kmsg_rmqueue(queue, kmsg) \ 226 circle_dequeue(queue, &(kmsg)->ikm_link) 227 228 extern bool ipc_kmsg_enqueue_qos( 229 ipc_kmsg_queue_t queue, 230 ipc_kmsg_t kmsg); 231 232 extern bool ipc_kmsg_override_qos( 233 ipc_kmsg_queue_t queue, 234 ipc_kmsg_t kmsg, 235 mach_msg_qos_t qos_ovr); 236 237 /* Pull the (given) first kmsg out of a queue */ 238 extern void ipc_kmsg_rmqueue_first( 239 ipc_kmsg_queue_t queue, 240 ipc_kmsg_t kmsg); 241 242 __options_decl(ipc_kmsg_alloc_flags_t, uint32_t, { 243 /* specify either user or kernel flag */ 244 IPC_KMSG_ALLOC_USER = 0x0000, 245 IPC_KMSG_ALLOC_KERNEL = 0x0001, 246 247 IPC_KMSG_ALLOC_ZERO = 0x0002, 248 IPC_KMSG_ALLOC_ALL_INLINE = 0x0004, 249 IPC_KMSG_ALLOC_NOFAIL = 0x0008, 250 IPC_KMSG_ALLOC_LINEAR = 0x0010, 251 IPC_KMSG_ALLOC_USE_KEEP_ALIVE = 0x0020, /* must call ipc_kmsg_keep_alive_abandon () */ 252 }); 253 254 /* Allocate a kernel message */ 255 extern ipc_kmsg_t ipc_kmsg_alloc( 256 mach_msg_size_t msg_size, 257 mach_msg_size_t aux_size, 258 mach_msg_size_t desc_count, 259 ipc_kmsg_alloc_flags_t flags); 260 261 /* Free a kernel message buffer */ 262 extern void ipc_kmsg_free( 263 ipc_kmsg_t kmsg); 264 265 extern void ipc_kmsg_clean_descriptors( 266 mach_msg_kdescriptor_t * kdesc __counted_by(number), 267 mach_msg_type_number_t number); 268 269 extern void ipc_kmsg_sign_descriptors( 270 mach_msg_kdescriptor_t *kdesc, 271 mach_msg_size_t dsc_count); 272 273 __options_decl(ipc_kmsg_destroy_flags_t, uint32_t, { 274 IPC_KMSG_DESTROY_ALL = 0x0000, 275 IPC_KMSG_DESTROY_SKIP_REMOTE = 0x0001, 276 IPC_KMSG_DESTROY_SKIP_LOCAL = 0x0002, 277 IPC_KMSG_DESTROY_NOT_SIGNED = 0x0004, 278 }); 279 /* Destroy kernel message */ 280 extern void ipc_kmsg_destroy( 281 ipc_kmsg_t kmsg, 282 ipc_kmsg_destroy_flags_t flags); 283 284 /* Enqueue kernel message for deferred destruction */ 285 extern bool ipc_kmsg_delayed_destroy( 286 ipc_kmsg_t kmsg); 287 288 /* Enqueue queue of kernel messages for deferred destruction */ 289 extern bool ipc_kmsg_delayed_destroy_queue( 290 ipc_kmsg_queue_t queue); 291 292 /* Process all the delayed message destroys */ 293 extern void ipc_kmsg_reap_delayed(void); 294 295 /* Try to mark a message as in use (setting IKM_KEEP_ALIVE_IN_USE). */ 296 extern bool ipc_kmsg_keep_alive_try_reusing( 297 ipc_kmsg_t kmsg); 298 299 /* Abandons a message that was allocated with IPC_KMSG_ALLOC_USE_KEEP_ALIVE. */ 300 extern void ipc_kmsg_keep_alive_abandon( 301 ipc_kmsg_t kmsg); 302 303 /* get the unshifted message header of a kmsg */ 304 extern mach_msg_header_t *ikm_header( 305 ipc_kmsg_t kmsg); 306 307 /* get the start address of user data (after the last descriptor) for a kmsg */ 308 extern void *ikm_udata( 309 ipc_kmsg_t kmsg, 310 mach_msg_size_t desc_count, 311 bool complex); 312 313 extern void * ikm_udata_from_header( 314 ipc_kmsg_t kmsg); 315 316 /* Allocate a kernel message buffer and copy a kernel message to the buffer */ 317 extern mach_msg_return_t ipc_kmsg_get_from_kernel( 318 mach_msg_header_t *msg, 319 mach_msg_size_t size, 320 mach_msg_option64_t options, 321 ipc_kmsg_t *kmsgp); 322 323 /* Send a message to a port */ 324 extern mach_msg_return_t ipc_kmsg_send( 325 ipc_kmsg_t kmsg, 326 mach_msg_option64_t options, 327 mach_msg_timeout_t timeout_val); 328 329 /* Copy a kernel message buffer to a user message */ 330 extern mach_msg_return_t ipc_kmsg_put_to_user( 331 ipc_kmsg_t kmsg, /* scalar or vector */ 332 mach_msg_recv_bufs_t *recv_bufs, 333 mach_msg_recv_result_t *msgr, 334 mach_msg_option64_t option, 335 vm_map_t map, 336 mach_msg_return_t mr); 337 338 /* Copy a kernel message buffer to a kernel message */ 339 extern void ipc_kmsg_put_to_kernel( 340 mach_msg_header_t *msg, 341 mach_msg_option64_t options, 342 ipc_kmsg_t kmsg, 343 mach_msg_size_t size); 344 345 /* Copyin data, port rights and out-of-line memory from a user message */ 346 extern mach_msg_return_t ipc_kmsg_copyin_from_user( 347 ipc_kmsg_t kmsg, 348 mach_msg_send_uctx_t *send_uctx, 349 ipc_space_t space, 350 vm_map_t map, 351 mach_msg_priority_t priority, 352 mach_msg_option64_t *optionp); 353 354 /* Copyin port rights and out-of-line memory from a kernel message */ 355 extern mach_msg_return_t ipc_kmsg_copyin_from_kernel( 356 ipc_kmsg_t kmsg); 357 358 /* Copyout the header and body to a user message */ 359 extern mach_msg_return_t ipc_kmsg_copyout( 360 ipc_kmsg_t kmsg, 361 ipc_space_t space, 362 vm_map_t map, 363 mach_msg_option64_t option); 364 365 /* Copyout port rights and out-of-line memory to a user message, 366 * not reversing the ports in the header */ 367 extern mach_msg_return_t ipc_kmsg_copyout_pseudo( 368 ipc_kmsg_t kmsg, 369 ipc_space_t space, 370 vm_map_t map); 371 372 /* Compute size of message as copied out to the specified space/map */ 373 extern mach_msg_size_t ipc_kmsg_copyout_size( 374 ipc_kmsg_t kmsg, 375 vm_map_t map); 376 377 /* Copyout the destination port in the message */ 378 extern void ipc_kmsg_copyout_dest_to_user( 379 ipc_kmsg_t kmsg, 380 ipc_space_t space); 381 382 /* kernel's version of ipc_kmsg_copyout_dest_to_user */ 383 extern void ipc_kmsg_copyout_dest_to_kernel( 384 ipc_kmsg_t kmsg, 385 ipc_space_t space); 386 387 /* Returns a pointer to a thread group in the kmsg if any. Caller has a 388 * reference to the kmsg */ 389 extern struct thread_group *ipc_kmsg_get_thread_group( 390 ipc_kmsg_t kmsg); 391 392 extern mach_msg_trailer_size_t ipc_kmsg_trailer_size( 393 mach_msg_option64_t option, 394 vm_map_t map); 395 396 extern mach_msg_max_trailer_t *ipc_kmsg_get_trailer( 397 ipc_kmsg_t kmsg); 398 399 extern void ipc_kmsg_set_voucher_port( 400 ipc_kmsg_t kmsg, 401 ipc_port_t voucher, 402 mach_msg_type_name_t type); 403 404 extern ipc_port_t ipc_kmsg_get_voucher_port( 405 ipc_kmsg_t kmsg); 406 407 extern void ipc_kmsg_clear_voucher_port( 408 ipc_kmsg_t kmsg); 409 410 /* checks signature and returns descriptor count */ 411 extern mach_msg_size_t ipc_kmsg_validate_signature( 412 ipc_kmsg_t kmsg) __result_use_check; 413 414 #define moved_provisional_reply_port(port_type, port) \ 415 (port_type == MACH_MSG_TYPE_MOVE_RECEIVE && IP_VALID(port) && ip_is_provisional_reply_port(port)) \ 416 417 extern void send_prp_telemetry(int msgh_id); 418 419 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) 420 extern void ipc_kmsg_trace_send( 421 ipc_kmsg_t kmsg, 422 mach_msg_option64_t option); 423 #else 424 #define ipc_kmsg_trace_send(a, b) do { } while (0) 425 #endif 426 427 #if (DEVELOPMENT || DEBUG) 428 vm_offset_t ikm_kdata_end(ipc_kmsg_t kmsg); 429 #endif 430 431 #endif /* _IPC_IPC_KMSG_H_ */ 432