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 Software.Distribution@CS.CMU.EDU |
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 | * sync_qos and special_port_qos stores the qos for prealloced |
99 | * port, this fields could be deleted once we remove ip_prealloc. |
100 | */ |
101 | |
102 | /* A kmsg can be in one of the following four layouts */ |
103 | __enum_decl(ipc_kmsg_type_t, uint8_t, { |
104 | /* |
105 | * IKM_TYPE_ALL_INLINED: The entire message (and aux) is allocated inline. |
106 | * mach_msg_header_t is immediately after the kmsg header. An optional aux |
107 | * may be following the inline message proper. |
108 | */ |
109 | IKM_TYPE_ALL_INLINED = 0, |
110 | /* |
111 | * IKM_TYPE_UDATA_OOL: Message header and descriptors are allocated inline, |
112 | * and message data, trailer, and aux are in buffer pointed to by ikm_udata. |
113 | * mach_msg_header_t is immediately after the kmsg header. |
114 | */ |
115 | IKM_TYPE_UDATA_OOL = 1, |
116 | /* |
117 | * IKM_TYPE_KDATA_OOL: The entire message is allocated out-of-line. |
118 | * An ipc_kmsg_vector_t follows the kmsg header specifying the address and |
119 | * size of the allocation. There is no aux data. |
120 | */ |
121 | IKM_TYPE_KDATA_OOL = 2, |
122 | /* |
123 | * IKM_TYPE_ALL_OOL: Everything is allocated out-of-line. Message header |
124 | * and descriptors are allocated from typed kernel heap (kalloc_type), and |
125 | * message data, trailer, and aux are in data buffer pointed to by ikm_udata. |
126 | * An ipc_kmsg_vector_t follows the kmsg header specifying the address and |
127 | * size of the kdata allocation. |
128 | */ |
129 | IKM_TYPE_ALL_OOL = 3 |
130 | }); |
131 | |
132 | struct ipc_kmsg { |
133 | queue_chain_t ikm_link; |
134 | union { |
135 | /* port we were preallocated from, for IKM_TYPE_ALL_INLINED */ |
136 | ipc_port_t XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_prealloc" ) ikm_prealloc; |
137 | /* user data buffer, unused for IKM_TYPE_ALL_INLINED */ |
138 | void *XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_udata" ) ikm_udata; |
139 | }; |
140 | ipc_port_t XNU_PTRAUTH_SIGNED_PTR("kmsg.ikm_voucher_port" ) ikm_voucher_port; /* voucher port carried */ |
141 | struct ipc_importance_elem *ikm_importance; /* inherited from */ |
142 | queue_chain_t ikm_inheritance; /* inherited from link */ |
143 | #if MACH_FLIPC |
144 | struct mach_node *ikm_node; /* originating node - needed for ack */ |
145 | #endif |
146 | mach_msg_size_t ikm_aux_size; /* size reserved for auxiliary data */ |
147 | uint32_t ikm_ppriority; /* pthread priority of this kmsg */ |
148 | union { |
149 | struct { |
150 | /* For PAC-supported devices */ |
151 | uint32_t ikm_sig_partial; /* partial sig for header + trailer */ |
152 | uint32_t ikm_sig_full; /* upper 32 bits is full signature */ |
153 | }; |
154 | uint64_t ikm_signature; /* sig for all kernel-processed data */ |
155 | }; |
156 | ipc_object_copyin_flags_t ikm_flags; |
157 | mach_msg_qos_t ikm_qos_override; /* qos override on this kmsg */ |
158 | |
159 | mach_msg_type_name_t ikm_voucher_type: 6; /* disposition type the voucher came in with */ |
160 | ipc_kmsg_type_t ikm_type: 2; |
161 | |
162 | /* size of buffer pointed to by ikm_udata, unused for IKM_TYPE_ALL_INLINED. */ |
163 | mach_msg_size_t ikm_udata_size; |
164 | /* inline data of size IKM_SAVED_MSG_SIZE follows */ |
165 | }; |
166 | |
167 | typedef struct { |
168 | void *XNU_PTRAUTH_SIGNED_PTR("kmsgv.kmsgv_data" ) kmsgv_data; |
169 | mach_msg_size_t kmsgv_size; /* size of buffer, or descriptor count */ |
170 | } ipc_kmsg_vector_t; |
171 | |
172 | /* |
173 | * XXX For debugging. |
174 | */ |
175 | #define IKM_BOGUS ((ipc_kmsg_t) 0xffffff10) |
176 | |
177 | /* |
178 | * The size of the kernel message buffers that will be cached. |
179 | * IKM_SAVED_KMSG_SIZE includes overhead; IKM_SAVED_MSG_SIZE doesn't. |
180 | */ |
181 | #define IKM_SAVED_KMSG_SIZE 256 |
182 | #define IKM_SAVED_MSG_SIZE (IKM_SAVED_KMSG_SIZE - sizeof(struct ipc_kmsg)) |
183 | |
184 | KALLOC_TYPE_VAR_DECLARE(KT_IPC_KMSG_KDATA_OOL); |
185 | |
186 | #define ikm_prealloc_inuse_port(kmsg) \ |
187 | ((kmsg)->ikm_prealloc) |
188 | |
189 | #define ikm_prealloc_inuse(kmsg) \ |
190 | ((kmsg)->ikm_prealloc != IP_NULL) |
191 | |
192 | #define ikm_prealloc_set_inuse(kmsg, port) \ |
193 | MACRO_BEGIN \ |
194 | assert((port) != IP_NULL); \ |
195 | (kmsg)->ikm_prealloc = (port); \ |
196 | ip_validate(port); \ |
197 | ip_reference(port); \ |
198 | MACRO_END |
199 | |
200 | #define ikm_prealloc_clear_inuse(kmsg) \ |
201 | MACRO_BEGIN \ |
202 | (kmsg)->ikm_prealloc = IP_NULL; \ |
203 | MACRO_END |
204 | |
205 | /* |
206 | * Exported interfaces |
207 | */ |
208 | struct ipc_kmsg_queue { |
209 | struct ipc_kmsg *ikmq_base; |
210 | }; |
211 | |
212 | typedef circle_queue_t ipc_kmsg_queue_t; |
213 | |
214 | #define ipc_kmsg_queue_init(queue) circle_queue_init(queue) |
215 | |
216 | #define ipc_kmsg_queue_empty(queue) circle_queue_empty(queue) |
217 | |
218 | #define ipc_kmsg_queue_element(elem) \ |
219 | cqe_element(elem, struct ipc_kmsg, ikm_link) |
220 | |
221 | #define ipc_kmsg_queue_first(queue) \ |
222 | cqe_queue_first(queue, struct ipc_kmsg, ikm_link) |
223 | |
224 | #define ipc_kmsg_queue_next(queue, elt) \ |
225 | cqe_queue_next(&(elt)->ikm_link, queue, struct ipc_kmsg, ikm_link) |
226 | |
227 | #define ipc_kmsg_enqueue(queue, kmsg) \ |
228 | circle_enqueue_tail(queue, &(kmsg)->ikm_link) |
229 | |
230 | #define ipc_kmsg_rmqueue(queue, kmsg) \ |
231 | circle_dequeue(queue, &(kmsg)->ikm_link) |
232 | |
233 | extern bool ipc_kmsg_enqueue_qos( |
234 | ipc_kmsg_queue_t queue, |
235 | ipc_kmsg_t kmsg); |
236 | |
237 | extern bool ipc_kmsg_too_large( |
238 | mach_msg_size_t msg_size, |
239 | mach_msg_size_t aux_size, |
240 | mach_msg_option64_t options, |
241 | mach_msg_size_t max_msg_size, |
242 | mach_msg_size_t max_aux_size, |
243 | thread_t receiver); |
244 | |
245 | extern bool ipc_kmsg_override_qos( |
246 | ipc_kmsg_queue_t queue, |
247 | ipc_kmsg_t kmsg, |
248 | mach_msg_qos_t qos_ovr); |
249 | |
250 | /* Pull the (given) first kmsg out of a queue */ |
251 | extern void ipc_kmsg_rmqueue_first( |
252 | ipc_kmsg_queue_t queue, |
253 | ipc_kmsg_t kmsg); |
254 | |
255 | __options_decl(ipc_kmsg_alloc_flags_t, uint32_t, { |
256 | /* specify either user or kernel flag */ |
257 | IPC_KMSG_ALLOC_USER = 0x0000, |
258 | IPC_KMSG_ALLOC_KERNEL = 0x0001, |
259 | |
260 | IPC_KMSG_ALLOC_ZERO = 0x0002, |
261 | IPC_KMSG_ALLOC_SAVED = 0x0004, |
262 | IPC_KMSG_ALLOC_NOFAIL = 0x0008, |
263 | IPC_KMSG_ALLOC_LINEAR = 0x0010, |
264 | }); |
265 | |
266 | /* Allocate a kernel message */ |
267 | extern ipc_kmsg_t ipc_kmsg_alloc( |
268 | mach_msg_size_t msg_size, |
269 | mach_msg_size_t aux_size, |
270 | mach_msg_size_t desc_count, |
271 | ipc_kmsg_alloc_flags_t flags); |
272 | |
273 | /* Free a kernel message buffer */ |
274 | extern void ipc_kmsg_free( |
275 | ipc_kmsg_t kmsg); |
276 | |
277 | __options_decl(ipc_kmsg_destroy_flags_t, uint32_t, { |
278 | IPC_KMSG_DESTROY_ALL = 0x0000, |
279 | IPC_KMSG_DESTROY_SKIP_REMOTE = 0x0001, |
280 | IPC_KMSG_DESTROY_SKIP_LOCAL = 0x0002, |
281 | IPC_KMSG_DESTROY_NOT_SIGNED = 0x0004, |
282 | }); |
283 | /* Destroy kernel message */ |
284 | extern void ipc_kmsg_destroy( |
285 | ipc_kmsg_t kmsg, |
286 | ipc_kmsg_destroy_flags_t flags); |
287 | |
288 | /* Enqueue kernel message for deferred destruction */ |
289 | extern bool ipc_kmsg_delayed_destroy( |
290 | ipc_kmsg_t kmsg); |
291 | |
292 | /* Enqueue queue of kernel messages for deferred destruction */ |
293 | extern bool ipc_kmsg_delayed_destroy_queue( |
294 | ipc_kmsg_queue_t queue); |
295 | |
296 | /* Process all the delayed message destroys */ |
297 | extern void ipc_kmsg_reap_delayed(void); |
298 | |
299 | /* bind a preallocated message buffer to a port */ |
300 | extern void ipc_kmsg_set_prealloc( |
301 | ipc_kmsg_t kmsg, |
302 | ipc_port_t port); |
303 | |
304 | /* get the unshifted message header of a kmsg */ |
305 | extern mach_msg_header_t *( |
306 | ipc_kmsg_t kmsg); |
307 | |
308 | /* get the start address of user data (after the last descriptor) for a kmsg */ |
309 | extern void *ikm_udata( |
310 | ipc_kmsg_t kmsg, |
311 | mach_msg_size_t desc_count, |
312 | bool complex); |
313 | |
314 | extern void * ( |
315 | ipc_kmsg_t kmsg); |
316 | |
317 | /* get the size of auxiliary data for a kmsg */ |
318 | extern mach_msg_size_t ipc_kmsg_aux_data_size( |
319 | ipc_kmsg_t kmsg); |
320 | |
321 | extern void ( |
322 | ipc_kmsg_t kmsg, |
323 | mach_msg_aux_header_t *); |
324 | |
325 | /* Allocate a kernel message buffer and copy a user message to the buffer */ |
326 | extern mach_msg_return_t ipc_kmsg_get_from_user( |
327 | mach_vm_address_t msg_addr, |
328 | mach_msg_size_t user_msg_size, |
329 | mach_vm_address_t aux_addr, |
330 | mach_msg_size_t aux_size, |
331 | mach_msg_user_header_t , |
332 | mach_msg_size_t desc_count, |
333 | mach_msg_option64_t option64, |
334 | ipc_kmsg_t *kmsgp); |
335 | |
336 | /* Allocate a kernel message buffer and copy a kernel message to the buffer */ |
337 | extern mach_msg_return_t ipc_kmsg_get_from_kernel( |
338 | mach_msg_header_t *msg, |
339 | mach_msg_size_t size, |
340 | ipc_kmsg_t *kmsgp); |
341 | |
342 | /* Send a message to a port */ |
343 | extern mach_msg_return_t ipc_kmsg_send( |
344 | ipc_kmsg_t kmsg, |
345 | mach_msg_option64_t option64, |
346 | mach_msg_timeout_t timeout_val); |
347 | |
348 | /* Copy a kernel message buffer to a user message */ |
349 | extern mach_msg_return_t ipc_kmsg_put_to_user( |
350 | ipc_kmsg_t kmsg, /* scalar or vector */ |
351 | mach_msg_option64_t option, |
352 | mach_vm_address_t rcv_msg_addr, |
353 | mach_msg_size_t max_msg_size, |
354 | mach_vm_address_t rcv_aux_addr, |
355 | mach_msg_size_t max_aux_size, |
356 | mach_msg_size_t trailer_size, |
357 | mach_msg_size_t *msg_sizep, |
358 | mach_msg_size_t *aux_sizep); |
359 | |
360 | /* Copy a kernel message buffer to a kernel message */ |
361 | extern void ipc_kmsg_put_to_kernel( |
362 | mach_msg_header_t *msg, |
363 | ipc_kmsg_t kmsg, |
364 | mach_msg_size_t size); |
365 | |
366 | /* Copyin port rights and out-of-line memory from a user message */ |
367 | extern mach_msg_return_t ipc_kmsg_copyin_from_user( |
368 | ipc_kmsg_t kmsg, |
369 | ipc_space_t space, |
370 | vm_map_t map, |
371 | mach_msg_priority_t priority, |
372 | mach_msg_option64_t *optionp, |
373 | bool filter_nonfatal); |
374 | |
375 | /* Copyin port rights and out-of-line memory from a kernel message */ |
376 | extern mach_msg_return_t ipc_kmsg_copyin_from_kernel( |
377 | ipc_kmsg_t kmsg); |
378 | |
379 | /* Copyout the header and body to a user message */ |
380 | extern mach_msg_return_t ipc_kmsg_copyout( |
381 | ipc_kmsg_t kmsg, |
382 | ipc_space_t space, |
383 | vm_map_t map, |
384 | mach_msg_option_t option); |
385 | |
386 | /* Copyout port rights and out-of-line memory to a user message, |
387 | * not reversing the ports in the header */ |
388 | extern mach_msg_return_t ipc_kmsg_copyout_pseudo( |
389 | ipc_kmsg_t kmsg, |
390 | ipc_space_t space, |
391 | vm_map_t map); |
392 | |
393 | /* Compute size of message as copied out to the specified space/map */ |
394 | extern mach_msg_size_t ipc_kmsg_copyout_size( |
395 | ipc_kmsg_t kmsg, |
396 | vm_map_t map); |
397 | |
398 | /* Copyout the destination port in the message */ |
399 | extern void ipc_kmsg_copyout_dest_to_user( |
400 | ipc_kmsg_t kmsg, |
401 | ipc_space_t space); |
402 | |
403 | /* kernel's version of ipc_kmsg_copyout_dest_to_user */ |
404 | extern void ipc_kmsg_copyout_dest_to_kernel( |
405 | ipc_kmsg_t kmsg, |
406 | ipc_space_t space); |
407 | |
408 | /* Returns a pointer to a thread group in the kmsg if any. Caller has a |
409 | * reference to the kmsg */ |
410 | extern struct thread_group *ipc_kmsg_get_thread_group( |
411 | ipc_kmsg_t kmsg); |
412 | |
413 | extern mach_msg_trailer_size_t ipc_kmsg_trailer_size( |
414 | mach_msg_option_t option, |
415 | thread_t thread); |
416 | |
417 | extern void ipc_kmsg_init_trailer( |
418 | ipc_kmsg_t kmsg, |
419 | task_t sender); |
420 | |
421 | extern void ipc_kmsg_add_trailer( |
422 | ipc_kmsg_t kmsg, |
423 | ipc_space_t space, |
424 | mach_msg_option_t option, |
425 | thread_t thread, |
426 | mach_port_seqno_t seqno, |
427 | boolean_t minimal_trailer, |
428 | mach_vm_offset_t context); |
429 | |
430 | extern mach_msg_max_trailer_t *ipc_kmsg_get_trailer( |
431 | ipc_kmsg_t kmsg, |
432 | bool body_copied_out); |
433 | |
434 | extern void ipc_kmsg_set_voucher_port( |
435 | ipc_kmsg_t kmsg, |
436 | ipc_port_t voucher, |
437 | mach_msg_type_name_t type); |
438 | |
439 | extern ipc_port_t ipc_kmsg_get_voucher_port( |
440 | ipc_kmsg_t kmsg); |
441 | |
442 | extern void ipc_kmsg_clear_voucher_port( |
443 | ipc_kmsg_t kmsg); |
444 | |
445 | extern void ipc_kmsg_validate_partial_sig( |
446 | ipc_kmsg_t kmsg); |
447 | |
448 | #define moved_provisional_reply_port(port_type, port) \ |
449 | (port_type == MACH_MSG_TYPE_MOVE_RECEIVE && IP_VALID(port) && ip_is_provisional_reply_port(port)) \ |
450 | |
451 | extern void send_prp_telemetry(int msgh_id); |
452 | |
453 | #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) |
454 | extern void ipc_kmsg_trace_send( |
455 | ipc_kmsg_t kmsg, |
456 | mach_msg_option_t option); |
457 | #else |
458 | #define ipc_kmsg_trace_send(a, b) do { } while (0) |
459 | #endif |
460 | |
461 | #if (DEVELOPMENT || DEBUG) |
462 | vm_offset_t ikm_kdata_end(ipc_kmsg_t kmsg); |
463 | vm_offset_t ikm_udata_end(ipc_kmsg_t kmsg); |
464 | #endif |
465 | |
466 | #endif /* _IPC_IPC_KMSG_H_ */ |
467 | |