1 /*
2 * Copyright (c) 2012-2016 Apple 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 #include <voucher/ipc_pthread_priority_types.h>
30 #include <voucher/ipc_pthread_priority_internal.h>
31 #include <mach/mach_types.h>
32 #include <mach/kern_return.h>
33 #include <ipc/ipc_port.h>
34 #include <mach/mach_vm.h>
35 #include <mach/vm_map.h>
36 #include <vm/vm_map.h>
37 #include <mach/host_priv.h>
38 #include <mach/host_special_ports.h>
39 #include <kern/host.h>
40 #include <kern/ledger.h>
41 #include <sys/kdebug.h>
42 #include <IOKit/IOBSD.h>
43 #include <pthread/priority_private.h>
44
45 ipc_voucher_attr_control_t ipc_pthread_priority_voucher_attr_control; /* communication channel from PTHPRIORITY to voucher system */
46
47 #define IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(x) ((mach_voucher_attr_value_handle_t)(x))
48 #define HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(x) ((ipc_pthread_priority_value_t)(x))
49
50 kern_return_t
51 ipc_pthread_priority_release_value(
52 ipc_voucher_attr_manager_t __assert_only manager,
53 mach_voucher_attr_key_t __assert_only key,
54 mach_voucher_attr_value_handle_t value,
55 mach_voucher_attr_value_reference_t sync);
56
57 kern_return_t
58 ipc_pthread_priority_get_value(
59 ipc_voucher_attr_manager_t __assert_only manager,
60 mach_voucher_attr_key_t __assert_only key,
61 mach_voucher_attr_recipe_command_t command,
62 mach_voucher_attr_value_handle_array_t prev_values,
63 mach_msg_type_number_t __assert_only prev_value_count,
64 mach_voucher_attr_content_t recipe,
65 mach_voucher_attr_content_size_t recipe_size,
66 mach_voucher_attr_value_handle_t *out_value,
67 mach_voucher_attr_value_flags_t *out_flags,
68 ipc_voucher_t *out_value_voucher);
69
70 kern_return_t
71 ipc_pthread_priority_extract_content(
72 ipc_voucher_attr_manager_t __assert_only manager,
73 mach_voucher_attr_key_t __assert_only key,
74 mach_voucher_attr_value_handle_array_t values,
75 mach_msg_type_number_t value_count,
76 mach_voucher_attr_recipe_command_t *out_command,
77 mach_voucher_attr_content_t out_recipe,
78 mach_voucher_attr_content_size_t *in_out_recipe_size);
79
80 kern_return_t
81 ipc_pthread_priority_command(
82 ipc_voucher_attr_manager_t __assert_only manager,
83 mach_voucher_attr_key_t __assert_only key,
84 mach_voucher_attr_value_handle_array_t values,
85 mach_msg_type_number_t value_count,
86 mach_voucher_attr_command_t command,
87 mach_voucher_attr_content_t in_content,
88 mach_voucher_attr_content_size_t in_content_size,
89 mach_voucher_attr_content_t out_content,
90 mach_voucher_attr_content_size_t *in_out_content_size);
91
92 /*
93 * communication channel from voucher system to IPC_PTHREAD_PRIORITY
94 */
95 const struct ipc_voucher_attr_manager ipc_pthread_priority_manager = {
96 .ivam_release_value = ipc_pthread_priority_release_value,
97 .ivam_get_value = ipc_pthread_priority_get_value,
98 .ivam_extract_content = ipc_pthread_priority_extract_content,
99 .ivam_command = ipc_pthread_priority_command,
100 .ivam_flags = IVAM_FLAGS_NONE,
101 };
102
103 /*
104 * Routine: ipc_pthread_priority_init
105 * Purpose: Initialize the IPC_PTHREAD_PRIORITY subsystem.
106 * Returns: None.
107 */
108 void
ipc_pthread_priority_init(void)109 ipc_pthread_priority_init(void)
110 {
111 kern_return_t kr = KERN_SUCCESS;
112
113 /* Register the ipc_pthread_priority manager with the Vouchers sub system. */
114 kr = ipc_register_well_known_mach_voucher_attr_manager(
115 &ipc_pthread_priority_manager,
116 0,
117 MACH_VOUCHER_ATTR_KEY_PTHPRIORITY,
118 &ipc_pthread_priority_voucher_attr_control);
119 if (kr != KERN_SUCCESS) {
120 panic("IPC_PTHREAD_PRIORITY subsystem initialization failed");
121 }
122
123 kprintf("IPC_PTHREAD_PRIORITY subsystem is initialized\n");
124 return;
125 }
126
127 /*
128 * IPC_PTHREAD_PRIORITY Resource Manager Routines.
129 */
130
131
132 /*
133 * Routine: ipc_pthread_priority_release_value
134 * Purpose: Release a value, if sync matches the sync count in value.
135 * Returns: KERN_SUCCESS: on Successful deletion.
136 * KERN_FAILURE: if sync value does not matches.
137 */
138 kern_return_t
ipc_pthread_priority_release_value(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_value_handle_t value,mach_voucher_attr_value_reference_t sync)139 ipc_pthread_priority_release_value(
140 ipc_voucher_attr_manager_t __assert_only manager,
141 mach_voucher_attr_key_t __assert_only key,
142 mach_voucher_attr_value_handle_t value,
143 mach_voucher_attr_value_reference_t sync)
144 {
145 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
146 assert(manager == &ipc_pthread_priority_manager);
147
148 ipc_pthread_priority_value_t ipc_pthread_priority_value = HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(value);
149
150 panic("ipc_pthread_priority_release_value called for a persistent PTHPRIORITY value %x with sync value %d", ipc_pthread_priority_value, sync);
151 return KERN_FAILURE;
152 }
153
154 /*
155 * Routine: ipc_pthread_priority_get_value
156 */
157 kern_return_t
ipc_pthread_priority_get_value(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_recipe_command_t command,mach_voucher_attr_value_handle_array_t __unused prev_values,mach_msg_type_number_t __unused prev_value_count,mach_voucher_attr_content_t recipe,mach_voucher_attr_content_size_t recipe_size,mach_voucher_attr_value_handle_t * out_value,mach_voucher_attr_value_flags_t * out_flags,ipc_voucher_t * out_value_voucher)158 ipc_pthread_priority_get_value(
159 ipc_voucher_attr_manager_t __assert_only manager,
160 mach_voucher_attr_key_t __assert_only key,
161 mach_voucher_attr_recipe_command_t command,
162 mach_voucher_attr_value_handle_array_t __unused prev_values,
163 mach_msg_type_number_t __unused prev_value_count,
164 mach_voucher_attr_content_t recipe,
165 mach_voucher_attr_content_size_t recipe_size,
166 mach_voucher_attr_value_handle_t *out_value,
167 mach_voucher_attr_value_flags_t *out_flags,
168 ipc_voucher_t *out_value_voucher)
169 {
170 kern_return_t kr = KERN_SUCCESS;
171 ipc_pthread_priority_value_t ipc_pthread_priority_value;
172 ipc_pthread_priority_value_t canonicalize_priority_value;
173
174 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
175 assert(manager == &ipc_pthread_priority_manager);
176
177 /* never an out voucher */
178 *out_value_voucher = IPC_VOUCHER_NULL;
179 *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
180
181 switch (command) {
182 case MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE:
183
184 if (recipe_size != sizeof(ipc_pthread_priority_value_t)) {
185 return KERN_INVALID_ARGUMENT;
186 }
187
188 memcpy(&ipc_pthread_priority_value, recipe, recipe_size);
189
190 if (ipc_pthread_priority_value == PTHPRIORITY_ATTR_DEFAULT_VALUE) {
191 *out_value = IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(PTHPRIORITY_ATTR_DEFAULT_VALUE);
192 return kr;
193 }
194
195 /* Callout to pthread kext to get the canonicalized value */
196 canonicalize_priority_value = (ipc_pthread_priority_value_t)
197 _pthread_priority_normalize_for_ipc((unsigned long)ipc_pthread_priority_value);
198
199 *out_value = IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(canonicalize_priority_value);
200 *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
201 return kr;
202
203 default:
204 kr = KERN_INVALID_ARGUMENT;
205 break;
206 }
207
208 return kr;
209 }
210
211 /*
212 * Routine: ipc_pthread_priority_extract_content
213 * Purpose: Extract a set of pthread_priority value from an array of voucher values.
214 * Returns: KERN_SUCCESS: on Success.
215 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of pthread_priority values.
216 */
217 kern_return_t
ipc_pthread_priority_extract_content(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_value_handle_array_t values,mach_msg_type_number_t value_count,mach_voucher_attr_recipe_command_t * out_command,mach_voucher_attr_content_t out_recipe,mach_voucher_attr_content_size_t * in_out_recipe_size)218 ipc_pthread_priority_extract_content(
219 ipc_voucher_attr_manager_t __assert_only manager,
220 mach_voucher_attr_key_t __assert_only key,
221 mach_voucher_attr_value_handle_array_t values,
222 mach_msg_type_number_t value_count,
223 mach_voucher_attr_recipe_command_t *out_command,
224 mach_voucher_attr_content_t out_recipe,
225 mach_voucher_attr_content_size_t *in_out_recipe_size)
226 {
227 kern_return_t kr = KERN_SUCCESS;
228 mach_msg_type_number_t i;
229 ipc_pthread_priority_value_t ipc_pthread_priority_value;
230
231 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
232 assert(manager == &ipc_pthread_priority_manager);
233
234 for (i = 0; i < value_count && *in_out_recipe_size > 0; i++) {
235 ipc_pthread_priority_value = HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(values[i]);
236
237 if (ipc_pthread_priority_value == PTHPRIORITY_ATTR_DEFAULT_VALUE) {
238 continue;
239 }
240
241 if (MACH_VOUCHER_PTHPRIORITY_CONTENT_SIZE > *in_out_recipe_size) {
242 *in_out_recipe_size = 0;
243 return KERN_NO_SPACE;
244 }
245
246 memcpy(&out_recipe[0], &ipc_pthread_priority_value, sizeof(ipc_pthread_priority_value));
247 *out_command = MACH_VOUCHER_ATTR_PTHPRIORITY_NULL;
248 *in_out_recipe_size = (mach_voucher_attr_content_size_t)sizeof(ipc_pthread_priority_value);
249 return kr;
250 }
251
252 *in_out_recipe_size = 0;
253 return KERN_INVALID_VALUE;
254 }
255
256 /*
257 * Routine: ipc_pthread_priority_command
258 * Purpose: Execute a command against a set of PTHPRIORITY values.
259 * Returns: KERN_SUCCESS: On successful execution of command.
260 * KERN_FAILURE: On failure.
261 */
262 kern_return_t
ipc_pthread_priority_command(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_value_handle_array_t __unused values,mach_msg_type_number_t __unused value_count,mach_voucher_attr_command_t __unused command,mach_voucher_attr_content_t __unused in_content,mach_voucher_attr_content_size_t __unused in_content_size,mach_voucher_attr_content_t __unused out_content,mach_voucher_attr_content_size_t __unused * out_content_size)263 ipc_pthread_priority_command(
264 ipc_voucher_attr_manager_t __assert_only manager,
265 mach_voucher_attr_key_t __assert_only key,
266 mach_voucher_attr_value_handle_array_t __unused values,
267 mach_msg_type_number_t __unused value_count,
268 mach_voucher_attr_command_t __unused command,
269 mach_voucher_attr_content_t __unused in_content,
270 mach_voucher_attr_content_size_t __unused in_content_size,
271 mach_voucher_attr_content_t __unused out_content,
272 mach_voucher_attr_content_size_t __unused *out_content_size)
273 {
274 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
275 assert(manager == &ipc_pthread_priority_manager);
276
277 return KERN_FAILURE;
278 }
279