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