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