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