xref: /xnu-11417.140.69/osfmk/bank/bank.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 /*
2  * Copyright (c) 2012-2020 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 <bank/bank_internal.h>
30 #include <bank/bank_types.h>
31 #include <mach/mach_types.h>
32 #include <mach/kern_return.h>
33 #include <ipc/ipc_port.h>
34 #include <ipc/ipc_voucher.h>
35 #include <mach/mach_vm.h>
36 #include <mach/vm_map.h>
37 #include <vm/vm_map.h>
38 #include <mach/host_priv.h>
39 #include <mach/host_special_ports.h>
40 #include <kern/host.h>
41 #include <kern/ledger.h>
42 #include <kern/coalition.h>
43 #include <kern/thread_group.h>
44 #include <sys/kdebug.h>
45 #include <IOKit/IOBSD.h>
46 #include <kern/policy_internal.h>
47 
48 /* we can't include the BSD <sys/persona.h> header here... */
49 #ifndef PERSONA_ID_NONE
50 #define PERSONA_ID_NONE ((uint32_t)-1)
51 #endif
52 /* can't include <sys/kauth.h> either */
53 #ifndef KAUTH_UID_NONE
54 #define KAUTH_UID_NONE  (~(uint32_t)0 - 100)
55 #endif
56 
57 static ZONE_DEFINE_TYPE(bank_task_zone, "bank_task",
58     struct bank_task, ZC_NONE);
59 static ZONE_DEFINE_TYPE(bank_account_zone, "bank_account",
60     struct bank_account, ZC_NONE);
61 
62 #define MAX_BANK_TASK     (CONFIG_TASK_MAX)
63 #define MAX_BANK_ACCOUNT  (CONFIG_TASK_MAX + CONFIG_THREAD_MAX)
64 
65 #define BANK_ELEMENT_TO_HANDLE(x) (CAST_DOWN(bank_handle_t, (x)))
66 #define HANDLE_TO_BANK_ELEMENT(x) (CAST_DOWN(bank_element_t, (x)))
67 
68 /* Need macro since bank_element_t is 4 byte aligned on release kernel and direct type case gives compilation error */
69 #define CAST_TO_BANK_ELEMENT(x) ((bank_element_t)((void *)(x)))
70 #define CAST_TO_BANK_TASK(x) ((bank_task_t)((void *)(x)))
71 #define CAST_TO_BANK_ACCOUNT(x) ((bank_account_t)((void *)(x)))
72 
73 ipc_voucher_attr_control_t  bank_voucher_attr_control;    /* communication channel from ATM to voucher system */
74 
75 static ledger_template_t bank_ledger_template = NULL;
76 struct _bank_ledger_indices bank_ledgers = { .cpu_time = -1, .energy = -1 };
77 
78 static bank_task_t bank_task_alloc_init(task_t task);
79 static bank_account_t bank_account_alloc_init(bank_task_t bank_holder, bank_task_t bank_merchant,
80     bank_task_t bank_secureoriginator, bank_task_t bank_proximateprocess, struct thread_group* banktg, struct bank_persona *persona);
81 static bank_task_t get_bank_task_context(task_t task, boolean_t initialize);
82 static void bank_task_dealloc(bank_task_t bank_task);
83 static kern_return_t bank_account_dealloc_with_sync(bank_account_t bank_account, mach_voucher_attr_value_reference_t sync);
84 static void bank_rollup_chit_to_tasks(ledger_t bill, ledger_t bank_holder_ledger, ledger_t bank_merchant_ledger,
85     int bank_holder_pid, int bank_merchant_pid);
86 static ledger_t bank_get_bank_task_ledger_with_ref(bank_task_t bank_task);
87 static void bank_destroy_bank_task_ledger(bank_task_t bank_task);
88 static void init_bank_ledgers(void);
89 static boolean_t bank_task_is_propagate_entitled(task_t t);
90 static boolean_t bank_task_is_persona_modify_entitled(task_t t);
91 static struct thread_group *bank_get_bank_task_thread_group(bank_task_t bank_task __unused);
92 static struct thread_group *bank_get_bank_account_thread_group(bank_account_t bank_account __unused);
93 static uint64_t bank_get_bank_account_holder_resource_coalition_id(bank_account_t bank_account __unused);
94 static boolean_t bank_verify_persona_id(uint32_t persona_id, struct bank_persona *persona_out);
95 static boolean_t bank_task_can_adopt_persona(bank_task_t bank_merchant, struct bank_persona *persona);
96 static void bank_task_get_persona(bank_task_t bank_task, struct bank_persona *persona_out);
97 
98 /* lock to protect task->bank_context transition */
99 static LCK_GRP_DECLARE(bank_lock_grp, "bank_lock");
100 static LCK_ATTR_DECLARE(bank_lock_attr, 0, 0);
101 static LCK_SPIN_DECLARE_ATTR(g_bank_task_lock_data, &bank_lock_grp, &bank_lock_attr);
102 
103 static TUNABLE(bool, disable_persona_propagate_check,
104     "disable_persona_propagate_check", false);
105 
106 #define global_bank_task_lock() \
107 	lck_spin_lock_grp(&g_bank_task_lock_data, &bank_lock_grp)
108 #define global_bank_task_lock_try() \
109 	lck_spin_try_lock_grp(&g_bank_task_lock_data, &bank_lock_grp)
110 #define global_bank_task_unlock() \
111 	lck_spin_unlock(&g_bank_task_lock_data)
112 
113 extern uint64_t proc_uniqueid(void *p);
114 struct proc;
115 extern int32_t proc_pid(struct proc *p);
116 extern int32_t proc_pidversion(void *p);
117 extern uint32_t proc_getuid(void *p);
118 extern uint32_t proc_getgid(void *p);
119 extern void proc_getexecutableuuid(void *p, unsigned char *uuidbuf, unsigned long size);
120 extern int kauth_cred_issuser(void *cred);
121 extern void* kauth_cred_get(void);
122 
123 struct persona_t;
124 extern struct persona *proc_persona_get(void *p);
125 extern struct persona *persona_lookup(uint32_t id);
126 extern void persona_put(struct persona *persona);
127 extern uint32_t persona_get_id(struct persona *persona);
128 extern uint32_t persona_get_uid(struct persona *persona);
129 extern boolean_t persona_is_adoption_allowed(struct persona *persona);
130 
131 kern_return_t
132 bank_release_value(
133 	ipc_voucher_attr_manager_t __assert_only manager,
134 	mach_voucher_attr_key_t __assert_only key,
135 	mach_voucher_attr_value_handle_t value,
136 	mach_voucher_attr_value_reference_t sync);
137 
138 kern_return_t
139 bank_get_value(
140 	ipc_voucher_attr_manager_t __assert_only manager,
141 	mach_voucher_attr_key_t __assert_only key,
142 	mach_voucher_attr_recipe_command_t command,
143 	mach_voucher_attr_value_handle_array_t prev_values,
144 	mach_msg_type_number_t __assert_only prev_value_count,
145 	mach_voucher_attr_content_t recipe,
146 	mach_voucher_attr_content_size_t recipe_size,
147 	mach_voucher_attr_value_handle_t *out_value,
148 	mach_voucher_attr_value_flags_t  *out_flags,
149 	ipc_voucher_t *out_value_voucher);
150 
151 kern_return_t
152 bank_extract_content(
153 	ipc_voucher_attr_manager_t __assert_only manager,
154 	mach_voucher_attr_key_t __assert_only key,
155 	mach_voucher_attr_value_handle_array_t values,
156 	mach_msg_type_number_t value_count,
157 	mach_voucher_attr_recipe_command_t *out_command,
158 	mach_voucher_attr_content_t out_recipe,
159 	mach_voucher_attr_content_size_t *in_out_recipe_size);
160 
161 kern_return_t
162 bank_command(
163 	ipc_voucher_attr_manager_t __assert_only manager,
164 	mach_voucher_attr_key_t __assert_only key,
165 	mach_voucher_attr_value_handle_array_t values,
166 	mach_msg_type_number_t value_count,
167 	mach_voucher_attr_command_t command,
168 	mach_voucher_attr_content_t in_content,
169 	mach_voucher_attr_content_size_t in_content_size,
170 	mach_voucher_attr_content_t out_content,
171 	mach_voucher_attr_content_size_t *in_out_content_size);
172 
173 
174 /*
175  * communication channel from voucher system to ATM
176  */
177 const struct ipc_voucher_attr_manager bank_manager = {
178 	.ivam_release_value    = bank_release_value,
179 	.ivam_get_value        = bank_get_value,
180 	.ivam_extract_content  = bank_extract_content,
181 	.ivam_command          = bank_command,
182 	.ivam_flags            = (IVAM_FLAGS_SUPPORT_SEND_PREPROCESS | IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS),
183 };
184 
185 
186 #if DEVELOPMENT || DEBUG
187 LCK_GRP_DECLARE(bank_dev_lock_grp, "bank_dev_lock");
188 LCK_MTX_DECLARE(bank_tasks_list_lock, &bank_dev_lock_grp);
189 LCK_MTX_DECLARE(bank_accounts_list_lock, &bank_dev_lock_grp);
190 queue_head_t bank_tasks_list = QUEUE_HEAD_INITIALIZER(bank_tasks_list);
191 queue_head_t bank_accounts_list = QUEUE_HEAD_INITIALIZER(bank_accounts_list);
192 #endif
193 
194 /*
195  * Routine: bank_init
196  * Purpose: Initialize the BANK subsystem.
197  * Returns: None.
198  */
199 __startup_func
200 static void
bank_init(void)201 bank_init(void)
202 {
203 	init_bank_ledgers();
204 
205 	/* Register the bank manager with the Vouchers sub system. */
206 	ipc_register_well_known_mach_voucher_attr_manager(
207 		&bank_manager,
208 		0,
209 		MACH_VOUCHER_ATTR_KEY_BANK,
210 		&bank_voucher_attr_control);
211 
212 	kprintf("BANK subsystem is initialized\n");
213 }
214 STARTUP(MACH_IPC, STARTUP_RANK_FIRST, bank_init);
215 
216 
217 /*
218  * BANK Resource Manager Routines.
219  */
220 
221 
222 /*
223  * Routine: bank_release_value
224  * Purpose: Release a value, if sync matches the sync count in value.
225  * Returns: KERN_SUCCESS: on Successful deletion.
226  *          KERN_FAILURE: if sync value does not matches.
227  */
228 kern_return_t
bank_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)229 bank_release_value(
230 	ipc_voucher_attr_manager_t              __assert_only manager,
231 	mach_voucher_attr_key_t                 __assert_only key,
232 	mach_voucher_attr_value_handle_t                      value,
233 	mach_voucher_attr_value_reference_t               sync)
234 {
235 	bank_task_t bank_task = BANK_TASK_NULL;
236 	bank_element_t bank_element = BANK_ELEMENT_NULL;
237 	bank_account_t bank_account = BANK_ACCOUNT_NULL;
238 	kern_return_t kr = KERN_SUCCESS;
239 
240 	assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
241 	assert(manager == &bank_manager);
242 
243 
244 	bank_element = HANDLE_TO_BANK_ELEMENT(value);
245 	/* Voucher system should never release the default or persistent value */
246 	assert(bank_element != BANK_DEFAULT_VALUE && bank_element != BANK_DEFAULT_TASK_VALUE);
247 
248 	if (bank_element == BANK_DEFAULT_VALUE || bank_element == BANK_DEFAULT_TASK_VALUE) {
249 		/* Return success for default and default task value */
250 		return KERN_SUCCESS;
251 	}
252 
253 
254 	if (bank_element->be_type == BANK_TASK) {
255 		bank_task = CAST_TO_BANK_TASK(bank_element);
256 
257 		/* Checking of the made ref with sync and clearing of voucher ref should be done under a lock */
258 		lck_mtx_lock(&bank_task->bt_acc_to_pay_lock);
259 		if (bank_task->bt_made != sync) {
260 			lck_mtx_unlock(&bank_task->bt_acc_to_pay_lock);
261 			return KERN_FAILURE;
262 		}
263 
264 		bank_task_made_release_num(bank_task, sync);
265 		assert(bank_task->bt_voucher_ref == 1);
266 		bank_task->bt_voucher_ref = 0;
267 		lck_mtx_unlock(&bank_task->bt_acc_to_pay_lock);
268 
269 		bank_task_dealloc(bank_task);
270 	} else if (bank_element->be_type == BANK_ACCOUNT) {
271 		bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
272 		kr = bank_account_dealloc_with_sync(bank_account, sync);
273 	} else {
274 		panic("Bogus bank type: %d passed in get_value", bank_element->be_type);
275 	}
276 
277 	return kr;
278 }
279 
280 
281 /*
282  * Routine: bank_get_value
283  *
284  * This function uses the recipe to create a bank attribute for a voucher.
285  */
286 kern_return_t
bank_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 prev_values,mach_msg_type_number_t 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)287 bank_get_value(
288 	ipc_voucher_attr_manager_t              __assert_only manager,
289 	mach_voucher_attr_key_t                 __assert_only key,
290 	mach_voucher_attr_recipe_command_t                command,
291 	mach_voucher_attr_value_handle_array_t        prev_values,
292 	mach_msg_type_number_t                        prev_value_count,
293 	mach_voucher_attr_content_t                   recipe,
294 	mach_voucher_attr_content_size_t              recipe_size,
295 	mach_voucher_attr_value_handle_t             *out_value,
296 	mach_voucher_attr_value_flags_t              *out_flags,
297 	ipc_voucher_t                                            *out_value_voucher)
298 {
299 	bank_task_t bank_holder = BANK_TASK_NULL;
300 	bank_task_t bank_merchant = BANK_TASK_NULL;
301 	bank_task_t bank_secureoriginator = BANK_TASK_NULL;
302 	bank_task_t bank_proximateprocess = BANK_TASK_NULL;
303 	bank_element_t bank_element = BANK_ELEMENT_NULL;
304 	bank_account_t bank_account = BANK_ACCOUNT_NULL;
305 	bank_account_t old_bank_account = BANK_ACCOUNT_NULL;
306 	mach_voucher_attr_value_handle_t bank_handle;
307 	task_t task;
308 	kern_return_t kr = KERN_SUCCESS;
309 	mach_msg_type_number_t i;
310 	struct thread_group *thread_group = NULL;
311 	struct thread_group *cur_thread_group = NULL;
312 	struct bank_persona persona = {
313 		.persona_id = PERSONA_ID_NONE,
314 		.persona_uid = KAUTH_UID_NONE
315 	};
316 
317 	assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
318 	assert(manager == &bank_manager);
319 
320 	/* never an out voucher */
321 	*out_value_voucher = IPC_VOUCHER_NULL;
322 	*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
323 
324 	switch (command) {
325 	case MACH_VOUCHER_ATTR_BANK_CREATE:
326 
327 		/* It returns the default task value. This value is replaced by
328 		 * an actual bank task reference, by using a recipe with
329 		 * MACH_VOUCHER_ATTR_SEND_PREPROCESS command.
330 		 */
331 		*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE);
332 		*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
333 		break;
334 
335 	case MACH_VOUCHER_ATTR_BANK_MODIFY_PERSONA:
336 
337 		/* It creates a bank account attribute value with a new persona id
338 		 * and auto-redeems it on behalf of the bank_holder.
339 		 */
340 		*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
341 
342 		for (i = 0; i < prev_value_count; i++) {
343 			bank_handle = prev_values[i];
344 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
345 
346 			/* Expect a pre-processed attribute value */
347 			if (bank_element == BANK_DEFAULT_VALUE || bank_element == BANK_DEFAULT_TASK_VALUE) {
348 				continue;
349 			}
350 
351 			if (!bank_task_is_persona_modify_entitled(current_task())) {
352 				return KERN_NO_ACCESS;
353 			}
354 
355 			struct persona_modify_info pmi = {};
356 			if (recipe_size == sizeof(pmi)) {
357 				memcpy((void *)&pmi, recipe, sizeof(pmi));
358 			} else {
359 				return KERN_INVALID_ARGUMENT;
360 			}
361 
362 			/* Verify if the persona id is valid */
363 			if (!bank_verify_persona_id(pmi.persona_id, &persona)) {
364 				return KERN_INVALID_ARGUMENT;
365 			}
366 
367 			/* Update the persona id only if the bank element is a bank task.
368 			 * This ensures that the bank_holder can be trusted.
369 			 */
370 			if (bank_element->be_type == BANK_TASK) {
371 				bank_holder = CAST_TO_BANK_TASK(bank_element);
372 				/* Ensure that the requestor validated by userspace matches
373 				 * the bank_holder
374 				 */
375 				if (pmi.unique_pid != bank_holder->bt_unique_pid) {
376 					return KERN_INVALID_CAPABILITY;
377 				}
378 				bank_merchant = bank_holder;
379 				bank_secureoriginator = bank_holder;
380 				bank_proximateprocess = bank_holder;
381 				thread_group = bank_get_bank_task_thread_group(bank_holder);
382 			} else if (bank_element->be_type == BANK_ACCOUNT) {
383 				return KERN_INVALID_ARGUMENT;
384 			} else {
385 				panic("Bogus bank type: %d passed in get_value", bank_element->be_type);
386 			}
387 
388 			if (!bank_task_can_adopt_persona(bank_merchant, &persona)) {
389 				return KERN_INVALID_ARGUMENT;
390 			}
391 
392 			if (bank_holder->bt_persona_id == persona.persona_id) {
393 				lck_mtx_lock(&bank_holder->bt_acc_to_pay_lock);
394 				bank_task_made_reference(bank_holder);
395 				if (bank_holder->bt_voucher_ref == 0) {
396 					/* Take a ref for voucher system, if voucher system does not have a ref */
397 					bank_task_reference(bank_holder);
398 					bank_holder->bt_voucher_ref = 1;
399 				}
400 				lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
401 
402 				*out_value = BANK_ELEMENT_TO_HANDLE(bank_holder);
403 				return kr;
404 			}
405 
406 			bank_account = bank_account_alloc_init(bank_holder, bank_merchant,
407 			    bank_secureoriginator, bank_proximateprocess,
408 			    thread_group, &persona);
409 			if (bank_account == BANK_ACCOUNT_NULL) {
410 				return KERN_RESOURCE_SHORTAGE;
411 			}
412 
413 			*out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
414 			return kr;
415 		}
416 		break;
417 
418 	case MACH_VOUCHER_ATTR_AUTO_REDEEM:
419 
420 		/* It creates a bank account with the bank_merchant set to the current task.
421 		 * A bank attribute voucher needs to be redeemed before it can be adopted by
422 		 * it's threads.
423 		 */
424 		for (i = 0; i < prev_value_count; i++) {
425 			bank_handle = prev_values[i];
426 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
427 
428 			/* Should not have received default task value from an IPC */
429 			if (bank_element == BANK_DEFAULT_VALUE || bank_element == BANK_DEFAULT_TASK_VALUE) {
430 				continue;
431 			}
432 
433 			task = current_task();
434 			if (bank_element->be_type == BANK_TASK) {
435 				bank_holder = CAST_TO_BANK_TASK(bank_element);
436 				bank_secureoriginator = bank_holder;
437 				bank_proximateprocess = bank_holder;
438 				thread_group = bank_get_bank_task_thread_group(bank_holder);
439 				bank_task_get_persona(bank_holder, &persona);
440 			} else if (bank_element->be_type == BANK_ACCOUNT) {
441 				old_bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
442 				bank_holder = old_bank_account->ba_holder;
443 				bank_secureoriginator = old_bank_account->ba_secureoriginator;
444 				bank_proximateprocess = old_bank_account->ba_proximateprocess;
445 				thread_group = bank_get_bank_account_thread_group(old_bank_account);
446 				persona = old_bank_account->ba_so_persona;
447 			} else {
448 				panic("Bogus bank type: %d passed in get_value", bank_element->be_type);
449 			}
450 
451 			bank_merchant = get_bank_task_context(task, FALSE);
452 			if (bank_merchant == BANK_TASK_NULL) {
453 				return KERN_RESOURCE_SHORTAGE;
454 			}
455 
456 			cur_thread_group = bank_get_bank_task_thread_group(bank_merchant);
457 
458 			/* Change voucher thread group to current thread group for Apps */
459 			if (task_is_app(task)) {
460 				thread_group = cur_thread_group;
461 			}
462 
463 			/* If persona adoption is disallowed, reset it to the current task value */
464 			if (!bank_task_can_adopt_persona(bank_merchant, &persona)) {
465 				bank_task_get_persona(bank_merchant, &persona);
466 			}
467 
468 			/* Check if trying to redeem for self task, return the default bank task */
469 			if (bank_holder == bank_merchant &&
470 			    bank_holder == bank_secureoriginator &&
471 			    bank_holder == bank_proximateprocess &&
472 			    thread_group == cur_thread_group &&
473 			    persona.persona_id == bank_holder->bt_persona_id) {
474 				*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE);
475 				*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
476 				return kr;
477 			}
478 
479 			bank_account = bank_account_alloc_init(bank_holder, bank_merchant,
480 			    bank_secureoriginator, bank_proximateprocess,
481 			    thread_group, &persona);
482 			if (bank_account == BANK_ACCOUNT_NULL) {
483 				return KERN_RESOURCE_SHORTAGE;
484 			}
485 
486 			*out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
487 			return kr;
488 		}
489 
490 		*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
491 		break;
492 
493 	case MACH_VOUCHER_ATTR_SEND_PREPROCESS:
494 
495 		for (i = 0; i < prev_value_count; i++) {
496 			bank_handle = prev_values[i];
497 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
498 
499 			if (bank_element == BANK_DEFAULT_VALUE) {
500 				continue;
501 			}
502 
503 			task = current_task();
504 			if (bank_element == BANK_DEFAULT_TASK_VALUE) {
505 				bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(task, FALSE));
506 			}
507 
508 			if (bank_element->be_type == BANK_TASK) {
509 				bank_holder = CAST_TO_BANK_TASK(bank_element);
510 				bank_secureoriginator = bank_holder;
511 				thread_group = bank_get_bank_task_thread_group(bank_holder);
512 				bank_task_get_persona(bank_holder, &persona);
513 			} else if (bank_element->be_type == BANK_ACCOUNT) {
514 				old_bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
515 				bank_holder = old_bank_account->ba_holder;
516 				bank_secureoriginator = old_bank_account->ba_secureoriginator;
517 				thread_group = bank_get_bank_account_thread_group(old_bank_account);
518 				persona = old_bank_account->ba_so_persona;
519 			} else {
520 				panic("Bogus bank type: %d passed in get_value", bank_element->be_type);
521 			}
522 
523 			bank_merchant = get_bank_task_context(task, FALSE);
524 			if (bank_merchant == BANK_TASK_NULL) {
525 				return KERN_RESOURCE_SHORTAGE;
526 			}
527 
528 			cur_thread_group = bank_get_bank_task_thread_group(bank_merchant);
529 
530 			/*
531 			 * If the process doesn't have secure persona entitlement,
532 			 * then replace the secure originator to current task.
533 			 * Also update the persona to match that of the secure originator.
534 			 */
535 			if (bank_merchant->bt_hasentitlement == 0) {
536 				KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
537 				    (BANK_CODE(BANK_ACCOUNT_INFO, (BANK_SECURE_ORIGINATOR_CHANGED))) | DBG_FUNC_NONE,
538 				    bank_secureoriginator->bt_pid, bank_merchant->bt_pid, 0, 0, 0);
539 				bank_secureoriginator = bank_merchant;
540 				bank_task_get_persona(bank_merchant, &persona);
541 			}
542 
543 			bank_proximateprocess = bank_merchant;
544 
545 			/* Check if trying to pre-process for self task, return the bank task */
546 			if (bank_holder == bank_merchant &&
547 			    bank_holder == bank_secureoriginator &&
548 			    bank_holder == bank_proximateprocess &&
549 			    thread_group == cur_thread_group &&
550 			    persona.persona_id == bank_holder->bt_persona_id) {
551 				lck_mtx_lock(&bank_holder->bt_acc_to_pay_lock);
552 				bank_task_made_reference(bank_holder);
553 				if (bank_holder->bt_voucher_ref == 0) {
554 					/* Take a ref for voucher system, if voucher system does not have a ref */
555 					bank_task_reference(bank_holder);
556 					bank_holder->bt_voucher_ref = 1;
557 				}
558 				lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
559 
560 				*out_value = BANK_ELEMENT_TO_HANDLE(bank_holder);
561 				return kr;
562 			}
563 			bank_account = bank_account_alloc_init(bank_holder, bank_merchant,
564 			    bank_secureoriginator, bank_proximateprocess,
565 			    thread_group, &persona);
566 			if (bank_account == BANK_ACCOUNT_NULL) {
567 				return KERN_RESOURCE_SHORTAGE;
568 			}
569 
570 			*out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
571 			return kr;
572 		}
573 
574 		*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
575 		break;
576 
577 	case MACH_VOUCHER_ATTR_REDEEM:
578 		/* This command expects that the bank attribute has been auto-redeemed
579 		 * and returns a reference to that bank account value.
580 		 */
581 		for (i = 0; i < prev_value_count; i++) {
582 			bank_handle = prev_values[i];
583 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
584 
585 			if (bank_element == BANK_DEFAULT_VALUE) {
586 				continue;
587 			}
588 
589 			if (bank_element == BANK_DEFAULT_TASK_VALUE) {
590 				*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE);
591 				*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
592 				return kr;
593 			}
594 
595 			task = current_task();
596 			if (bank_element->be_type == BANK_TASK) {
597 				bank_holder =  CAST_TO_BANK_TASK(bank_element);
598 				if (bank_holder == get_bank_task_context(task, FALSE)) {
599 					*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE);
600 					*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
601 				} else {
602 					kr = KERN_INVALID_CAPABILITY;
603 				}
604 				return kr;
605 			} else if (bank_element->be_type == BANK_ACCOUNT) {
606 				bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
607 				bank_merchant = bank_account->ba_merchant;
608 				if (bank_merchant != get_bank_task_context(task, FALSE)) {
609 					/* This error can be used to verify if the task can
610 					 * adopt the voucher.
611 					 */
612 					kr = KERN_INVALID_CAPABILITY;
613 					return kr;
614 				}
615 				bank_account_made_reference(bank_account);
616 				*out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
617 				return kr;
618 			} else {
619 				panic("Bogus bank type: %d passed in get_value", bank_element->be_type);
620 			}
621 		}
622 
623 		*out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
624 		break;
625 
626 	default:
627 		kr = KERN_INVALID_ARGUMENT;
628 		break;
629 	}
630 
631 	return kr;
632 }
633 
634 
635 /*
636  * Routine: bank_extract_content
637  * Purpose: Extract a set of aid from an array of voucher values.
638  * Returns: KERN_SUCCESS: on Success.
639  *          KERN_FAILURE: one of the value is not present in the hash.
640  *          KERN_NO_SPACE: insufficeint buffer provided to fill an array of aid.
641  */
642 kern_return_t
bank_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)643 bank_extract_content(
644 	ipc_voucher_attr_manager_t      __assert_only manager,
645 	mach_voucher_attr_key_t         __assert_only key,
646 	mach_voucher_attr_value_handle_array_t        values,
647 	mach_msg_type_number_t                                value_count,
648 	mach_voucher_attr_recipe_command_t           *out_command,
649 	mach_voucher_attr_content_t                   out_recipe,
650 	mach_voucher_attr_content_size_t             *in_out_recipe_size)
651 {
652 	bank_task_t bank_task = BANK_TASK_NULL;
653 	bank_element_t bank_element = BANK_ELEMENT_NULL;
654 	bank_account_t bank_account = BANK_ACCOUNT_NULL;
655 	mach_voucher_attr_value_handle_t bank_handle;
656 	char buf[MACH_VOUCHER_BANK_CONTENT_SIZE];
657 	mach_msg_type_number_t i;
658 
659 	assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
660 	assert(manager == &bank_manager);
661 
662 	for (i = 0; i < value_count && *in_out_recipe_size > 0; i++) {
663 		bank_handle = values[i];
664 		bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
665 		if (bank_element == BANK_DEFAULT_VALUE) {
666 			continue;
667 		}
668 
669 		if (bank_element == BANK_DEFAULT_TASK_VALUE) {
670 			bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
671 		}
672 
673 		if (MACH_VOUCHER_BANK_CONTENT_SIZE > *in_out_recipe_size) {
674 			*in_out_recipe_size = 0;
675 			return KERN_NO_SPACE;
676 		}
677 
678 		if (bank_element->be_type == BANK_TASK) {
679 			bank_task = CAST_TO_BANK_TASK(bank_element);
680 			snprintf(buf, MACH_VOUCHER_BANK_CONTENT_SIZE,
681 			    " Bank Context for a pid %d\n", bank_task->bt_pid);
682 		} else if (bank_element->be_type == BANK_ACCOUNT) {
683 			bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
684 			snprintf(buf, MACH_VOUCHER_BANK_CONTENT_SIZE,
685 			    " Bank Account linking holder pid %d with merchant pid %d, originator PID/persona: %d, %u and proximate PID/persona: %d, %u\n",
686 			    bank_account->ba_holder->bt_pid,
687 			    bank_account->ba_merchant->bt_pid,
688 			    bank_account->ba_secureoriginator->bt_pid,
689 			    bank_account->ba_so_persona.persona_id,
690 			    bank_account->ba_proximateprocess->bt_pid,
691 			    bank_account->ba_proximateprocess->bt_persona_id);
692 		} else {
693 			panic("Bogus bank type: %d passed in get_value", bank_element->be_type);
694 		}
695 
696 		memcpy(&out_recipe[0], buf, strlen(buf) + 1);
697 		*out_command = MACH_VOUCHER_ATTR_BANK_NULL;
698 		*in_out_recipe_size = (mach_voucher_attr_content_size_t)strlen(buf) + 1;
699 		return KERN_SUCCESS;
700 	}
701 
702 	return KERN_SUCCESS;
703 }
704 
705 /*
706  * Routine: bank_command
707  * Purpose: Execute a command against a set of bank values.
708  * Returns: KERN_SUCCESS: On successful execution of command.
709  *           KERN_FAILURE: On failure.
710  */
711 kern_return_t
bank_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)712 bank_command(
713 	ipc_voucher_attr_manager_t                 __assert_only manager,
714 	mach_voucher_attr_key_t                    __assert_only key,
715 	mach_voucher_attr_value_handle_array_t  __unused values,
716 	mach_msg_type_number_t                  __unused value_count,
717 	mach_voucher_attr_command_t              __unused command,
718 	mach_voucher_attr_content_t        __unused in_content,
719 	mach_voucher_attr_content_size_t   __unused in_content_size,
720 	mach_voucher_attr_content_t        __unused out_content,
721 	mach_voucher_attr_content_size_t   __unused *out_content_size)
722 {
723 	bank_task_t bank_task = BANK_TASK_NULL;
724 	bank_task_t bank_merchant = BANK_TASK_NULL;
725 	bank_task_t bank_secureoriginator = BANK_TASK_NULL;
726 	bank_task_t bank_proximateprocess = BANK_TASK_NULL;
727 	struct persona_token *token = NULL;
728 	bank_element_t bank_element = BANK_ELEMENT_NULL;
729 	bank_account_t bank_account = BANK_ACCOUNT_NULL;
730 	mach_voucher_attr_value_handle_t bank_handle;
731 	mach_msg_type_number_t i;
732 	task_t task;
733 	int32_t pid;
734 	uint32_t persona_id;
735 	boolean_t adopt_any_persona = FALSE;
736 
737 	assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
738 	assert(manager == &bank_manager);
739 
740 	switch (command) {
741 	case BANK_ORIGINATOR_PID:
742 
743 		if ((sizeof(pid)) > *out_content_size) {
744 			*out_content_size = 0;
745 			return KERN_NO_SPACE;
746 		}
747 
748 		for (i = 0; i < value_count; i++) {
749 			bank_handle = values[i];
750 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
751 			if (bank_element == BANK_DEFAULT_VALUE) {
752 				continue;
753 			}
754 
755 			if (bank_element == BANK_DEFAULT_TASK_VALUE) {
756 				bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
757 			}
758 
759 			if (bank_element->be_type == BANK_TASK) {
760 				bank_task = CAST_TO_BANK_TASK(bank_element);
761 			} else if (bank_element->be_type == BANK_ACCOUNT) {
762 				bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
763 				bank_task = bank_account->ba_holder;
764 			} else {
765 				panic("Bogus bank type: %d passed in voucher_command", bank_element->be_type);
766 			}
767 			pid = bank_task->bt_pid;
768 
769 			memcpy(&out_content[0], &pid, sizeof(pid));
770 			*out_content_size = (mach_voucher_attr_content_size_t)sizeof(pid);
771 			return KERN_SUCCESS;
772 		}
773 		/* In the case of no value, return error KERN_INVALID_VALUE */
774 		*out_content_size = 0;
775 		return KERN_INVALID_VALUE;
776 
777 	case BANK_PERSONA_TOKEN:
778 
779 		if ((sizeof(struct persona_token)) > *out_content_size) {
780 			*out_content_size = 0;
781 			return KERN_NO_SPACE;
782 		}
783 		for (i = 0; i < value_count; i++) {
784 			bank_handle = values[i];
785 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
786 			if (bank_element == BANK_DEFAULT_VALUE) {
787 				continue;
788 			}
789 
790 			if (bank_element == BANK_DEFAULT_TASK_VALUE) {
791 				bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
792 			}
793 
794 			if (bank_element->be_type == BANK_TASK) {
795 				*out_content_size = 0;
796 				return KERN_INVALID_OBJECT;
797 			} else if (bank_element->be_type == BANK_ACCOUNT) {
798 				bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
799 				bank_secureoriginator = bank_account->ba_secureoriginator;
800 				bank_proximateprocess = bank_account->ba_proximateprocess;
801 			} else {
802 				panic("Bogus bank type: %d passed in voucher_command", bank_element->be_type);
803 			}
804 			token = (struct persona_token *)(void *)&out_content[0];
805 			memcpy(&token->originator, &bank_secureoriginator->bt_proc_persona, sizeof(struct proc_persona_info));
806 			memcpy(&token->proximate, &bank_proximateprocess->bt_proc_persona, sizeof(struct proc_persona_info));
807 
808 			*out_content_size = (mach_voucher_attr_content_size_t)sizeof(*token);
809 			return KERN_SUCCESS;
810 		}
811 		/* In the case of no value, return error KERN_INVALID_VALUE */
812 		*out_content_size = 0;
813 		return KERN_INVALID_VALUE;
814 
815 	case BANK_PERSONA_ID:
816 
817 		if ((sizeof(persona_id)) > *out_content_size) {
818 			*out_content_size = 0;
819 			return KERN_NO_SPACE;
820 		}
821 
822 		for (i = 0; i < value_count; i++) {
823 			bank_handle = values[i];
824 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
825 			if (bank_element == BANK_DEFAULT_VALUE) {
826 				continue;
827 			}
828 
829 			if (bank_element == BANK_DEFAULT_TASK_VALUE) {
830 				bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
831 			}
832 
833 			if (bank_element->be_type == BANK_TASK) {
834 				bank_task = CAST_TO_BANK_TASK(bank_element);
835 				persona_id = bank_task->bt_persona_id;
836 			} else if (bank_element->be_type == BANK_ACCOUNT) {
837 				bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
838 				persona_id = bank_account->ba_so_persona.persona_id;
839 			} else {
840 				panic("Bogus bank type: %d passed in voucher_command", bank_element->be_type);
841 			}
842 
843 			memcpy(out_content, &persona_id, sizeof(persona_id));
844 			*out_content_size = (mach_voucher_attr_content_size_t)sizeof(persona_id);
845 			return KERN_SUCCESS;
846 		}
847 		/* In the case of no value, return error KERN_INVALID_VALUE */
848 		*out_content_size = 0;
849 		return KERN_INVALID_VALUE;
850 
851 	case BANK_PERSONA_ADOPT_ANY:
852 		if ((sizeof(boolean_t)) > *out_content_size) {
853 			*out_content_size = 0;
854 			return KERN_NO_SPACE;
855 		}
856 
857 		task = current_task();
858 		bank_merchant = get_bank_task_context(task, FALSE);
859 		if (bank_merchant == BANK_TASK_NULL) {
860 			*out_content_size = 0;
861 			return KERN_RESOURCE_SHORTAGE;
862 		}
863 
864 		adopt_any_persona = (bank_merchant->bt_flags & PROC_PERSONA_INFO_FLAG_ADOPTION_ALLOWED) != 0;
865 		memcpy(out_content, &adopt_any_persona, sizeof(adopt_any_persona));
866 		*out_content_size = (mach_voucher_attr_content_size_t)sizeof(adopt_any_persona);
867 		return KERN_SUCCESS;
868 
869 	case BANK_ORIGINATOR_PROXIMATE_PID:;
870 		int32_t *pids_out = (int32_t *)(uintptr_t)&out_content[0];
871 		if ((sizeof(pid) * 2) > *out_content_size) {
872 			*out_content_size = 0;
873 			return KERN_NO_SPACE;
874 		}
875 
876 		for (i = 0; i < value_count; i++) {
877 			bank_task_t bank_origin_task = BANK_TASK_NULL;
878 			bank_task_t bank_proximate_task = BANK_TASK_NULL;
879 			bank_handle = values[i];
880 			bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
881 			if (bank_element == BANK_DEFAULT_VALUE) {
882 				continue;
883 			}
884 
885 			if (bank_element == BANK_DEFAULT_TASK_VALUE) {
886 				bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
887 			}
888 
889 			if (bank_element->be_type == BANK_TASK) {
890 				bank_origin_task = CAST_TO_BANK_TASK(bank_element);
891 			} else if (bank_element->be_type == BANK_ACCOUNT) {
892 				bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
893 				bank_origin_task = bank_account->ba_holder;
894 				bank_proximate_task = bank_account->ba_proximateprocess;
895 			} else {
896 				panic("Bogus bank type: %d passed in voucher_command", bank_element->be_type);
897 			}
898 			int32_t origin_pid = bank_origin_task->bt_pid;
899 			int32_t proximate_pid = bank_proximate_task != BANK_TASK_NULL ? bank_proximate_task->bt_pid : -1;
900 
901 			memcpy(&pids_out[0], &origin_pid, sizeof(origin_pid));
902 			memcpy(&pids_out[1], &proximate_pid, sizeof(proximate_pid));
903 			*out_content_size = (mach_voucher_attr_content_size_t)sizeof(pid) * 2;
904 			return KERN_SUCCESS;
905 		}
906 		/* In the case of no value, return error KERN_INVALID_VALUE */
907 		*out_content_size = 0;
908 		return KERN_INVALID_VALUE;
909 
910 	default:
911 		return KERN_INVALID_ARGUMENT;
912 	}
913 	return KERN_SUCCESS;
914 }
915 
916 /*
917  * Bank Internal Routines.
918  */
919 
920 static boolean_t
bank_task_is_persona_adoption_allowed(task_t task __unused,struct persona * persona)921 bank_task_is_persona_adoption_allowed(task_t task __unused, struct persona *persona)
922 {
923 #if defined(XNU_TARGET_OS_OSX)
924 	/*
925 	 * On macOS platform binaries spawned in no persona are allowed to adopt
926 	 * personas.
927 	 */
928 	if (persona_get_id(persona) == PERSONA_ID_NONE) {
929 		return task_get_platform_binary(task) ||
930 		       IOTaskHasEntitlement(task, ENTITLEMENT_PERSONA_ADOPT_ANY);
931 	}
932 #endif
933 	return persona_is_adoption_allowed(persona);
934 }
935 
936 /*
937  * Routine: bank_task_alloc_init
938  * Purpose: Allocate and initialize a bank task structure.
939  * Returns: bank_task_t on Success.
940  *          BANK_TASK_NULL: on Failure.
941  * Notes:   Leaves the task and ledger blank and has only 1 ref,
942  *           needs to take 1 extra ref after the task field is initialized.
943  */
944 static bank_task_t
bank_task_alloc_init(task_t task)945 bank_task_alloc_init(task_t task)
946 {
947 	bank_task_t new_bank_task;
948 	struct persona *persona = NULL;
949 	void *bsd_info = get_bsdtask_info(task);
950 
951 	new_bank_task = zalloc_flags(bank_task_zone, Z_WAITOK | Z_NOFAIL);
952 
953 	new_bank_task->bt_type = BANK_TASK;
954 	new_bank_task->bt_voucher_ref = 0;
955 	new_bank_task->bt_made = 0;
956 	bank_task_ref_init(new_bank_task);
957 
958 	new_bank_task->bt_ledger = LEDGER_NULL;
959 	new_bank_task->bt_hasentitlement = !!bank_task_is_propagate_entitled(task);
960 	queue_init(&new_bank_task->bt_accounts_to_pay);
961 	queue_init(&new_bank_task->bt_accounts_to_charge);
962 	lck_mtx_init(&new_bank_task->bt_acc_to_pay_lock, &bank_lock_grp, &bank_lock_attr);
963 	lck_mtx_init(&new_bank_task->bt_acc_to_charge_lock, &bank_lock_grp, &bank_lock_attr);
964 
965 	/*
966 	 * Initialize the persona_id struct
967 	 */
968 	persona = proc_persona_get(bsd_info);
969 
970 	bzero(&new_bank_task->bt_proc_persona, sizeof(new_bank_task->bt_proc_persona));
971 	new_bank_task->bt_flags = 0;
972 	if (bank_task_is_persona_adoption_allowed(task, persona)) {
973 		new_bank_task->bt_flags |= PROC_PERSONA_INFO_FLAG_ADOPTION_ALLOWED;
974 	}
975 	new_bank_task->bt_unique_pid = proc_uniqueid(bsd_info);
976 	new_bank_task->bt_pid = proc_pid(bsd_info);
977 	new_bank_task->bt_pidversion = proc_pidversion(bsd_info);
978 	new_bank_task->bt_persona_id = persona_get_id(persona);
979 	new_bank_task->bt_persona_uid = persona_get_uid(persona);
980 	new_bank_task->bt_uid = proc_getuid(bsd_info);
981 	new_bank_task->bt_gid = proc_getgid(bsd_info);
982 #if CONFIG_THREAD_GROUPS
983 	new_bank_task->bt_thread_group = thread_group_retain(task_coalition_get_thread_group(task));
984 #endif /* CONFIG_THREAD_GROUPS */
985 #if CONFIG_COALITIONS
986 	coalition_t rsrc_coal = task->coalition[COALITION_TYPE_RESOURCE];
987 	new_bank_task->bt_rsrc_coal_id = rsrc_coal != COALITION_NULL ? coalition_id(rsrc_coal) : 0;
988 #endif /* CONFIG_COALITIONS */
989 	proc_getexecutableuuid(bsd_info, new_bank_task->bt_macho_uuid, sizeof(new_bank_task->bt_macho_uuid));
990 
991 	persona_put(persona);
992 	persona = NULL;
993 
994 #if DEVELOPMENT || DEBUG
995 	new_bank_task->bt_task = NULL;
996 	lck_mtx_lock(&bank_tasks_list_lock);
997 	queue_enter(&bank_tasks_list, new_bank_task, bank_task_t, bt_global_elt);
998 	lck_mtx_unlock(&bank_tasks_list_lock);
999 #endif
1000 	return new_bank_task;
1001 }
1002 
1003 /*
1004  * Routine: proc_is_propagate_entitled
1005  * Purpose: Check if the process is allowed to propagate secure originator.
1006  * Returns: TRUE if entitled.
1007  *          FALSE if not.
1008  */
1009 static boolean_t
bank_task_is_propagate_entitled(task_t t)1010 bank_task_is_propagate_entitled(task_t t)
1011 {
1012 	/* Check if it has an entitlement which disallows secure originator propagation */
1013 	boolean_t entitled = FALSE;
1014 	entitled = IOTaskHasEntitlement(t, ENTITLEMENT_PERSONA_NO_PROPAGATE);
1015 	if (entitled) {
1016 		return FALSE;
1017 	}
1018 
1019 	/* If it's a platform binary, allow propagation by default */
1020 	if (disable_persona_propagate_check || task_get_platform_binary(t)) {
1021 		return TRUE;
1022 	}
1023 
1024 	return FALSE;
1025 }
1026 
1027 /*
1028  * Routine: proc_is_persona_modify_entitled
1029  * Purpose: Check if the process has persona modify entitlement.
1030  * Returns: TRUE if entitled.
1031  *          FALSE if not.
1032  */
1033 static boolean_t
bank_task_is_persona_modify_entitled(task_t t)1034 bank_task_is_persona_modify_entitled(task_t t)
1035 {
1036 	boolean_t entitled = FALSE;
1037 	entitled = IOTaskHasEntitlement(t, ENTITLEMENT_PERSONA_MODIFY);
1038 	return entitled;
1039 }
1040 
1041 /*
1042  * Routine: bank_account_alloc_init
1043  * Purpose: Allocate and Initialize the bank account struct.
1044  * Returns: bank_account_t : On Success.
1045  *          BANK_ACCOUNT_NULL: On Failure.
1046  */
1047 static bank_account_t
bank_account_alloc_init(bank_task_t bank_holder,bank_task_t bank_merchant,bank_task_t bank_secureoriginator,bank_task_t bank_proximateprocess,struct thread_group * thread_group,struct bank_persona * persona)1048 bank_account_alloc_init(
1049 	bank_task_t bank_holder,
1050 	bank_task_t bank_merchant,
1051 	bank_task_t bank_secureoriginator,
1052 	bank_task_t bank_proximateprocess,
1053 	struct thread_group *thread_group,
1054 	struct bank_persona *persona)
1055 {
1056 	bank_account_t new_bank_account;
1057 	bank_account_t bank_account;
1058 	boolean_t entry_found = FALSE;
1059 	ledger_t new_ledger = ledger_instantiate(bank_ledger_template, LEDGER_CREATE_INACTIVE_ENTRIES);
1060 
1061 	if (new_ledger == LEDGER_NULL) {
1062 		return BANK_ACCOUNT_NULL;
1063 	}
1064 
1065 	ledger_entry_setactive(new_ledger, bank_ledgers.cpu_time);
1066 	ledger_entry_setactive(new_ledger, bank_ledgers.energy);
1067 	new_bank_account = zalloc_flags(bank_account_zone, Z_WAITOK | Z_NOFAIL);
1068 
1069 	new_bank_account->ba_type = BANK_ACCOUNT;
1070 	new_bank_account->ba_voucher_ref = 0;
1071 	new_bank_account->ba_made = 1;
1072 	bank_account_ref_init(new_bank_account);
1073 
1074 	new_bank_account->ba_bill = new_ledger;
1075 	new_bank_account->ba_merchant = bank_merchant;
1076 	new_bank_account->ba_holder = bank_holder;
1077 	new_bank_account->ba_secureoriginator = bank_secureoriginator;
1078 	new_bank_account->ba_proximateprocess = bank_proximateprocess;
1079 #if CONFIG_THREAD_GROUPS
1080 	new_bank_account->ba_thread_group = thread_group;
1081 #endif
1082 	new_bank_account->ba_so_persona = *persona;
1083 
1084 	/* Iterate through accounts need to pay list to find the existing entry */
1085 	lck_mtx_lock(&bank_holder->bt_acc_to_pay_lock);
1086 	queue_iterate(&bank_holder->bt_accounts_to_pay, bank_account, bank_account_t, ba_next_acc_to_pay) {
1087 		if (bank_account->ba_merchant != bank_merchant ||
1088 		    bank_account->ba_secureoriginator != bank_secureoriginator ||
1089 		    bank_account->ba_proximateprocess != bank_proximateprocess ||
1090 		    bank_get_bank_account_thread_group(bank_account) != thread_group ||
1091 		    bank_account->ba_so_persona.persona_id != persona->persona_id) {
1092 			continue;
1093 		}
1094 
1095 		entry_found = TRUE;
1096 		/* Take a made ref, since this value would be returned to voucher system. */
1097 		bank_account_made_reference(bank_account);
1098 		break;
1099 	}
1100 
1101 	if (!entry_found) {
1102 		/*  Create a linkage between the holder and the merchant task, Grab both the list locks before adding it to the list. */
1103 		lck_mtx_lock(&bank_merchant->bt_acc_to_charge_lock);
1104 
1105 		/* Add the account entry into Accounts need to pay account link list. */
1106 		queue_enter(&bank_holder->bt_accounts_to_pay, new_bank_account, bank_account_t, ba_next_acc_to_pay);
1107 
1108 		/* Add the account entry into Accounts need to charge account link list. */
1109 		queue_enter(&bank_merchant->bt_accounts_to_charge, new_bank_account, bank_account_t, ba_next_acc_to_charge);
1110 
1111 		lck_mtx_unlock(&bank_merchant->bt_acc_to_charge_lock);
1112 	}
1113 
1114 	lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
1115 
1116 	if (entry_found) {
1117 		ledger_dereference(new_ledger);
1118 		zfree(bank_account_zone, new_bank_account);
1119 		return bank_account;
1120 	}
1121 
1122 	bank_task_reference(bank_holder);
1123 	bank_task_reference(bank_merchant);
1124 	bank_task_reference(bank_secureoriginator);
1125 	bank_task_reference(bank_proximateprocess);
1126 #if CONFIG_THREAD_GROUPS
1127 	assert(new_bank_account->ba_thread_group != NULL);
1128 	thread_group_retain(new_bank_account->ba_thread_group);
1129 #endif
1130 
1131 #if DEVELOPMENT || DEBUG
1132 	new_bank_account->ba_task = NULL;
1133 	lck_mtx_lock(&bank_accounts_list_lock);
1134 	queue_enter(&bank_accounts_list, new_bank_account, bank_account_t, ba_global_elt);
1135 	lck_mtx_unlock(&bank_accounts_list_lock);
1136 #endif
1137 
1138 	return new_bank_account;
1139 }
1140 
1141 /*
1142  * Routine: get_bank_task_context
1143  * Purpose: Get the bank context of the given task
1144  * Returns: bank_task_t on Success.
1145  *          BANK_TASK_NULL: on Failure.
1146  * Note:    Initialize bank context if NULL.
1147  */
1148 static bank_task_t
get_bank_task_context(task_t task,boolean_t initialize)1149 get_bank_task_context
1150 (task_t task,
1151     boolean_t initialize)
1152 {
1153 	bank_task_t bank_task;
1154 
1155 	if (task->bank_context || !initialize) {
1156 		assert(task->bank_context != NULL);
1157 		return task->bank_context;
1158 	}
1159 
1160 	bank_task = bank_task_alloc_init(task);
1161 
1162 	/* Grab the task lock and check if we won the race. */
1163 	task_lock(task);
1164 	if (task->bank_context) {
1165 		task_unlock(task);
1166 		if (bank_task != BANK_TASK_NULL) {
1167 			bank_task_dealloc(bank_task);
1168 		}
1169 		return task->bank_context;
1170 	} else if (bank_task == BANK_TASK_NULL) {
1171 		task_unlock(task);
1172 		return BANK_TASK_NULL;
1173 	}
1174 	/* We won the race. Take a ref on the ledger and initialize bank task. */
1175 	bank_task->bt_ledger = task->ledger;
1176 #if DEVELOPMENT || DEBUG
1177 	bank_task->bt_task = task;
1178 #endif
1179 	ledger_reference(task->ledger);
1180 
1181 	/* Grab the global bank task lock before setting the bank context on a task */
1182 	global_bank_task_lock();
1183 	task->bank_context = bank_task;
1184 	global_bank_task_unlock();
1185 
1186 	task_unlock(task);
1187 
1188 	return bank_task;
1189 }
1190 
1191 /*
1192  * Routine: bank_task_dealloc
1193  * Purpose: Drops the reference on bank task.
1194  * Returns: None.
1195  */
1196 static void
bank_task_dealloc(bank_task_t bank_task)1197 bank_task_dealloc(bank_task_t bank_task)
1198 {
1199 	if (bank_task_release(bank_task) > 0) {
1200 		return;
1201 	}
1202 
1203 	assert(queue_empty(&bank_task->bt_accounts_to_pay));
1204 	assert(queue_empty(&bank_task->bt_accounts_to_charge));
1205 
1206 	assert(!LEDGER_VALID(bank_task->bt_ledger));
1207 	lck_mtx_destroy(&bank_task->bt_acc_to_pay_lock, &bank_lock_grp);
1208 	lck_mtx_destroy(&bank_task->bt_acc_to_charge_lock, &bank_lock_grp);
1209 
1210 #if CONFIG_THREAD_GROUPS
1211 	thread_group_release(bank_task->bt_thread_group);
1212 #endif
1213 
1214 #if DEVELOPMENT || DEBUG
1215 	lck_mtx_lock(&bank_tasks_list_lock);
1216 	queue_remove(&bank_tasks_list, bank_task, bank_task_t, bt_global_elt);
1217 	lck_mtx_unlock(&bank_tasks_list_lock);
1218 #endif
1219 
1220 	zfree(bank_task_zone, bank_task);
1221 }
1222 
1223 /*
1224  * Routine: bank_account_dealloc_with_sync
1225  * Purpose: Drop the reference on bank account if the sync matches.
1226  * Returns: KERN_SUCCESS if sync matches.
1227  *          KERN_FAILURE on mismatch.
1228  */
1229 static kern_return_t
bank_account_dealloc_with_sync(bank_account_t bank_account,mach_voucher_attr_value_reference_t sync)1230 bank_account_dealloc_with_sync(
1231 	bank_account_t bank_account,
1232 	mach_voucher_attr_value_reference_t sync)
1233 {
1234 	bank_task_t bank_holder = bank_account->ba_holder;
1235 	bank_task_t bank_merchant = bank_account->ba_merchant;
1236 	bank_task_t bank_secureoriginator = bank_account->ba_secureoriginator;
1237 	bank_task_t bank_proximateprocess = bank_account->ba_proximateprocess;
1238 	ledger_t bank_merchant_ledger = LEDGER_NULL;
1239 
1240 	/*
1241 	 * Grab a reference on the bank_merchant_ledger, since we would not be able
1242 	 * to take bt_acc_to_pay_lock for bank_merchant later.
1243 	 */
1244 	bank_merchant_ledger = bank_get_bank_task_ledger_with_ref(bank_merchant);
1245 
1246 	/* Grab the acc to pay list lock and check the sync value */
1247 	lck_mtx_lock(&bank_holder->bt_acc_to_pay_lock);
1248 
1249 	if (bank_account->ba_made != sync) {
1250 		lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
1251 		if (bank_merchant_ledger) {
1252 			ledger_dereference(bank_merchant_ledger);
1253 		}
1254 		return KERN_FAILURE;
1255 	}
1256 
1257 	bank_account_made_release_num(bank_account, sync);
1258 
1259 	if (bank_account_release(bank_account) > 0) {
1260 		panic("Releasing a non zero ref bank account %p", bank_account);
1261 	}
1262 
1263 
1264 	/* Grab both the acc to pay and acc to charge locks */
1265 	lck_mtx_lock(&bank_merchant->bt_acc_to_charge_lock);
1266 
1267 	/* No need to take ledger reference for bank_holder ledger since bt_acc_to_pay_lock is locked */
1268 	bank_rollup_chit_to_tasks(bank_account->ba_bill, bank_holder->bt_ledger, bank_merchant_ledger,
1269 	    bank_holder->bt_pid, bank_merchant->bt_pid);
1270 
1271 	/* Remove the account entry from Accounts need to pay account link list. */
1272 	queue_remove(&bank_holder->bt_accounts_to_pay, bank_account, bank_account_t, ba_next_acc_to_pay);
1273 
1274 	/* Remove the account entry from Accounts need to charge account link list. */
1275 	queue_remove(&bank_merchant->bt_accounts_to_charge, bank_account, bank_account_t, ba_next_acc_to_charge);
1276 
1277 	lck_mtx_unlock(&bank_merchant->bt_acc_to_charge_lock);
1278 	lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
1279 
1280 	if (bank_merchant_ledger) {
1281 		ledger_dereference(bank_merchant_ledger);
1282 	}
1283 	ledger_dereference(bank_account->ba_bill);
1284 
1285 	/* Drop the reference of bank holder and merchant */
1286 	bank_task_dealloc(bank_holder);
1287 	bank_task_dealloc(bank_merchant);
1288 	bank_task_dealloc(bank_secureoriginator);
1289 	bank_task_dealloc(bank_proximateprocess);
1290 #if CONFIG_THREAD_GROUPS
1291 	assert(bank_account->ba_thread_group != NULL);
1292 	thread_group_release(bank_account->ba_thread_group);
1293 #endif
1294 
1295 #if DEVELOPMENT || DEBUG
1296 	lck_mtx_lock(&bank_accounts_list_lock);
1297 	queue_remove(&bank_accounts_list, bank_account, bank_account_t, ba_global_elt);
1298 	lck_mtx_unlock(&bank_accounts_list_lock);
1299 #endif
1300 
1301 	zfree(bank_account_zone, bank_account);
1302 	return KERN_SUCCESS;
1303 }
1304 
1305 /*
1306  * Routine: bank_rollup_chit_to_tasks
1307  * Purpose: Debit and Credit holder's and merchant's ledgers.
1308  * Returns: None.
1309  */
1310 static void
bank_rollup_chit_to_tasks(ledger_t bill,ledger_t bank_holder_ledger,ledger_t bank_merchant_ledger,int bank_holder_pid,int bank_merchant_pid)1311 bank_rollup_chit_to_tasks(
1312 	ledger_t bill,
1313 	ledger_t bank_holder_ledger,
1314 	ledger_t bank_merchant_ledger,
1315 	int bank_holder_pid,
1316 	int bank_merchant_pid)
1317 {
1318 	ledger_amount_t credit;
1319 	ledger_amount_t debit;
1320 	kern_return_t ret;
1321 
1322 	if (bank_holder_ledger == bank_merchant_ledger) {
1323 		return;
1324 	}
1325 
1326 	ret = ledger_get_entries(bill, bank_ledgers.cpu_time, &credit, &debit);
1327 	if (ret == KERN_SUCCESS) {
1328 		KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
1329 		    (BANK_CODE(BANK_ACCOUNT_INFO, (BANK_SETTLE_CPU_TIME))) | DBG_FUNC_NONE,
1330 		    bank_merchant_pid, bank_holder_pid, credit, debit, 0);
1331 
1332 		if (bank_holder_ledger) {
1333 			ledger_credit(bank_holder_ledger, task_ledgers.cpu_time_billed_to_me, credit);
1334 			ledger_debit(bank_holder_ledger, task_ledgers.cpu_time_billed_to_me, debit);
1335 		}
1336 
1337 		if (bank_merchant_ledger) {
1338 			ledger_credit(bank_merchant_ledger, task_ledgers.cpu_time_billed_to_others, credit);
1339 			ledger_debit(bank_merchant_ledger, task_ledgers.cpu_time_billed_to_others, debit);
1340 		}
1341 	}
1342 
1343 	ret = ledger_get_entries(bill, bank_ledgers.energy, &credit, &debit);
1344 	if (ret == KERN_SUCCESS) {
1345 		KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
1346 		    (BANK_CODE(BANK_ACCOUNT_INFO, (BANK_SETTLE_ENERGY))) | DBG_FUNC_NONE,
1347 		    bank_merchant_pid, bank_holder_pid, credit, debit, 0);
1348 
1349 		if (bank_holder_ledger) {
1350 			ledger_credit(bank_holder_ledger, task_ledgers.energy_billed_to_me, credit);
1351 			ledger_debit(bank_holder_ledger, task_ledgers.energy_billed_to_me, debit);
1352 		}
1353 
1354 		if (bank_merchant_ledger) {
1355 			ledger_credit(bank_merchant_ledger, task_ledgers.energy_billed_to_others, credit);
1356 			ledger_debit(bank_merchant_ledger, task_ledgers.energy_billed_to_others, debit);
1357 		}
1358 	}
1359 }
1360 
1361 
1362 
1363 /*
1364  * Routine: bank_task_destroy
1365  * Purpose: Drops reference on bank task.
1366  * Returns: None.
1367  */
1368 void
bank_task_destroy(task_t task)1369 bank_task_destroy(task_t task)
1370 {
1371 	bank_task_t bank_task;
1372 
1373 	/* Grab the global bank task lock before dropping the ref on task bank context */
1374 	global_bank_task_lock();
1375 	bank_task = task->bank_context;
1376 	task->bank_context = NULL;
1377 	global_bank_task_unlock();
1378 
1379 	bank_destroy_bank_task_ledger(bank_task);
1380 	bank_task_dealloc(bank_task);
1381 }
1382 
1383 /*
1384  * Routine: bank_task_initialize
1385  * Purpose: Initialize the bank context of a task.
1386  * Returns: None.
1387  */
1388 void
bank_task_initialize(task_t task)1389 bank_task_initialize(task_t task)
1390 {
1391 	get_bank_task_context(task, TRUE);
1392 }
1393 
1394 /*
1395  * Routine: init_bank_ledgers
1396  * Purpose: Initialize template for bank ledgers.
1397  * Returns: None.
1398  */
1399 static void
init_bank_ledgers(void)1400 init_bank_ledgers(void)
1401 {
1402 	ledger_template_t t;
1403 	int idx;
1404 
1405 	assert(bank_ledger_template == NULL);
1406 
1407 	if ((t = ledger_template_create("Bank ledger")) == NULL) {
1408 		panic("couldn't create bank ledger template");
1409 	}
1410 
1411 	if ((idx = ledger_entry_add(t, "cpu_time", "sched", "ns")) < 0) {
1412 		panic("couldn't create cpu_time entry for bank ledger template");
1413 	}
1414 	bank_ledgers.cpu_time = idx;
1415 
1416 	if ((idx = ledger_entry_add(t, "energy", "power", "nj")) < 0) {
1417 		panic("couldn't create energy entry for bank ledger template");
1418 	}
1419 	bank_ledgers.energy = idx;
1420 
1421 	ledger_template_complete(t);
1422 	bank_ledger_template = t;
1423 }
1424 
1425 /* Routine: bank_billed_balance_safe
1426  * Purpose: Walk through all the bank accounts billed to me by other tasks and get the current billing balance.
1427  *          Called from another task. It takes global bank task lock to make sure the bank context is
1428  *           not deallocated while accesing it.
1429  * Returns: cpu balance and energy balance in out paremeters.
1430  */
1431 void
bank_billed_balance_safe(task_t task,uint64_t * cpu_time,uint64_t * energy)1432 bank_billed_balance_safe(task_t task, uint64_t *cpu_time, uint64_t *energy)
1433 {
1434 	bank_task_t bank_task = BANK_TASK_NULL;
1435 	ledger_amount_t credit, debit;
1436 	uint64_t cpu_balance = 0;
1437 	uint64_t energy_balance = 0;
1438 	kern_return_t kr;
1439 
1440 	/* Task might be in exec, grab the global bank task lock before accessing bank context. */
1441 	global_bank_task_lock();
1442 	/* Grab a reference on bank context */
1443 	if (task->bank_context != NULL) {
1444 		bank_task = task->bank_context;
1445 		bank_task_reference(bank_task);
1446 	}
1447 	global_bank_task_unlock();
1448 
1449 	if (bank_task) {
1450 		bank_billed_balance(bank_task, &cpu_balance, &energy_balance);
1451 		bank_task_dealloc(bank_task);
1452 	} else {
1453 		kr = ledger_get_entries(task->ledger, task_ledgers.cpu_time_billed_to_me,
1454 		    &credit, &debit);
1455 		if (kr == KERN_SUCCESS) {
1456 			cpu_balance = credit - debit;
1457 		}
1458 		kr = ledger_get_entries(task->ledger, task_ledgers.energy_billed_to_me,
1459 		    &credit, &debit);
1460 		if (kr == KERN_SUCCESS) {
1461 			energy_balance = credit - debit;
1462 		}
1463 	}
1464 
1465 	*cpu_time = cpu_balance;
1466 	*energy = energy_balance;
1467 	return;
1468 }
1469 
1470 /*
1471  * Routine: bank_billed_time
1472  * Purpose: Walk through the Accounts need to pay account list and get the current billing balance.
1473  * Returns: cpu balance and energy balance in out paremeters.
1474  */
1475 void
bank_billed_balance(bank_task_t bank_task,uint64_t * cpu_time,uint64_t * energy)1476 bank_billed_balance(bank_task_t bank_task, uint64_t *cpu_time, uint64_t *energy)
1477 {
1478 	int64_t cpu_balance = 0;
1479 	int64_t energy_balance = 0;
1480 	bank_account_t bank_account;
1481 	int64_t temp = 0;
1482 	kern_return_t kr;
1483 	if (bank_task == BANK_TASK_NULL) {
1484 		*cpu_time = 0;
1485 		*energy = 0;
1486 		return;
1487 	}
1488 
1489 	lck_mtx_lock(&bank_task->bt_acc_to_pay_lock);
1490 
1491 	/* bt_acc_to_pay_lock locked, no need to take ledger reference for bt_ledger */
1492 	if (bank_task->bt_ledger != LEDGER_NULL) {
1493 		kr = ledger_get_balance(bank_task->bt_ledger, task_ledgers.cpu_time_billed_to_me, &temp);
1494 		if (kr == KERN_SUCCESS && temp >= 0) {
1495 			cpu_balance += temp;
1496 		}
1497 #if DEVELOPMENT || DEBUG
1498 		else {
1499 			printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1500 		}
1501 #endif /* DEVELOPMENT || DEBUG */
1502 
1503 		kr = ledger_get_balance(bank_task->bt_ledger, task_ledgers.energy_billed_to_me, &temp);
1504 		if (kr == KERN_SUCCESS && temp >= 0) {
1505 			energy_balance += temp;
1506 		}
1507 	}
1508 
1509 	queue_iterate(&bank_task->bt_accounts_to_pay, bank_account, bank_account_t, ba_next_acc_to_pay) {
1510 		temp = 0;
1511 		kr = ledger_get_balance(bank_account->ba_bill, bank_ledgers.cpu_time, &temp);
1512 		if (kr == KERN_SUCCESS && temp >= 0) {
1513 			cpu_balance += temp;
1514 		}
1515 #if DEVELOPMENT || DEBUG
1516 		else {
1517 			printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1518 		}
1519 #endif /* DEVELOPMENT || DEBUG */
1520 
1521 		kr = ledger_get_balance(bank_account->ba_bill, bank_ledgers.energy, &temp);
1522 		if (kr == KERN_SUCCESS && temp >= 0) {
1523 			energy_balance += temp;
1524 		}
1525 	}
1526 	lck_mtx_unlock(&bank_task->bt_acc_to_pay_lock);
1527 	*cpu_time = (uint64_t)cpu_balance;
1528 	*energy = (uint64_t)energy_balance;
1529 	return;
1530 }
1531 
1532 /* Routine: bank_serviced_balance_safe
1533  * Purpose: Walk through the bank accounts billed to other tasks by me and get the current balance to be charged.
1534  *          Called from another task. It takes global bank task lock to make sure the bank context is
1535  *           not deallocated while accesing it.
1536  * Returns: cpu balance and energy balance in out paremeters.
1537  */
1538 void
bank_serviced_balance_safe(task_t task,uint64_t * cpu_time,uint64_t * energy)1539 bank_serviced_balance_safe(task_t task, uint64_t *cpu_time, uint64_t *energy)
1540 {
1541 	bank_task_t bank_task = BANK_TASK_NULL;
1542 	ledger_amount_t credit, debit;
1543 	uint64_t cpu_balance = 0;
1544 	uint64_t energy_balance = 0;
1545 	kern_return_t kr;
1546 
1547 	/* Task might be in exec, grab the global bank task lock before accessing bank context. */
1548 	global_bank_task_lock();
1549 	/* Grab a reference on bank context */
1550 	if (task->bank_context != NULL) {
1551 		bank_task = task->bank_context;
1552 		bank_task_reference(bank_task);
1553 	}
1554 	global_bank_task_unlock();
1555 
1556 	if (bank_task) {
1557 		bank_serviced_balance(bank_task, &cpu_balance, &energy_balance);
1558 		bank_task_dealloc(bank_task);
1559 	} else {
1560 		kr = ledger_get_entries(task->ledger, task_ledgers.cpu_time_billed_to_others,
1561 		    &credit, &debit);
1562 		if (kr == KERN_SUCCESS) {
1563 			cpu_balance = credit - debit;
1564 		}
1565 
1566 		kr = ledger_get_entries(task->ledger, task_ledgers.energy_billed_to_others,
1567 		    &credit, &debit);
1568 		if (kr == KERN_SUCCESS) {
1569 			energy_balance = credit - debit;
1570 		}
1571 	}
1572 
1573 	*cpu_time = cpu_balance;
1574 	*energy = energy_balance;
1575 	return;
1576 }
1577 
1578 /*
1579  * Routine: bank_serviced_balance
1580  * Purpose: Walk through the Account need to charge account list and get the current balance to be charged.
1581  * Returns: cpu balance and energy balance in out paremeters.
1582  */
1583 void
bank_serviced_balance(bank_task_t bank_task,uint64_t * cpu_time,uint64_t * energy)1584 bank_serviced_balance(bank_task_t bank_task, uint64_t *cpu_time, uint64_t *energy)
1585 {
1586 	int64_t cpu_balance = 0;
1587 	int64_t energy_balance = 0;
1588 	bank_account_t bank_account;
1589 	int64_t temp = 0;
1590 	kern_return_t kr;
1591 	ledger_t ledger = LEDGER_NULL;
1592 	if (bank_task == BANK_TASK_NULL) {
1593 		*cpu_time = 0;
1594 		*energy = 0;
1595 		return;
1596 	}
1597 
1598 	/* Grab a ledger reference on bt_ledger for bank_task */
1599 	ledger = bank_get_bank_task_ledger_with_ref(bank_task);
1600 
1601 	lck_mtx_lock(&bank_task->bt_acc_to_charge_lock);
1602 
1603 	if (ledger) {
1604 		kr = ledger_get_balance(ledger, task_ledgers.cpu_time_billed_to_others, &temp);
1605 		if (kr == KERN_SUCCESS && temp >= 0) {
1606 			cpu_balance += temp;
1607 		}
1608 #if DEVELOPMENT || DEBUG
1609 		else {
1610 			printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1611 		}
1612 #endif /* DEVELOPMENT || DEBUG */
1613 
1614 		kr = ledger_get_balance(ledger, task_ledgers.energy_billed_to_others, &temp);
1615 		if (kr == KERN_SUCCESS && temp >= 0) {
1616 			energy_balance += temp;
1617 		}
1618 	}
1619 
1620 	queue_iterate(&bank_task->bt_accounts_to_charge, bank_account, bank_account_t, ba_next_acc_to_charge) {
1621 		temp = 0;
1622 		kr = ledger_get_balance(bank_account->ba_bill, bank_ledgers.cpu_time, &temp);
1623 		if (kr == KERN_SUCCESS && temp >= 0) {
1624 			cpu_balance += temp;
1625 		}
1626 #if DEVELOPMENT || DEBUG
1627 		else {
1628 			printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1629 		}
1630 #endif /* DEVELOPMENT || DEBUG */
1631 
1632 		kr = ledger_get_balance(bank_account->ba_bill, bank_ledgers.energy, &temp);
1633 		if (kr == KERN_SUCCESS && temp >= 0) {
1634 			energy_balance += temp;
1635 		}
1636 	}
1637 	lck_mtx_unlock(&bank_task->bt_acc_to_charge_lock);
1638 	if (ledger) {
1639 		ledger_dereference(ledger);
1640 	}
1641 	*cpu_time = (uint64_t)cpu_balance;
1642 	*energy = (uint64_t)energy_balance;
1643 	return;
1644 }
1645 
1646 /*
1647  * Routine: bank_get_voucher_bank_account
1648  * Purpose: Get the bank account from the voucher.
1649  * Returns: bank_account if bank_account attribute present in voucher.
1650  *          NULL on no attribute or no bank_element
1651  */
1652 static bank_account_t
bank_get_voucher_bank_account(ipc_voucher_t voucher)1653 bank_get_voucher_bank_account(ipc_voucher_t voucher)
1654 {
1655 	bank_element_t bank_element = BANK_ELEMENT_NULL;
1656 	bank_account_t bank_account = BANK_ACCOUNT_NULL;
1657 	mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED];
1658 	mach_voucher_attr_value_handle_array_size_t val_count;
1659 	kern_return_t kr;
1660 
1661 	val_count = MACH_VOUCHER_ATTR_VALUE_MAX_NESTED;
1662 	kr = mach_voucher_attr_control_get_values(bank_voucher_attr_control,
1663 	    voucher,
1664 	    vals,
1665 	    &val_count);
1666 
1667 	if (kr != KERN_SUCCESS || val_count == 0) {
1668 		return BANK_ACCOUNT_NULL;
1669 	}
1670 
1671 	bank_element = HANDLE_TO_BANK_ELEMENT(vals[0]);
1672 	if (bank_element == BANK_DEFAULT_VALUE) {
1673 		return BANK_ACCOUNT_NULL;
1674 	}
1675 	if (bank_element == BANK_DEFAULT_TASK_VALUE) {
1676 		bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
1677 	}
1678 
1679 	if (bank_element->be_type == BANK_TASK) {
1680 		return BANK_ACCOUNT_NULL;
1681 	} else if (bank_element->be_type == BANK_ACCOUNT) {
1682 		bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
1683 		return bank_account;
1684 	} else {
1685 		panic("Bogus bank type: %d passed in bank_get_voucher_bank_account", bank_element->be_type);
1686 	}
1687 	return BANK_ACCOUNT_NULL;
1688 }
1689 
1690 /*
1691  * Routine: bank_get_bank_task_ledger_with_ref
1692  * Purpose: Get the bank ledger from the bank task and return a reference to it.
1693  */
1694 static ledger_t
bank_get_bank_task_ledger_with_ref(bank_task_t bank_task)1695 bank_get_bank_task_ledger_with_ref(bank_task_t bank_task)
1696 {
1697 	ledger_t ledger = LEDGER_NULL;
1698 
1699 	lck_mtx_lock(&bank_task->bt_acc_to_pay_lock);
1700 	ledger = bank_task->bt_ledger;
1701 	if (ledger) {
1702 		ledger_reference(ledger);
1703 	}
1704 	lck_mtx_unlock(&bank_task->bt_acc_to_pay_lock);
1705 
1706 	return ledger;
1707 }
1708 
1709 /*
1710  * Routine: bank_destroy_bank_task_ledger
1711  * Purpose: Drop the bank task reference on the task ledger.
1712  */
1713 static void
bank_destroy_bank_task_ledger(bank_task_t bank_task)1714 bank_destroy_bank_task_ledger(bank_task_t bank_task)
1715 {
1716 	ledger_t ledger;
1717 
1718 	/* Remove the ledger reference from the bank task */
1719 	lck_mtx_lock(&bank_task->bt_acc_to_pay_lock);
1720 	assert(LEDGER_VALID(bank_task->bt_ledger));
1721 	ledger = bank_task->bt_ledger;
1722 	bank_task->bt_ledger = LEDGER_NULL;
1723 	lck_mtx_unlock(&bank_task->bt_acc_to_pay_lock);
1724 
1725 	ledger_dereference(ledger);
1726 }
1727 
1728 /*
1729  * Routine: bank_get_bank_account_ledger
1730  * Purpose: Get the bankledger from the bank account if ba_merchant different than ba_holder
1731  */
1732 static ledger_t
bank_get_bank_account_ledger(bank_account_t bank_account)1733 bank_get_bank_account_ledger(bank_account_t bank_account)
1734 {
1735 	ledger_t bankledger = LEDGER_NULL;
1736 
1737 	if (bank_account != BANK_ACCOUNT_NULL &&
1738 	    bank_account->ba_holder != bank_account->ba_merchant) {
1739 		bankledger = bank_account->ba_bill;
1740 	}
1741 
1742 	return bankledger;
1743 }
1744 
1745 #if CONFIG_PREADOPT_TG
1746 /*
1747  * Routine: bank_get_preadopt_thread_group
1748  * Purpose: Get the thread group from the voucher for preadoption
1749  *                      (assuming post process is not done on voucher).
1750  * Returns: thread group for pre adoption
1751  * Note: Make sure that the receiver is not an App before preadopting the voucher.
1752  */
1753 kern_return_t
bank_get_preadopt_thread_group(ipc_voucher_t voucher,struct thread_group ** banktg)1754 bank_get_preadopt_thread_group(ipc_voucher_t     voucher,
1755     struct thread_group **banktg)
1756 {
1757 	bank_account_t bank_account = BANK_ACCOUNT_NULL;
1758 	bank_task_t bank_task = BANK_TASK_NULL;
1759 	struct thread_group *thread_group = NULL;
1760 	mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED];
1761 	mach_voucher_attr_value_handle_array_size_t val_count;
1762 	bank_element_t bank_element = BANK_ELEMENT_NULL;
1763 
1764 	kern_return_t kr;
1765 	val_count = MACH_VOUCHER_ATTR_VALUE_MAX_NESTED;
1766 	kr = mach_voucher_attr_control_get_values(bank_voucher_attr_control,
1767 	    voucher,
1768 	    vals,
1769 	    &val_count);
1770 	if (kr != KERN_SUCCESS || val_count == 0) {
1771 		goto errorout;
1772 	}
1773 	bank_element = HANDLE_TO_BANK_ELEMENT(vals[0]);
1774 	if (bank_element == BANK_DEFAULT_VALUE) {
1775 		goto errorout;
1776 	}
1777 
1778 	if (bank_element == BANK_DEFAULT_TASK_VALUE) {
1779 		bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
1780 	}
1781 
1782 	if (bank_element->be_type == BANK_TASK) {
1783 		bank_task = CAST_TO_BANK_TASK(bank_element);
1784 	} else if (bank_element->be_type == BANK_ACCOUNT) {
1785 		bank_account = CAST_TO_BANK_ACCOUNT(bank_element);
1786 	} else {
1787 		panic("Bogus bank type: %d passed in bank_get_preadopt_thread_group", bank_element->be_type);
1788 	}
1789 
1790 errorout:
1791 	if (banktg != NULL) {
1792 		/* If the voucher has bank account, then give the thread group from
1793 		 * bank account. If the voucher has a bank task, this is the sender's bank task,
1794 		 * the receiver will convert the sender's bank task to bank account, so give
1795 		 * thread group from the bank task. */
1796 		if (bank_account != NULL) {
1797 			thread_group = bank_get_bank_account_thread_group(bank_account);
1798 		} else if (bank_task != NULL) {
1799 			thread_group = bank_get_bank_task_thread_group(bank_task);
1800 		}
1801 		*banktg = thread_group;
1802 	}
1803 	return KERN_SUCCESS;
1804 }
1805 #endif
1806 
1807 /*
1808  * Routine: bank_get_bank_task_thread_group
1809  * Purpose: Get the bank task's thread group from the bank task
1810  */
1811 static struct thread_group *
bank_get_bank_task_thread_group(bank_task_t bank_task __unused)1812 bank_get_bank_task_thread_group(bank_task_t bank_task __unused)
1813 {
1814 	struct thread_group *banktg = NULL;
1815 
1816 #if CONFIG_THREAD_GROUPS
1817 	if (bank_task != BANK_TASK_NULL) {
1818 		banktg = bank_task->bt_thread_group;
1819 	}
1820 #endif /* CONFIG_THREAD_GROUPS */
1821 
1822 	return banktg;
1823 }
1824 
1825 /*
1826  * Routine: bank_get_bank_account_thread_group
1827  * Purpose: Get the bank account's thread group from the bank account
1828  */
1829 static struct thread_group *
bank_get_bank_account_thread_group(bank_account_t bank_account __unused)1830 bank_get_bank_account_thread_group(bank_account_t bank_account __unused)
1831 {
1832 	struct thread_group *banktg = NULL;
1833 
1834 #if CONFIG_THREAD_GROUPS
1835 	if (bank_account != BANK_ACCOUNT_NULL) {
1836 		banktg = bank_account->ba_thread_group;
1837 	}
1838 #endif /* CONFIG_THREAD_GROUPS */
1839 
1840 	return banktg;
1841 }
1842 
1843 static uint64_t
bank_get_bank_account_holder_resource_coalition_id(bank_account_t bank_account __unused)1844 bank_get_bank_account_holder_resource_coalition_id(bank_account_t bank_account __unused)
1845 {
1846 #if CONFIG_COALITIONS
1847 	if (bank_account != BANK_ACCOUNT_NULL) {
1848 		bank_task_t bank_task = bank_account->ba_holder;
1849 		if (bank_task != BANK_TASK_NULL) {
1850 			return bank_task->bt_rsrc_coal_id;
1851 		}
1852 	}
1853 #endif /* CONFIG_COALITIONS */
1854 	return 0;
1855 }
1856 
1857 /*
1858  * Routine: bank_get_bank_ledger_thread_group_and_persona
1859  * Purpose: Get the bankledger (chit), thread group and persona id from the voucher.
1860  * Returns: bankledger, thread group if bank_account attribute present in voucher
1861  *          and persona_id
1862  */
1863 kern_return_t
bank_get_bank_ledger_thread_group_and_persona(ipc_voucher_t voucher,ledger_t * bankledger,struct thread_group ** banktg,uint32_t * persona_id)1864 bank_get_bank_ledger_thread_group_and_persona(
1865 	ipc_voucher_t     voucher,
1866 	ledger_t          *bankledger,
1867 	struct thread_group **banktg,
1868 	uint32_t *persona_id)
1869 {
1870 	bank_account_t bank_account;
1871 	bank_task_t bank_task;
1872 	struct thread_group *thread_group = NULL;
1873 
1874 	bank_account = bank_get_voucher_bank_account(voucher);
1875 	bank_task = get_bank_task_context(current_task(), FALSE);
1876 	if (persona_id != NULL) {
1877 		if (bank_account != BANK_ACCOUNT_NULL) {
1878 			*persona_id = bank_account->ba_so_persona.persona_id;
1879 		} else {
1880 			*persona_id = bank_task->bt_persona_id;
1881 		}
1882 	}
1883 	/*
1884 	 * Use BANK_ACCOUNT_NULL if the ba_holder is same as ba_merchant
1885 	 * and bank account thread group is same as current thread group
1886 	 * i.e. ba_merchant's thread group.
1887 	 *
1888 	 * The bank account might have ba_holder same as ba_merchant but different
1889 	 * thread group if daemon sends a voucher to an App and then App sends the
1890 	 * same voucher back to the daemon (IPC code will replace thread group in the
1891 	 * voucher to App's thread group when it gets auto redeemed by the App).
1892 	 */
1893 	if ((bank_account != NULL) &&
1894 	    (bank_account->ba_holder == bank_account->ba_merchant) &&
1895 	    (bank_get_bank_account_thread_group(bank_account) ==
1896 	    bank_get_bank_task_thread_group(bank_account->ba_merchant))) {
1897 		bank_account = BANK_ACCOUNT_NULL;
1898 	}
1899 
1900 	if (bankledger != NULL) {
1901 		*bankledger = bank_get_bank_account_ledger(bank_account);
1902 	}
1903 
1904 	if (banktg != NULL) {
1905 		thread_group = bank_get_bank_account_thread_group(bank_account);
1906 
1907 		/* Return NULL thread group if voucher has current task's thread group */
1908 		if (thread_group == bank_get_bank_task_thread_group(bank_task)) {
1909 			thread_group = NULL;
1910 		}
1911 		*banktg = thread_group;
1912 	}
1913 	return KERN_SUCCESS;
1914 }
1915 
1916 uint64_t
bank_get_bank_ledger_resource_coalition_id(ipc_voucher_t voucher)1917 bank_get_bank_ledger_resource_coalition_id(
1918 	ipc_voucher_t     voucher)
1919 {
1920 	bank_account_t bank_account = bank_get_voucher_bank_account(voucher);
1921 	return bank_account != NULL ?
1922 	       bank_get_bank_account_holder_resource_coalition_id(bank_account) :
1923 	       0;
1924 }
1925 
1926 /*
1927  * Routine: bank_swap_thread_bank_ledger
1928  * Purpose: swap the bank ledger on the thread.
1929  * Returns: None.
1930  * Note: Should be only called for current thread or thread which is not started.
1931  */
1932 void
bank_swap_thread_bank_ledger(thread_t thread __unused,ledger_t new_ledger __unused)1933 bank_swap_thread_bank_ledger(thread_t thread __unused, ledger_t new_ledger __unused)
1934 {
1935 	spl_t                   s;
1936 	processor_t             processor;
1937 	ledger_t old_ledger = thread->t_bankledger;
1938 	int64_t ctime, effective_ledger_time_consumed = 0;
1939 	int64_t remainder = 0, consumed = 0;
1940 	int64_t effective_energy_consumed = 0;
1941 	uint64_t thread_energy;
1942 
1943 	if (old_ledger == LEDGER_NULL && new_ledger == LEDGER_NULL) {
1944 		return;
1945 	}
1946 
1947 	assert((thread == current_thread() || thread->started == 0));
1948 
1949 	s = splsched();
1950 	thread_lock(thread);
1951 
1952 	/*
1953 	 * Calculation of time elapsed by the thread before voucher swap.
1954 	 * Following is the timeline which shows all the variables used in the calculation below.
1955 	 *
1956 	 *               thread ledger
1957 	 *                 cpu_time
1958 	 *                    |<-          consumed            ->|<- remainder  ->|
1959 	 * timeline  ----------------------------------------------------------------->
1960 	 *                    |                                  |                |
1961 	 *             thread_dispatch                        ctime           quantum end
1962 	 *
1963 	 *                           |<-effective_ledger_time -> |
1964 	 *               deduct_bank_ledger_time
1965 	 */
1966 
1967 	ctime = mach_absolute_time();
1968 	processor = thread->last_processor;
1969 	if (processor != NULL) {
1970 		if ((int64_t)processor->quantum_end > ctime) {
1971 			remainder = (int64_t)processor->quantum_end - ctime;
1972 		}
1973 
1974 		consumed = thread->quantum_remaining - remainder;
1975 		effective_ledger_time_consumed = consumed - thread->t_deduct_bank_ledger_time;
1976 	}
1977 
1978 	thread->t_deduct_bank_ledger_time = consumed;
1979 
1980 	thread_energy = recount_current_thread_energy_nj();
1981 	effective_energy_consumed =
1982 	    thread_energy - thread->t_deduct_bank_ledger_energy;
1983 	assert(effective_energy_consumed >= 0);
1984 	thread->t_deduct_bank_ledger_energy = thread_energy;
1985 
1986 	thread->t_bankledger = new_ledger;
1987 
1988 	thread_unlock(thread);
1989 	splx(s);
1990 
1991 	if (old_ledger != LEDGER_NULL) {
1992 		ledger_credit(old_ledger,
1993 		    bank_ledgers.cpu_time,
1994 		    effective_ledger_time_consumed);
1995 		ledger_credit(old_ledger,
1996 		    bank_ledgers.energy,
1997 		    effective_energy_consumed);
1998 	}
1999 }
2000 
2001 /*
2002  * Routine: bank_verify_persona_id
2003  * Purpose: Verifies if the persona id is valid
2004  *
2005  * The caller should check if the task is entitled
2006  * to do the lookup.
2007  */
2008 static boolean_t
bank_verify_persona_id(uint32_t persona_id,struct bank_persona * persona_out)2009 bank_verify_persona_id(uint32_t persona_id, struct bank_persona *persona_out)
2010 {
2011 	/* A successful lookup implies that the persona id is valid */
2012 	void *persona = persona_lookup(persona_id);
2013 	if (!persona) {
2014 		return FALSE;
2015 	}
2016 
2017 	persona_out->persona_id = persona_id;
2018 	persona_out->persona_uid = persona_get_uid(persona);
2019 
2020 	persona_put(persona);
2021 
2022 	return TRUE;
2023 }
2024 
2025 static boolean_t
bank_task_can_adopt_persona(bank_task_t bank_merchant,struct bank_persona * persona)2026 bank_task_can_adopt_persona(bank_task_t bank_merchant, struct bank_persona *persona)
2027 {
2028 	if (bank_merchant->bt_persona_id == persona->persona_id) {
2029 		return TRUE;
2030 	}
2031 
2032 	if ((bank_merchant->bt_flags & PROC_PERSONA_INFO_FLAG_ADOPTION_ALLOWED) == 0) {
2033 		return FALSE;
2034 	}
2035 
2036 	/*
2037 	 * If persona UID is set, and it's not a System session persona that doesn't
2038 	 * belong to any user (UINT_MAX), new persona UID needs to match the old
2039 	 * one.
2040 	 */
2041 	uint32_t own_uid = bank_merchant->bt_persona_uid;
2042 	uint32_t new_uid = persona->persona_uid;
2043 	return own_uid == KAUTH_UID_NONE || own_uid == UINT_MAX || own_uid == new_uid;
2044 }
2045 
2046 static void
bank_task_get_persona(bank_task_t bank_task,struct bank_persona * persona_out)2047 bank_task_get_persona(bank_task_t bank_task, struct bank_persona *persona_out)
2048 {
2049 	persona_out->persona_id = bank_task->bt_persona_id;
2050 	persona_out->persona_uid = bank_task->bt_persona_uid;
2051 }
2052