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
57static ZONE_DEFINE_TYPE(bank_task_zone, "bank_task",
58 struct bank_task, ZC_NONE);
59static 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
73ipc_voucher_attr_control_t bank_voucher_attr_control; /* communication channel from ATM to voucher system */
74
75static ledger_template_t bank_ledger_template = NULL;
76struct _bank_ledger_indices bank_ledgers = { .cpu_time = -1, .energy = -1 };
77
78static bank_task_t bank_task_alloc_init(task_t task);
79static 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);
81static bank_task_t get_bank_task_context(task_t task, boolean_t initialize);
82static void bank_task_dealloc(bank_task_t bank_task);
83static kern_return_t bank_account_dealloc_with_sync(bank_account_t bank_account, mach_voucher_attr_value_reference_t sync);
84static 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);
86static ledger_t bank_get_bank_task_ledger_with_ref(bank_task_t bank_task);
87static void bank_destroy_bank_task_ledger(bank_task_t bank_task);
88static void init_bank_ledgers(void);
89static boolean_t bank_task_is_propagate_entitled(task_t t);
90static boolean_t bank_task_is_persona_modify_entitled(task_t t);
91static struct thread_group *bank_get_bank_task_thread_group(bank_task_t bank_task __unused);
92static struct thread_group *bank_get_bank_account_thread_group(bank_account_t bank_account __unused);
93static uint64_t bank_get_bank_account_holder_resource_coalition_id(bank_account_t bank_account __unused);
94static boolean_t bank_verify_persona_id(uint32_t persona_id, struct bank_persona *persona_out);
95static boolean_t bank_task_can_adopt_persona(bank_task_t bank_merchant, struct bank_persona *persona);
96static void bank_task_get_persona(bank_task_t bank_task, struct bank_persona *persona_out);
97
98/* lock to protect task->bank_context transition */
99static LCK_GRP_DECLARE(bank_lock_grp, "bank_lock");
100static LCK_ATTR_DECLARE(bank_lock_attr, 0, 0);
101static LCK_SPIN_DECLARE_ATTR(g_bank_task_lock_data, &bank_lock_grp, &bank_lock_attr);
102
103static 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
113extern uint64_t proc_uniqueid(void *p);
114struct proc;
115extern int32_t proc_pid(struct proc *p);
116extern int32_t proc_pidversion(void *p);
117extern uint32_t proc_getuid(void *p);
118extern uint32_t proc_getgid(void *p);
119extern void proc_getexecutableuuid(void *p, unsigned char *uuidbuf, unsigned long size);
120extern int kauth_cred_issuser(void *cred);
121extern void* kauth_cred_get(void);
122
123struct persona_t;
124extern struct persona *proc_persona_get(void *p);
125extern struct persona *persona_lookup(uint32_t id);
126extern void persona_put(struct persona *persona);
127extern uint32_t persona_get_id(struct persona *persona);
128extern uint32_t persona_get_uid(struct persona *persona);
129extern boolean_t persona_is_adoption_allowed(struct persona *persona);
130
131kern_return_t
132bank_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
138kern_return_t
139bank_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
151kern_return_t
152bank_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
161kern_return_t
162bank_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 */
177const 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
187LCK_GRP_DECLARE(bank_dev_lock_grp, "bank_dev_lock");
188LCK_MTX_DECLARE(bank_tasks_list_lock, &bank_dev_lock_grp);
189LCK_MTX_DECLARE(bank_accounts_list_lock, &bank_dev_lock_grp);
190queue_head_t bank_tasks_list = QUEUE_HEAD_INITIALIZER(bank_tasks_list);
191queue_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
200static void
201bank_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 manager: &bank_manager,
208 default_value: 0,
209 MACH_VOUCHER_ATTR_KEY_BANK,
210 control: &bank_voucher_attr_control);
211
212 kprintf(fmt: "BANK subsystem is initialized\n");
213}
214STARTUP(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 */
228kern_return_t
229bank_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(lck: &bank_task->bt_acc_to_pay_lock);
259 if (bank_task->bt_made != sync) {
260 lck_mtx_unlock(lck: &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(lck: &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 */
286kern_return_t
287bank_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(t: current_task())) {
352 return KERN_NO_ACCESS;
353 }
354
355 struct persona_modify_info pmi = {};
356 if (recipe_size == sizeof(pmi)) {
357 memcpy(dst: (void *)&pmi, src: recipe, n: 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(persona_id: pmi.persona_id, persona_out: &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_task: 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: &persona)) {
389 return KERN_INVALID_ARGUMENT;
390 }
391
392 if (bank_holder->bt_persona_id == persona.persona_id) {
393 lck_mtx_lock(lck: &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(lck: &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 banktg: thread_group, persona: &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_task: bank_holder);
439 bank_task_get_persona(bank_task: bank_holder, persona_out: &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(bank_account: 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_task: 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: &persona)) {
465 bank_task_get_persona(bank_task: bank_merchant, persona_out: &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 banktg: thread_group, persona: &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_task: bank_holder);
512 bank_task_get_persona(bank_task: bank_holder, persona_out: &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(bank_account: 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_task: 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_task: bank_merchant, persona_out: &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(lck: &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(lck: &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 banktg: thread_group, persona: &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 */
642kern_return_t
643bank_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(dst: &out_recipe[0], src: buf, n: strlen(s: buf) + 1);
697 *out_command = MACH_VOUCHER_ATTR_BANK_NULL;
698 *in_out_recipe_size = (mach_voucher_attr_content_size_t)strlen(s: 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 */
711kern_return_t
712bank_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(dst: &out_content[0], src: &pid, n: 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(dst: &token->originator, src: &bank_secureoriginator->bt_proc_persona, n: sizeof(struct proc_persona_info));
806 memcpy(dst: &token->proximate, src: &bank_proximateprocess->bt_proc_persona, n: 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(dst: out_content, src: &persona_id, n: 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(dst: out_content, src: &adopt_any_persona, n: 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(dst: &pids_out[0], src: &origin_pid, n: sizeof(origin_pid));
902 memcpy(dst: &pids_out[1], src: &proximate_pid, n: 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
920static boolean_t
921bank_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 */
944static bank_task_t
945bank_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(t: 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(lck: &new_bank_task->bt_acc_to_pay_lock, grp: &bank_lock_grp, attr: &bank_lock_attr);
963 lck_mtx_init(lck: &new_bank_task->bt_acc_to_charge_lock, grp: &bank_lock_grp, attr: &bank_lock_attr);
964
965 /*
966 * Initialize the persona_id struct
967 */
968 persona = proc_persona_get(p: bsd_info);
969
970 bzero(s: &new_bank_task->bt_proc_persona, n: 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(p: bsd_info);
976 new_bank_task->bt_pid = proc_pid(p: bsd_info);
977 new_bank_task->bt_pidversion = proc_pidversion(p: 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(p: bsd_info);
981 new_bank_task->bt_gid = proc_getgid(p: bsd_info);
982#if CONFIG_THREAD_GROUPS
983 new_bank_task->bt_thread_group = thread_group_retain(tg: 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(coal: rsrc_coal) : 0;
988#endif /* CONFIG_COALITIONS */
989 proc_getexecutableuuid(p: bsd_info, uuidbuf: new_bank_task->bt_macho_uuid, size: 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 */
1009static boolean_t
1010bank_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(task: 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(task: 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 */
1033static boolean_t
1034bank_task_is_persona_modify_entitled(task_t t)
1035{
1036 boolean_t entitled = FALSE;
1037 entitled = IOTaskHasEntitlement(task: 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 */
1047static bank_account_t
1048bank_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(template: 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(ledger: new_ledger, entry: bank_ledgers.cpu_time);
1066 ledger_entry_setactive(ledger: new_ledger, entry: 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(lck: &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(lck: &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(lck: &bank_merchant->bt_acc_to_charge_lock);
1112 }
1113
1114 lck_mtx_unlock(lck: &bank_holder->bt_acc_to_pay_lock);
1115
1116 if (entry_found) {
1117 ledger_dereference(ledger: 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(tg: 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 */
1148static bank_task_t
1149get_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(ledger: 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 */
1196static void
1197bank_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(lck: &bank_task->bt_acc_to_pay_lock, grp: &bank_lock_grp);
1208 lck_mtx_destroy(lck: &bank_task->bt_acc_to_charge_lock, grp: &bank_lock_grp);
1209
1210#if CONFIG_THREAD_GROUPS
1211 thread_group_release(tg: 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 */
1229static kern_return_t
1230bank_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_task: bank_merchant);
1245
1246 /* Grab the acc to pay list lock and check the sync value */
1247 lck_mtx_lock(lck: &bank_holder->bt_acc_to_pay_lock);
1248
1249 if (bank_account->ba_made != sync) {
1250 lck_mtx_unlock(lck: &bank_holder->bt_acc_to_pay_lock);
1251 if (bank_merchant_ledger) {
1252 ledger_dereference(ledger: 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(lck: &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(bill: bank_account->ba_bill, bank_holder_ledger: bank_holder->bt_ledger, bank_merchant_ledger,
1269 bank_holder_pid: bank_holder->bt_pid, bank_merchant_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(lck: &bank_merchant->bt_acc_to_charge_lock);
1278 lck_mtx_unlock(lck: &bank_holder->bt_acc_to_pay_lock);
1279
1280 if (bank_merchant_ledger) {
1281 ledger_dereference(ledger: bank_merchant_ledger);
1282 }
1283 ledger_dereference(ledger: bank_account->ba_bill);
1284
1285 /* Drop the reference of bank holder and merchant */
1286 bank_task_dealloc(bank_task: bank_holder);
1287 bank_task_dealloc(bank_task: bank_merchant);
1288 bank_task_dealloc(bank_task: bank_secureoriginator);
1289 bank_task_dealloc(bank_task: bank_proximateprocess);
1290#if CONFIG_THREAD_GROUPS
1291 assert(bank_account->ba_thread_group != NULL);
1292 thread_group_release(tg: 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 */
1310static void
1311bank_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(ledger: bill, entry: bank_ledgers.cpu_time, credit: &credit, debit: &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(ledger: bank_holder_ledger, entry: task_ledgers.cpu_time_billed_to_me, amount: credit);
1334 ledger_debit(ledger: bank_holder_ledger, entry: task_ledgers.cpu_time_billed_to_me, amount: debit);
1335 }
1336
1337 if (bank_merchant_ledger) {
1338 ledger_credit(ledger: bank_merchant_ledger, entry: task_ledgers.cpu_time_billed_to_others, amount: credit);
1339 ledger_debit(ledger: bank_merchant_ledger, entry: task_ledgers.cpu_time_billed_to_others, amount: debit);
1340 }
1341 }
1342
1343 ret = ledger_get_entries(ledger: bill, entry: bank_ledgers.energy, credit: &credit, debit: &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(ledger: bank_holder_ledger, entry: task_ledgers.energy_billed_to_me, amount: credit);
1351 ledger_debit(ledger: bank_holder_ledger, entry: task_ledgers.energy_billed_to_me, amount: debit);
1352 }
1353
1354 if (bank_merchant_ledger) {
1355 ledger_credit(ledger: bank_merchant_ledger, entry: task_ledgers.energy_billed_to_others, amount: credit);
1356 ledger_debit(ledger: bank_merchant_ledger, entry: task_ledgers.energy_billed_to_others, amount: debit);
1357 }
1358 }
1359}
1360
1361
1362
1363/*
1364 * Routine: bank_task_destroy
1365 * Purpose: Drops reference on bank task.
1366 * Returns: None.
1367 */
1368void
1369bank_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 */
1388void
1389bank_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 */
1399static void
1400init_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(name: "Bank ledger")) == NULL) {
1408 panic("couldn't create bank ledger template");
1409 }
1410
1411 if ((idx = ledger_entry_add(template: t, key: "cpu_time", group: "sched", units: "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(template: t, key: "energy", group: "power", units: "nj")) < 0) {
1417 panic("couldn't create energy entry for bank ledger template");
1418 }
1419 bank_ledgers.energy = idx;
1420
1421 ledger_template_complete(template: 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 */
1431void
1432bank_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_time: &cpu_balance, energy: &energy_balance);
1451 bank_task_dealloc(bank_task);
1452 } else {
1453 kr = ledger_get_entries(ledger: task->ledger, entry: task_ledgers.cpu_time_billed_to_me,
1454 credit: &credit, debit: &debit);
1455 if (kr == KERN_SUCCESS) {
1456 cpu_balance = credit - debit;
1457 }
1458 kr = ledger_get_entries(ledger: task->ledger, entry: task_ledgers.energy_billed_to_me,
1459 credit: &credit, debit: &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 */
1475void
1476bank_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(lck: &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(ledger: bank_task->bt_ledger, entry: task_ledgers.cpu_time_billed_to_me, balance: &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(ledger: bank_task->bt_ledger, entry: task_ledgers.energy_billed_to_me, balance: &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(ledger: bank_account->ba_bill, entry: bank_ledgers.cpu_time, balance: &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(ledger: bank_account->ba_bill, entry: bank_ledgers.energy, balance: &temp);
1522 if (kr == KERN_SUCCESS && temp >= 0) {
1523 energy_balance += temp;
1524 }
1525 }
1526 lck_mtx_unlock(lck: &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 */
1538void
1539bank_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_time: &cpu_balance, energy: &energy_balance);
1558 bank_task_dealloc(bank_task);
1559 } else {
1560 kr = ledger_get_entries(ledger: task->ledger, entry: task_ledgers.cpu_time_billed_to_others,
1561 credit: &credit, debit: &debit);
1562 if (kr == KERN_SUCCESS) {
1563 cpu_balance = credit - debit;
1564 }
1565
1566 kr = ledger_get_entries(ledger: task->ledger, entry: task_ledgers.energy_billed_to_others,
1567 credit: &credit, debit: &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 */
1583void
1584bank_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(lck: &bank_task->bt_acc_to_charge_lock);
1602
1603 if (ledger) {
1604 kr = ledger_get_balance(ledger, entry: task_ledgers.cpu_time_billed_to_others, balance: &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, entry: task_ledgers.energy_billed_to_others, balance: &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(ledger: bank_account->ba_bill, entry: bank_ledgers.cpu_time, balance: &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(ledger: bank_account->ba_bill, entry: bank_ledgers.energy, balance: &temp);
1633 if (kr == KERN_SUCCESS && temp >= 0) {
1634 energy_balance += temp;
1635 }
1636 }
1637 lck_mtx_unlock(lck: &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 */
1652static bank_account_t
1653bank_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(control: bank_voucher_attr_control,
1663 voucher,
1664 out_values: vals,
1665 in_out_size: &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 */
1694static ledger_t
1695bank_get_bank_task_ledger_with_ref(bank_task_t bank_task)
1696{
1697 ledger_t ledger = LEDGER_NULL;
1698
1699 lck_mtx_lock(lck: &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(lck: &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 */
1713static void
1714bank_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(lck: &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(lck: &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 */
1732static ledger_t
1733bank_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 */
1753kern_return_t
1754bank_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(control: bank_voucher_attr_control,
1767 voucher,
1768 out_values: vals,
1769 in_out_size: &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
1790errorout:
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 */
1811static struct thread_group *
1812bank_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 */
1829static struct thread_group *
1830bank_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
1843static uint64_t
1844bank_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 */
1863kern_return_t
1864bank_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(task: 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_task: 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
1916uint64_t
1917bank_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 */
1932void
1933bank_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(ledger: old_ledger,
1993 entry: bank_ledgers.cpu_time,
1994 amount: effective_ledger_time_consumed);
1995 ledger_credit(ledger: old_ledger,
1996 entry: bank_ledgers.energy,
1997 amount: 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 */
2008static boolean_t
2009bank_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(id: 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
2025static boolean_t
2026bank_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
2046static void
2047bank_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