xref: /xnu-8019.80.24/osfmk/ipc/ipc_voucher.h (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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 #ifndef _IPC_IPC_VOUCHER_H_
29 #define _IPC_IPC_VOUCHER_H_
30 
31 #include <mach/mach_types.h>
32 #include <mach/mach_voucher_types.h>
33 #include <mach/boolean.h>
34 #include <ipc/ipc_types.h>
35 #include <os/refcnt.h>
36 
37 #ifdef MACH_KERNEL_PRIVATE
38 
39 #include <kern/queue.h>
40 #include <kern/locks.h>
41 #include <kern/simple_lock.h>
42 #include <voucher/ipc_pthread_priority_types.h>
43 
44 /* locking */
45 extern lck_grp_t        ipc_lck_grp;
46 extern lck_attr_t       ipc_lck_attr;
47 
48 /* some shorthand for longer types */
49 typedef mach_voucher_attr_value_handle_t        iv_value_handle_t __kernel_ptr_semantics;
50 typedef mach_voucher_attr_value_reference_t     iv_value_refs_t;
51 
52 typedef natural_t               iv_index_t;
53 #define IV_UNUSED_VALINDEX      ((iv_index_t) 0)
54 #define IV_UNUSED_KEYINDEX      ((iv_index_t) ~0)
55 
56 typedef iv_index_t              *iv_entry_t;
57 #define IVE_NULL                ((iv_entry_t) 0)
58 
59 #define IV_ENTRIES_INLINE MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN
60 
61 /*
62  * IPC Voucher
63  *
64  * Vouchers are a reference counted immutable (once-created) set of
65  * indexes to particular resource manager attribute values
66  * (which themselves are reference counted).
67  */
68 struct ipc_voucher {
69 	iv_index_t              iv_hash;        /* checksum hash */
70 	iv_index_t              iv_sum;         /* checksum of values */
71 	os_refcnt_t             iv_refs;        /* reference count */
72 	iv_index_t              iv_table_size;  /* size of the voucher table */
73 	iv_index_t              iv_inline_table[IV_ENTRIES_INLINE];
74 	iv_entry_t              iv_table;       /* table of voucher attr entries */
75 	ipc_port_t              iv_port;        /* port representing the voucher */
76 	queue_chain_t           iv_hash_link;   /* link on hash chain */
77 };
78 
79 #define IV_NULL         IPC_VOUCHER_NULL
80 
81 
82 /*
83  * Voucher Attribute Cache Control Object
84  *
85  * This is where the Voucher system stores its caches/references to
86  * returned resource manager attribute values.  Each value only appears
87  * once in the table.  If a value is returned more than once by the
88  * resource manager, the voucher system will increase the reference
89  * on the previous value.
90  *
91  * The voucher itself contains one entry per key, that indexes into
92  * this table.
93  *
94  * A voucher that does not have an explicit index for a given key
95  * is assumed to have a reference on slot zero - which is where the
96  * voucher system stores the default value for the given attribute
97  * (specified at the time of resource manager registration).
98  *
99  * The ivace_releasing field limits the entry to a single concurrent
100  * return. Without it, a previous release's reply might still be
101  * working its way back to the voucher code, and a subsequent get-
102  * value could return the same value as was previously returned.  If
103  * the resource manager already knew that, it would return a failure
104  * on the return, and all is well.  We just treat the additional made
105  * references on the value as we normally would.  However, if the resource
106  * manager accepted the return, and the get-value response raced the
107  * release's reply, the newly made references will look like an extension
108  * of the old value's cache lifetime, rather than a new one.  Dropping
109  * that new lifetime's references to zero would result in a second
110  * release callback to the resource manager - this time with the wrong
111  * "made" reference count.  We avoid the race with this flag.
112  */
113 
114 struct ivac_entry_s {
115 	iv_value_handle_t       ivace_value;
116 	iv_value_refs_t         ivace_layered:1,     /* layered effective entry */
117 	    ivace_releasing:1,                       /* release in progress */
118 	    ivace_free:1,                            /* on freelist */
119 	    ivace_persist:1,                         /* Persist the entry, don't count made refs */
120 	    ivace_refs:28;                           /* reference count */
121 	union {
122 		iv_value_refs_t ivaceu_made;         /* made count (non-layered) */
123 		iv_index_t      ivaceu_layer;        /* next effective layer (layered) */
124 	} ivace_u;
125 	iv_index_t              ivace_next;          /* hash or freelist */
126 	iv_index_t              ivace_index;         /* hash head (independent) */
127 };
128 typedef struct ivac_entry_s       ivac_entry;
129 typedef ivac_entry              *ivac_entry_t;
130 
131 #define ivace_made              ivace_u.ivaceu_made
132 #define ivace_layer             ivace_u.ivaceu_layer
133 
134 #define IVACE_NULL              ((ivac_entry_t) 0);
135 
136 #define IVACE_REFS_MAX          ((1 << 28) - 1)
137 
138 #define IVAC_ENTRIES_MIN        512
139 #define IVAC_ENTRIES_MAX        524288
140 
141 struct ipc_voucher_attr_control {
142 	os_refcnt_t             ivac_refs;
143 	boolean_t               ivac_is_growing;        /* is the table being grown */
144 	ivac_entry_t            ivac_table;             /* table of voucher attr value entries */
145 	iv_index_t              ivac_table_size;        /* size of the attr value table */
146 	iv_index_t              ivac_init_table_size;   /* size of the attr value table */
147 	iv_index_t              ivac_freelist;          /* index of the first free element */
148 	ipc_port_t              ivac_port;              /* port for accessing the cache control  */
149 	lck_spin_t              ivac_lock_data;
150 	iv_index_t              ivac_key_index;         /* key index for this value */
151 };
152 typedef ipc_voucher_attr_control_t iv_attr_control_t;
153 
154 #define IVAC_NULL                  IPC_VOUCHER_ATTR_CONTROL_NULL
155 
156 extern ipc_voucher_attr_control_t  ivac_alloc(iv_index_t);
157 extern void ipc_voucher_receive_postprocessing(ipc_kmsg_t kmsg, mach_msg_option_t option);
158 extern void ipc_voucher_send_preprocessing(ipc_kmsg_t kmsg);
159 extern ipc_voucher_t ipc_voucher_get_default_voucher(void);
160 extern void mach_init_activity_id(void);
161 extern kern_return_t ipc_get_pthpriority_from_kmsg_voucher(ipc_kmsg_t kmsg, ipc_pthread_priority_value_t *qos);
162 #define ivac_lock_init(ivac) \
163 	lck_spin_init(&(ivac)->ivac_lock_data, &ipc_lck_grp, &ipc_lck_attr)
164 #define ivac_lock_destroy(ivac) \
165 	lck_spin_destroy(&(ivac)->ivac_lock_data, &ipc_lck_grp)
166 #define ivac_lock(ivac) \
167 	lck_spin_lock_grp(&(ivac)->ivac_lock_data, &ipc_lck_grp)
168 #define ivac_lock_try(ivac) \
169 	lck_spin_try_lock_grp(&(ivac)->ivac_lock_data, &ipc_lck_grp)
170 #define ivac_unlock(ivac) \
171 	lck_spin_unlock(&(ivac)->ivac_lock_data)
172 #define ivac_sleep(ivac) lck_spin_sleep_grp(&(ivac)->ivac_lock_data,        \
173 	                                LCK_SLEEP_DEFAULT,              \
174 	                                (event_t)(ivac),                \
175 	                                THREAD_UNINT, &ipc_lck_grp)
176 #define ivac_wakeup(ivac) thread_wakeup((event_t)(ivac))
177 
178 extern void ivac_dealloc(ipc_voucher_attr_control_t ivac);
179 
180 static inline void
ivac_reference(ipc_voucher_attr_control_t ivac)181 ivac_reference(ipc_voucher_attr_control_t ivac)
182 {
183 	if (ivac == IVAC_NULL) {
184 		return;
185 	}
186 	os_ref_retain(&ivac->ivac_refs);
187 }
188 
189 static inline void
ivac_release(ipc_voucher_attr_control_t ivac)190 ivac_release(ipc_voucher_attr_control_t ivac)
191 {
192 	if (IVAC_NULL == ivac) {
193 		return;
194 	}
195 
196 	if (os_ref_release(&ivac->ivac_refs) == 0) {
197 		ivac_dealloc(ivac);
198 	}
199 }
200 
201 #define IVAM_NULL IPC_VOUCHER_ATTR_MANAGER_NULL
202 
203 /*
204  * IPC voucher Resource Manager table element
205  *
206  * Information Associated with a specific registration of
207  * a voucher resource manager.
208  *
209  * NOTE: For now, this table is indexed directly by the key.  In the future,
210  * it will have to be growable and sparse by key.  When that is implemented
211  * the index will be independent from the key (but there will be a hash to
212  * find the index by key).
213  */
214 typedef struct ipc_voucher_global_table_element {
215 	ipc_voucher_attr_manager_t      ivgte_manager;
216 	ipc_voucher_attr_control_t      ivgte_control;
217 	mach_voucher_attr_key_t         ivgte_key;
218 } ipc_voucher_global_table_element;
219 
220 typedef ipc_voucher_global_table_element *ipc_voucher_global_table_element_t;
221 
222 #endif /* MACH_KERNEL_PRIVATE */
223 
224 /*
225  * IPC voucher attribute recipe
226  *
227  * In-kernel recipe format with an ipc_voucher_t pointer for the previous
228  * voucher reference.
229  */
230 #pragma pack(1)
231 typedef struct ipc_voucher_attr_recipe_data {
232 	mach_voucher_attr_key_t                 key;
233 	mach_voucher_attr_recipe_command_t      command;
234 	ipc_voucher_t                           previous_voucher;
235 	mach_voucher_attr_content_size_t        content_size;
236 	uint8_t                                 content[];
237 } ipc_voucher_attr_recipe_data_t;
238 typedef ipc_voucher_attr_recipe_data_t *ipc_voucher_attr_recipe_t;
239 typedef mach_msg_type_number_t ipc_voucher_attr_recipe_size_t;
240 
241 typedef uint8_t *ipc_voucher_attr_raw_recipe_t;
242 typedef ipc_voucher_attr_raw_recipe_t ipc_voucher_attr_raw_recipe_array_t;
243 typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_size_t;
244 typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_array_size_t;
245 
246 #pragma pack()
247 
248 /*
249  * In-kernel Resource Manager Definition
250  *
251  * In-kernel resource managers are defined by a v-table like structure for
252  * the three callouts supported by a resource manager (and release function).
253  *
254  * There is a single in-kernel resource manager that represents all the
255  * outside kernel managers (and reflects the calls through MIG to user-space).
256  */
257 
258 typedef kern_return_t (*ipc_voucher_attr_manager_release_value_t)(ipc_voucher_attr_manager_t,
259     mach_voucher_attr_key_t,
260     mach_voucher_attr_value_handle_t,
261     mach_voucher_attr_value_reference_t);
262 
263 typedef kern_return_t (*ipc_voucher_attr_manager_get_value_t)(ipc_voucher_attr_manager_t,
264     mach_voucher_attr_key_t,
265     mach_voucher_attr_recipe_command_t,
266     mach_voucher_attr_value_handle_array_t,
267     mach_voucher_attr_value_handle_array_size_t,
268     mach_voucher_attr_content_t,
269     mach_voucher_attr_content_size_t,
270     mach_voucher_attr_value_handle_t *,
271     mach_voucher_attr_value_flags_t *,
272     ipc_voucher_t *);
273 
274 typedef kern_return_t (*ipc_voucher_attr_manager_extract_content_t)(ipc_voucher_attr_manager_t,
275     mach_voucher_attr_key_t,
276     mach_voucher_attr_value_handle_array_t,
277     mach_voucher_attr_value_handle_array_size_t,
278     mach_voucher_attr_recipe_command_t *,
279     mach_voucher_attr_content_t,
280     mach_voucher_attr_content_size_t *);
281 
282 typedef kern_return_t (*ipc_voucher_attr_manager_command_t)(ipc_voucher_attr_manager_t,
283     mach_voucher_attr_key_t,
284     mach_voucher_attr_value_handle_array_t,
285     mach_voucher_attr_value_handle_array_size_t,
286     mach_voucher_attr_command_t,
287     mach_voucher_attr_content_t,
288     mach_voucher_attr_content_size_t,
289     mach_voucher_attr_content_t,
290     mach_voucher_attr_content_size_t *);
291 
292 typedef void (*ipc_voucher_attr_manager_release_t)(ipc_voucher_attr_manager_t);
293 
294 typedef uint32_t ipc_voucher_attr_manager_flags;
295 
296 struct ipc_voucher_attr_manager {
297 	ipc_voucher_attr_manager_release_value_t        ivam_release_value;
298 	ipc_voucher_attr_manager_get_value_t            ivam_get_value;
299 	ipc_voucher_attr_manager_extract_content_t      ivam_extract_content;
300 	ipc_voucher_attr_manager_command_t              ivam_command;
301 	ipc_voucher_attr_manager_release_t              ivam_release;
302 	ipc_voucher_attr_manager_flags                  ivam_flags;
303 };
304 
305 #define IVAM_FLAGS_NONE                              0
306 #define IVAM_FLAGS_SUPPORT_SEND_PREPROCESS         0x1
307 #define IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS     0x2
308 
309 __BEGIN_DECLS
310 
311 /* DEBUG/TRACE Convert from a port to a voucher */
312 extern uintptr_t unsafe_convert_port_to_voucher(
313 	ipc_port_t              port) __pure2;
314 
315 /* Convert from a port to a voucher */
316 extern ipc_voucher_t convert_port_to_voucher(
317 	ipc_port_t              port);
318 
319 /* Convert from a port name to an ipc_voucher */
320 extern ipc_voucher_t convert_port_name_to_voucher(
321 	mach_port_name_t        name);
322 
323 /* add a reference to the specified voucher */
324 extern void ipc_voucher_reference(
325 	ipc_voucher_t           voucher);
326 
327 /* drop the voucher reference picked up above */
328 extern void ipc_voucher_release(
329 	ipc_voucher_t           voucher);
330 
331 /* Convert from a voucher to a port */
332 extern ipc_port_t convert_voucher_to_port(
333 	ipc_voucher_t           voucher);
334 
335 /* convert from a voucher attribute control to a port */
336 extern ipc_port_t convert_voucher_attr_control_to_port(
337 	ipc_voucher_attr_control_t      control);
338 
339 /* add a reference to the specified voucher */
340 extern void ipc_voucher_attr_control_reference(
341 	ipc_voucher_attr_control_t      control);
342 
343 /* drop the reference picked up above */
344 extern void ipc_voucher_attr_control_release(
345 	ipc_voucher_attr_control_t      control);
346 
347 /* convert from a port to a voucher attribute control */
348 extern ipc_voucher_attr_control_t convert_port_to_voucher_attr_control(
349 	ipc_port_t              port);
350 
351 /*
352  * In-kernel equivalents to the user syscalls
353  */
354 extern kern_return_t
355 ipc_create_mach_voucher(
356 	ipc_voucher_attr_raw_recipe_array_t             recipes,
357 	ipc_voucher_attr_raw_recipe_array_size_t        recipe_size,
358 	ipc_voucher_t                                   *new_voucher);
359 
360 extern kern_return_t
361 ipc_voucher_attr_control_create_mach_voucher(
362 	ipc_voucher_attr_control_t                      control,
363 	ipc_voucher_attr_raw_recipe_array_t             recipes,
364 	ipc_voucher_attr_raw_recipe_array_size_t        recipe_size,
365 	ipc_voucher_t                                   *new_voucher);
366 
367 extern kern_return_t
368 ipc_register_well_known_mach_voucher_attr_manager(
369 	ipc_voucher_attr_manager_t              manager,
370 	mach_voucher_attr_value_handle_t        default_value,
371 	mach_voucher_attr_key_t                 key,
372 	ipc_voucher_attr_control_t              *control);
373 
374 
375 extern kern_return_t
376 ipc_register_mach_voucher_attr_manager(
377 	ipc_voucher_attr_manager_t              manager,
378 	mach_voucher_attr_value_handle_t        default_value,
379 	mach_voucher_attr_key_t                 *key,
380 	ipc_voucher_attr_control_t              *control);
381 
382 __END_DECLS
383 
384 #endif  /* _IPC_IPC_VOUCHER_H_ */
385