2 * Copyright (c) 2012-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 <mach/mach_vm.h>
35 #include <mach/vm_map.h>
36 #include <vm/vm_map.h>
37 #include <mach/host_priv.h>
38 #include <mach/host_special_ports.h>
39 #include <kern/host.h>
40 #include <kern/ledger.h>
41 #include <kern/coalition.h>
42 #include <kern/thread_group.h>
43 #include <sys/kdebug.h>
44 #include <IOKit/IOBSD.h>
45 #include <mach/mach_voucher_attr_control.h>
46 #include <kern/policy_internal.h>
48 static ZONE_DECLARE(bank_task_zone
, "bank_task",
49 sizeof(struct bank_task
), ZC_NONE
);
50 static ZONE_DECLARE(bank_account_zone
, "bank_account",
51 sizeof(struct bank_account
), ZC_NONE
);
53 #define MAX_BANK_TASK (CONFIG_TASK_MAX)
54 #define MAX_BANK_ACCOUNT (CONFIG_TASK_MAX + CONFIG_THREAD_MAX)
56 #define BANK_ELEMENT_TO_HANDLE(x) (CAST_DOWN(bank_handle_t, (x)))
57 #define HANDLE_TO_BANK_ELEMENT(x) (CAST_DOWN(bank_element_t, (x)))
59 /* Need macro since bank_element_t is 4 byte aligned on release kernel and direct type case gives compilation error */
60 #define CAST_TO_BANK_ELEMENT(x) ((bank_element_t)((void *)(x)))
61 #define CAST_TO_BANK_TASK(x) ((bank_task_t)((void *)(x)))
62 #define CAST_TO_BANK_ACCOUNT(x) ((bank_account_t)((void *)(x)))
64 ipc_voucher_attr_control_t bank_voucher_attr_control
; /* communication channel from ATM to voucher system */
66 extern struct persona
*system_persona
, *proxy_system_persona
;
67 uint32_t persona_get_id(struct persona
*persona
);
68 extern int unique_persona
;
70 static ledger_template_t bank_ledger_template
= NULL
;
71 struct _bank_ledger_indices bank_ledgers
= { .cpu_time
= -1, .energy
= -1 };
73 static bank_task_t
bank_task_alloc_init(task_t task
);
74 static bank_account_t
bank_account_alloc_init(bank_task_t bank_holder
, bank_task_t bank_merchant
,
75 bank_task_t bank_secureoriginator
, bank_task_t bank_proximateprocess
, struct thread_group
* banktg
, uint32_t persona_id
);
76 static bank_task_t
get_bank_task_context(task_t task
, boolean_t initialize
);
77 static void bank_task_dealloc(bank_task_t bank_task
, mach_voucher_attr_value_reference_t sync
);
78 static kern_return_t
bank_account_dealloc_with_sync(bank_account_t bank_account
, mach_voucher_attr_value_reference_t sync
);
79 static void bank_rollup_chit_to_tasks(ledger_t bill
, ledger_t bank_holder_ledger
, ledger_t bank_merchant_ledger
,
80 int bank_holder_pid
, int bank_merchant_pid
);
81 static ledger_t
bank_get_bank_task_ledger_with_ref(bank_task_t bank_task
);
82 static void bank_destroy_bank_task_ledger(bank_task_t bank_task
);
83 static void init_bank_ledgers(void);
84 static boolean_t
bank_task_is_propagate_entitled(task_t t
);
85 static boolean_t
bank_task_is_persona_modify_entitled(task_t t
);
86 static struct thread_group
*bank_get_bank_task_thread_group(bank_task_t bank_task __unused
);
87 static struct thread_group
*bank_get_bank_account_thread_group(bank_account_t bank_account __unused
);
88 static boolean_t
bank_verify_persona_id(uint32_t persona_id
);
90 /* lock to protect task->bank_context transition */
91 static LCK_GRP_DECLARE(bank_lock_grp
, "bank_lock");
92 static LCK_ATTR_DECLARE(bank_lock_attr
, 0, 0);
93 static LCK_SPIN_DECLARE_ATTR(g_bank_task_lock_data
, &bank_lock_grp
, &bank_lock_attr
);
95 static TUNABLE(bool, disable_persona_propagate_check
,
96 "disable_persona_propagate_check", false);
98 #define global_bank_task_lock() \
99 lck_spin_lock_grp(&g_bank_task_lock_data, &bank_lock_grp)
100 #define global_bank_task_lock_try() \
101 lck_spin_try_lock_grp(&g_bank_task_lock_data, &bank_lock_grp)
102 #define global_bank_task_unlock() \
103 lck_spin_unlock(&g_bank_task_lock_data)
105 extern uint64_t proc_uniqueid(void *p
);
107 extern int32_t proc_pid(struct proc
*p
);
108 extern int32_t proc_pidversion(void *p
);
109 extern uint32_t proc_persona_id(void *p
);
110 extern uint32_t proc_getuid(void *p
);
111 extern uint32_t proc_getgid(void *p
);
112 extern void proc_getexecutableuuid(void *p
, unsigned char *uuidbuf
, unsigned long size
);
113 extern int kauth_cred_issuser(void *cred
);
114 extern void* kauth_cred_get(void);
115 extern void* persona_lookup(uint32_t id
);
116 extern void persona_put(void* persona
);
120 ipc_voucher_attr_manager_t __assert_only manager
,
121 mach_voucher_attr_key_t __assert_only key
,
122 mach_voucher_attr_value_handle_t value
,
123 mach_voucher_attr_value_reference_t sync
);
127 ipc_voucher_attr_manager_t __assert_only manager
,
128 mach_voucher_attr_key_t __assert_only key
,
129 mach_voucher_attr_recipe_command_t command
,
130 mach_voucher_attr_value_handle_array_t prev_values
,
131 mach_msg_type_number_t __assert_only prev_value_count
,
132 mach_voucher_attr_content_t recipe
,
133 mach_voucher_attr_content_size_t recipe_size
,
134 mach_voucher_attr_value_handle_t
*out_value
,
135 mach_voucher_attr_value_flags_t
*out_flags
,
136 ipc_voucher_t
*out_value_voucher
);
139 bank_extract_content(
140 ipc_voucher_attr_manager_t __assert_only manager
,
141 mach_voucher_attr_key_t __assert_only key
,
142 mach_voucher_attr_value_handle_array_t values
,
143 mach_msg_type_number_t value_count
,
144 mach_voucher_attr_recipe_command_t
*out_command
,
145 mach_voucher_attr_content_t out_recipe
,
146 mach_voucher_attr_content_size_t
*in_out_recipe_size
);
150 ipc_voucher_attr_manager_t __assert_only manager
,
151 mach_voucher_attr_key_t __assert_only key
,
152 mach_voucher_attr_value_handle_array_t values
,
153 mach_msg_type_number_t value_count
,
154 mach_voucher_attr_command_t command
,
155 mach_voucher_attr_content_t in_content
,
156 mach_voucher_attr_content_size_t in_content_size
,
157 mach_voucher_attr_content_t out_content
,
158 mach_voucher_attr_content_size_t
*in_out_content_size
);
161 bank_release(ipc_voucher_attr_manager_t __assert_only manager
);
164 * communication channel from voucher system to ATM
166 const struct ipc_voucher_attr_manager bank_manager
= {
167 .ivam_release_value
= bank_release_value
,
168 .ivam_get_value
= bank_get_value
,
169 .ivam_extract_content
= bank_extract_content
,
170 .ivam_command
= bank_command
,
171 .ivam_release
= bank_release
,
172 .ivam_flags
= (IVAM_FLAGS_SUPPORT_SEND_PREPROCESS
| IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS
),
176 #if DEVELOPMENT || DEBUG
177 LCK_GRP_DECLARE(bank_dev_lock_grp
, "bank_dev_lock");
178 LCK_MTX_DECLARE(bank_tasks_list_lock
, &bank_dev_lock_grp
);
179 LCK_MTX_DECLARE(bank_accounts_list_lock
, &bank_dev_lock_grp
);
180 queue_head_t bank_tasks_list
= QUEUE_HEAD_INITIALIZER(bank_tasks_list
);
181 queue_head_t bank_accounts_list
= QUEUE_HEAD_INITIALIZER(bank_accounts_list
);
186 * Purpose: Initialize the BANK subsystem.
192 kern_return_t kr
= KERN_SUCCESS
;
196 /* Register the bank manager with the Vouchers sub system. */
197 kr
= ipc_register_well_known_mach_voucher_attr_manager(
200 MACH_VOUCHER_ATTR_KEY_BANK
,
201 &bank_voucher_attr_control
);
202 if (kr
!= KERN_SUCCESS
) {
203 panic("BANK subsystem initialization failed");
207 kprintf("BANK subsystem is initialized\n");
212 * BANK Resource Manager Routines.
217 * Routine: bank_release_value
218 * Purpose: Release a value, if sync matches the sync count in value.
219 * Returns: KERN_SUCCESS: on Successful deletion.
220 * KERN_FAILURE: if sync value does not matches.
224 ipc_voucher_attr_manager_t __assert_only manager
,
225 mach_voucher_attr_key_t __assert_only key
,
226 mach_voucher_attr_value_handle_t value
,
227 mach_voucher_attr_value_reference_t sync
)
229 bank_task_t bank_task
= BANK_TASK_NULL
;
230 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
231 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
232 kern_return_t kr
= KERN_SUCCESS
;
234 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
235 assert(manager
== &bank_manager
);
238 bank_element
= HANDLE_TO_BANK_ELEMENT(value
);
239 /* Voucher system should never release the default or persistent value */
240 assert(bank_element
!= BANK_DEFAULT_VALUE
&& bank_element
!= BANK_DEFAULT_TASK_VALUE
);
242 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
243 /* Return success for default and default task value */
248 if (bank_element
->be_type
== BANK_TASK
) {
249 bank_task
= CAST_TO_BANK_TASK(bank_element
);
251 /* Checking of the made ref with sync and clearing of voucher ref should be done under a lock */
252 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
253 if (bank_task
->bt_made
!= sync
) {
254 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
258 bank_task_made_release_num(bank_task
, sync
);
259 assert(bank_task
->bt_voucher_ref
== 1);
260 bank_task
->bt_voucher_ref
= 0;
261 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
263 bank_task_dealloc(bank_task
, 1);
264 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
265 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
266 kr
= bank_account_dealloc_with_sync(bank_account
, sync
);
268 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
276 * Routine: bank_get_value
278 * This function uses the recipe to create a bank attribute for a voucher.
282 ipc_voucher_attr_manager_t __assert_only manager
,
283 mach_voucher_attr_key_t __assert_only key
,
284 mach_voucher_attr_recipe_command_t command
,
285 mach_voucher_attr_value_handle_array_t prev_values
,
286 mach_msg_type_number_t prev_value_count
,
287 mach_voucher_attr_content_t recipe
,
288 mach_voucher_attr_content_size_t recipe_size
,
289 mach_voucher_attr_value_handle_t
*out_value
,
290 mach_voucher_attr_value_flags_t
*out_flags
,
291 ipc_voucher_t
*out_value_voucher
)
293 bank_task_t bank_holder
= BANK_TASK_NULL
;
294 bank_task_t bank_merchant
= BANK_TASK_NULL
;
295 bank_task_t bank_secureoriginator
= BANK_TASK_NULL
;
296 bank_task_t bank_proximateprocess
= BANK_TASK_NULL
;
297 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
298 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
299 bank_account_t old_bank_account
= BANK_ACCOUNT_NULL
;
300 mach_voucher_attr_value_handle_t bank_handle
;
302 kern_return_t kr
= KERN_SUCCESS
;
303 mach_msg_type_number_t i
;
304 struct thread_group
*thread_group
= NULL
;
305 struct thread_group
*cur_thread_group
= NULL
;
306 uint32_t persona_id
= proc_persona_id(NULL
);
308 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
309 assert(manager
== &bank_manager
);
311 /* never an out voucher */
312 *out_value_voucher
= IPC_VOUCHER_NULL
;
313 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE
;
316 case MACH_VOUCHER_ATTR_BANK_CREATE
:
318 /* It returns the default task value. This value is replaced by
319 * an actual bank task reference, by using a recipe with
320 * MACH_VOUCHER_ATTR_SEND_PREPROCESS command.
322 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
323 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
326 case MACH_VOUCHER_ATTR_BANK_MODIFY_PERSONA
:
328 /* It creates a bank account attribute value with a new persona id
329 * and auto-redeems it on behalf of the bank_holder.
331 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
333 for (i
= 0; i
< prev_value_count
; i
++) {
334 bank_handle
= prev_values
[i
];
335 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
337 /* Expect a pre-processed attribute value */
338 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
342 if (!bank_task_is_persona_modify_entitled(current_task())) {
343 return KERN_NO_ACCESS
;
346 struct persona_modify_info pmi
= {};
347 if (recipe_size
== sizeof(pmi
)) {
348 memcpy((void *)&pmi
, recipe
, sizeof(pmi
));
349 persona_id
= pmi
.persona_id
;
351 return KERN_INVALID_ARGUMENT
;
354 /* Verify if the persona id is valid */
355 if (!bank_verify_persona_id(persona_id
)) {
356 return KERN_INVALID_ARGUMENT
;
359 /* Update the persona id only if the bank element is a bank task.
360 * This ensures that the bank_holder can be trusted.
362 if (bank_element
->be_type
== BANK_TASK
) {
363 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
364 /* Ensure that the requestor validated by userspace matches
367 if (pmi
.unique_pid
!= bank_holder
->bt_unique_pid
) {
368 return KERN_INVALID_CAPABILITY
;
370 bank_merchant
= bank_holder
;
371 bank_secureoriginator
= bank_holder
;
372 bank_proximateprocess
= bank_holder
;
373 thread_group
= bank_get_bank_task_thread_group(bank_holder
);
374 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
375 return KERN_INVALID_ARGUMENT
;
377 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
380 /* Do not replace persona id if the task is not spawned in system persona */
381 if (unique_persona
&&
382 bank_merchant
->bt_persona_id
!= persona_get_id(system_persona
) &&
383 bank_merchant
->bt_persona_id
!= persona_get_id(proxy_system_persona
) &&
384 bank_merchant
->bt_persona_id
!= persona_id
) {
385 return KERN_INVALID_ARGUMENT
;
388 if (bank_holder
->bt_persona_id
== persona_id
) {
389 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
390 bank_task_made_reference(bank_holder
);
391 if (bank_holder
->bt_voucher_ref
== 0) {
392 /* Take a ref for voucher system, if voucher system does not have a ref */
393 bank_task_reference(bank_holder
);
394 bank_holder
->bt_voucher_ref
= 1;
396 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
398 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_holder
);
402 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
403 bank_secureoriginator
, bank_proximateprocess
,
404 thread_group
, persona_id
);
405 if (bank_account
== BANK_ACCOUNT_NULL
) {
406 return KERN_RESOURCE_SHORTAGE
;
409 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
414 case MACH_VOUCHER_ATTR_AUTO_REDEEM
:
416 /* It creates a bank account with the bank_merchant set to the current task.
417 * A bank attribute voucher needs to be redeemed before it can be adopted by
420 for (i
= 0; i
< prev_value_count
; i
++) {
421 bank_handle
= prev_values
[i
];
422 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
424 /* Should not have received default task value from an IPC */
425 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
429 task
= current_task();
430 if (bank_element
->be_type
== BANK_TASK
) {
431 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
432 bank_secureoriginator
= bank_holder
;
433 bank_proximateprocess
= bank_holder
;
434 thread_group
= bank_get_bank_task_thread_group(bank_holder
);
435 persona_id
= bank_holder
->bt_persona_id
;
436 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
437 old_bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
438 bank_holder
= old_bank_account
->ba_holder
;
439 bank_secureoriginator
= old_bank_account
->ba_secureoriginator
;
440 bank_proximateprocess
= old_bank_account
->ba_proximateprocess
;
441 thread_group
= bank_get_bank_account_thread_group(old_bank_account
);
442 persona_id
= old_bank_account
->ba_so_persona_id
;
444 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
447 bank_merchant
= get_bank_task_context(task
, FALSE
);
448 if (bank_merchant
== BANK_TASK_NULL
) {
449 return KERN_RESOURCE_SHORTAGE
;
452 cur_thread_group
= bank_get_bank_task_thread_group(bank_merchant
);
454 /* Change voucher thread group to current thread group for Apps */
455 if (task_is_app(task
)) {
456 thread_group
= cur_thread_group
;
459 /* Change the persona-id to current task persona-id if the task is not spawned in system persona */
460 if (unique_persona
&&
461 bank_merchant
->bt_persona_id
!= persona_get_id(system_persona
) &&
462 bank_merchant
->bt_persona_id
!= persona_get_id(proxy_system_persona
)) {
463 persona_id
= bank_merchant
->bt_persona_id
;
466 /* Check if trying to redeem for self task, return the default bank task */
467 if (bank_holder
== bank_merchant
&&
468 bank_holder
== bank_secureoriginator
&&
469 bank_holder
== bank_proximateprocess
&&
470 thread_group
== cur_thread_group
&&
471 persona_id
== bank_holder
->bt_persona_id
) {
472 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
473 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
477 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
478 bank_secureoriginator
, bank_proximateprocess
,
479 thread_group
, persona_id
);
480 if (bank_account
== BANK_ACCOUNT_NULL
) {
481 return KERN_RESOURCE_SHORTAGE
;
484 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
488 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
491 case MACH_VOUCHER_ATTR_SEND_PREPROCESS
:
493 for (i
= 0; i
< prev_value_count
; i
++) {
494 bank_handle
= prev_values
[i
];
495 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
497 if (bank_element
== BANK_DEFAULT_VALUE
) {
501 task
= current_task();
502 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
503 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(task
, FALSE
));
506 if (bank_element
->be_type
== BANK_TASK
) {
507 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
508 bank_secureoriginator
= bank_holder
;
509 thread_group
= bank_get_bank_task_thread_group(bank_holder
);
510 persona_id
= bank_holder
->bt_persona_id
;
511 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
512 old_bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
513 bank_holder
= old_bank_account
->ba_holder
;
514 bank_secureoriginator
= old_bank_account
->ba_secureoriginator
;
515 thread_group
= bank_get_bank_account_thread_group(old_bank_account
);
516 persona_id
= old_bank_account
->ba_so_persona_id
;
518 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
521 bank_merchant
= get_bank_task_context(task
, FALSE
);
522 if (bank_merchant
== BANK_TASK_NULL
) {
523 return KERN_RESOURCE_SHORTAGE
;
526 cur_thread_group
= bank_get_bank_task_thread_group(bank_merchant
);
529 * If the process doesn't have secure persona entitlement,
530 * then replace the secure originator to current task.
531 * Also update the persona_id to match that of the secure originator.
533 if (bank_merchant
->bt_hasentitlement
== 0) {
534 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
535 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SECURE_ORIGINATOR_CHANGED
))) | DBG_FUNC_NONE
,
536 bank_secureoriginator
->bt_pid
, bank_merchant
->bt_pid
, 0, 0, 0);
537 bank_secureoriginator
= bank_merchant
;
538 persona_id
= bank_merchant
->bt_persona_id
;
541 bank_proximateprocess
= bank_merchant
;
543 /* Check if trying to pre-process for self task, return the bank task */
544 if (bank_holder
== bank_merchant
&&
545 bank_holder
== bank_secureoriginator
&&
546 bank_holder
== bank_proximateprocess
&&
547 thread_group
== cur_thread_group
&&
548 persona_id
== bank_holder
->bt_persona_id
) {
549 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
550 bank_task_made_reference(bank_holder
);
551 if (bank_holder
->bt_voucher_ref
== 0) {
552 /* Take a ref for voucher system, if voucher system does not have a ref */
553 bank_task_reference(bank_holder
);
554 bank_holder
->bt_voucher_ref
= 1;
556 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
558 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_holder
);
561 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
562 bank_secureoriginator
, bank_proximateprocess
,
563 thread_group
, persona_id
);
564 if (bank_account
== BANK_ACCOUNT_NULL
) {
565 return KERN_RESOURCE_SHORTAGE
;
568 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
572 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
575 case MACH_VOUCHER_ATTR_REDEEM
:
576 /* This command expects that the bank attribute has been auto-redeemed
577 * and returns a reference to that bank account value.
579 for (i
= 0; i
< prev_value_count
; i
++) {
580 bank_handle
= prev_values
[i
];
581 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
583 if (bank_element
== BANK_DEFAULT_VALUE
) {
587 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
588 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
589 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
593 task
= current_task();
594 if (bank_element
->be_type
== BANK_TASK
) {
595 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
596 if (bank_holder
== get_bank_task_context(task
, FALSE
)) {
597 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
598 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
600 kr
= KERN_INVALID_CAPABILITY
;
603 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
604 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
605 bank_merchant
= bank_account
->ba_merchant
;
606 if (bank_merchant
!= get_bank_task_context(task
, FALSE
)) {
607 /* This error can be used to verify if the task can
610 kr
= KERN_INVALID_CAPABILITY
;
613 bank_account_made_reference(bank_account
);
614 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
617 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
621 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
625 kr
= KERN_INVALID_ARGUMENT
;
634 * Routine: bank_extract_content
635 * Purpose: Extract a set of aid from an array of voucher values.
636 * Returns: KERN_SUCCESS: on Success.
637 * KERN_FAILURE: one of the value is not present in the hash.
638 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of aid.
641 bank_extract_content(
642 ipc_voucher_attr_manager_t __assert_only manager
,
643 mach_voucher_attr_key_t __assert_only key
,
644 mach_voucher_attr_value_handle_array_t values
,
645 mach_msg_type_number_t value_count
,
646 mach_voucher_attr_recipe_command_t
*out_command
,
647 mach_voucher_attr_content_t out_recipe
,
648 mach_voucher_attr_content_size_t
*in_out_recipe_size
)
650 bank_task_t bank_task
= BANK_TASK_NULL
;
651 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
652 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
653 mach_voucher_attr_value_handle_t bank_handle
;
654 char buf
[MACH_VOUCHER_BANK_CONTENT_SIZE
];
655 mach_msg_type_number_t i
;
657 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
658 assert(manager
== &bank_manager
);
660 for (i
= 0; i
< value_count
&& *in_out_recipe_size
> 0; i
++) {
661 bank_handle
= values
[i
];
662 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
663 if (bank_element
== BANK_DEFAULT_VALUE
) {
667 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
668 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
671 if (MACH_VOUCHER_BANK_CONTENT_SIZE
> *in_out_recipe_size
) {
672 *in_out_recipe_size
= 0;
673 return KERN_NO_SPACE
;
676 if (bank_element
->be_type
== BANK_TASK
) {
677 bank_task
= CAST_TO_BANK_TASK(bank_element
);
678 snprintf(buf
, MACH_VOUCHER_BANK_CONTENT_SIZE
,
679 " Bank Context for a pid %d\n", bank_task
->bt_pid
);
680 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
681 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
682 snprintf(buf
, MACH_VOUCHER_BANK_CONTENT_SIZE
,
683 " Bank Account linking holder pid %d with merchant pid %d, originator PID/persona: %d, %u and proximate PID/persona: %d, %u\n",
684 bank_account
->ba_holder
->bt_pid
,
685 bank_account
->ba_merchant
->bt_pid
,
686 bank_account
->ba_secureoriginator
->bt_pid
,
687 bank_account
->ba_so_persona_id
,
688 bank_account
->ba_proximateprocess
->bt_pid
,
689 bank_account
->ba_proximateprocess
->bt_persona_id
);
691 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
694 memcpy(&out_recipe
[0], buf
, strlen(buf
) + 1);
695 *out_command
= MACH_VOUCHER_ATTR_BANK_NULL
;
696 *in_out_recipe_size
= (mach_voucher_attr_content_size_t
)strlen(buf
) + 1;
704 * Routine: bank_command
705 * Purpose: Execute a command against a set of bank values.
706 * Returns: KERN_SUCCESS: On successful execution of command.
707 * KERN_FAILURE: On failure.
711 ipc_voucher_attr_manager_t __assert_only manager
,
712 mach_voucher_attr_key_t __assert_only key
,
713 mach_voucher_attr_value_handle_array_t __unused values
,
714 mach_msg_type_number_t __unused value_count
,
715 mach_voucher_attr_command_t __unused command
,
716 mach_voucher_attr_content_t __unused in_content
,
717 mach_voucher_attr_content_size_t __unused in_content_size
,
718 mach_voucher_attr_content_t __unused out_content
,
719 mach_voucher_attr_content_size_t __unused
*out_content_size
)
721 bank_task_t bank_task
= BANK_TASK_NULL
;
722 bank_task_t bank_secureoriginator
= BANK_TASK_NULL
;
723 bank_task_t bank_proximateprocess
= BANK_TASK_NULL
;
724 struct persona_token
*token
= NULL
;
725 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
726 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
727 mach_voucher_attr_value_handle_t bank_handle
;
728 mach_msg_type_number_t i
;
732 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
733 assert(manager
== &bank_manager
);
736 case BANK_ORIGINATOR_PID
:
738 if ((sizeof(pid
)) > *out_content_size
) {
739 *out_content_size
= 0;
740 return KERN_NO_SPACE
;
743 for (i
= 0; i
< value_count
; i
++) {
744 bank_handle
= values
[i
];
745 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
746 if (bank_element
== BANK_DEFAULT_VALUE
) {
750 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
751 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
754 if (bank_element
->be_type
== BANK_TASK
) {
755 bank_task
= CAST_TO_BANK_TASK(bank_element
);
756 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
757 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
758 bank_task
= bank_account
->ba_holder
;
760 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
762 pid
= bank_task
->bt_pid
;
764 memcpy(&out_content
[0], &pid
, sizeof(pid
));
765 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(pid
);
768 /* In the case of no value, return error KERN_INVALID_VALUE */
769 *out_content_size
= 0;
770 return KERN_INVALID_VALUE
;
772 case BANK_PERSONA_TOKEN
:
774 if ((sizeof(struct persona_token
)) > *out_content_size
) {
775 *out_content_size
= 0;
776 return KERN_NO_SPACE
;
778 for (i
= 0; i
< value_count
; i
++) {
779 bank_handle
= values
[i
];
780 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
781 if (bank_element
== BANK_DEFAULT_VALUE
) {
785 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
786 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
789 if (bank_element
->be_type
== BANK_TASK
) {
790 *out_content_size
= 0;
791 return KERN_INVALID_OBJECT
;
792 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
793 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
794 bank_secureoriginator
= bank_account
->ba_secureoriginator
;
795 bank_proximateprocess
= bank_account
->ba_proximateprocess
;
797 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
799 token
= (struct persona_token
*)(void *)&out_content
[0];
800 memcpy(&token
->originator
, &bank_secureoriginator
->bt_proc_persona
, sizeof(struct proc_persona_info
));
801 memcpy(&token
->proximate
, &bank_proximateprocess
->bt_proc_persona
, sizeof(struct proc_persona_info
));
803 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(*token
);
806 /* In the case of no value, return error KERN_INVALID_VALUE */
807 *out_content_size
= 0;
808 return KERN_INVALID_VALUE
;
810 case BANK_PERSONA_ID
:
812 if ((sizeof(persona_id
)) > *out_content_size
) {
813 *out_content_size
= 0;
814 return KERN_NO_SPACE
;
817 for (i
= 0; i
< value_count
; i
++) {
818 bank_handle
= values
[i
];
819 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
820 if (bank_element
== BANK_DEFAULT_VALUE
) {
824 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
825 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
828 if (bank_element
->be_type
== BANK_TASK
) {
829 bank_task
= CAST_TO_BANK_TASK(bank_element
);
830 persona_id
= bank_task
->bt_persona_id
;
831 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
832 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
833 persona_id
= bank_account
->ba_so_persona_id
;
835 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
838 memcpy(out_content
, &persona_id
, sizeof(persona_id
));
839 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(persona_id
);
842 /* In the case of no value, return error KERN_INVALID_VALUE */
843 *out_content_size
= 0;
844 return KERN_INVALID_VALUE
;
847 return KERN_INVALID_ARGUMENT
;
855 ipc_voucher_attr_manager_t __assert_only manager
)
857 assert(manager
== &bank_manager
);
863 * Bank Internal Routines.
867 * Routine: bank_task_alloc_init
868 * Purpose: Allocate and initialize a bank task structure.
869 * Returns: bank_task_t on Success.
870 * BANK_TASK_NULL: on Failure.
871 * Notes: Leaves the task and ledger blank and has only 1 ref,
872 * needs to take 1 extra ref after the task field is initialized.
875 bank_task_alloc_init(task_t task
)
877 bank_task_t new_bank_task
;
879 new_bank_task
= (bank_task_t
) zalloc(bank_task_zone
);
880 if (new_bank_task
== BANK_TASK_NULL
) {
881 return BANK_TASK_NULL
;
884 new_bank_task
->bt_type
= BANK_TASK
;
885 new_bank_task
->bt_voucher_ref
= 0;
886 new_bank_task
->bt_refs
= 1;
887 new_bank_task
->bt_made
= 0;
888 new_bank_task
->bt_ledger
= LEDGER_NULL
;
889 new_bank_task
->bt_hasentitlement
= bank_task_is_propagate_entitled(task
);
890 queue_init(&new_bank_task
->bt_accounts_to_pay
);
891 queue_init(&new_bank_task
->bt_accounts_to_charge
);
892 lck_mtx_init(&new_bank_task
->bt_acc_to_pay_lock
, &bank_lock_grp
, &bank_lock_attr
);
893 lck_mtx_init(&new_bank_task
->bt_acc_to_charge_lock
, &bank_lock_grp
, &bank_lock_attr
);
896 * Initialize the persona_id struct
898 bzero(&new_bank_task
->bt_proc_persona
, sizeof(new_bank_task
->bt_proc_persona
));
899 new_bank_task
->bt_flags
= 0;
900 new_bank_task
->bt_unique_pid
= proc_uniqueid(task
->bsd_info
);
901 new_bank_task
->bt_pid
= proc_pid(task
->bsd_info
);
902 new_bank_task
->bt_pidversion
= proc_pidversion(task
->bsd_info
);
903 new_bank_task
->bt_persona_id
= proc_persona_id(task
->bsd_info
);
904 new_bank_task
->bt_uid
= proc_getuid(task
->bsd_info
);
905 new_bank_task
->bt_gid
= proc_getgid(task
->bsd_info
);
906 #if CONFIG_THREAD_GROUPS
907 new_bank_task
->bt_thread_group
= thread_group_retain(task_coalition_get_thread_group(task
));
909 proc_getexecutableuuid(task
->bsd_info
, new_bank_task
->bt_macho_uuid
, sizeof(new_bank_task
->bt_macho_uuid
));
911 #if DEVELOPMENT || DEBUG
912 new_bank_task
->bt_task
= NULL
;
913 lck_mtx_lock(&bank_tasks_list_lock
);
914 queue_enter(&bank_tasks_list
, new_bank_task
, bank_task_t
, bt_global_elt
);
915 lck_mtx_unlock(&bank_tasks_list_lock
);
917 return new_bank_task
;
921 * Routine: proc_is_propagate_entitled
922 * Purpose: Check if the process is allowed to propagate secure originator.
923 * Returns: TRUE if entitled.
927 bank_task_is_propagate_entitled(task_t t
)
929 /* Check if it has an entitlement which disallows secure originator propagation */
930 boolean_t entitled
= FALSE
;
931 entitled
= IOTaskHasEntitlement(t
, ENTITLEMENT_PERSONA_NO_PROPAGATE
);
936 /* If it's a platform binary, allow propagation by default */
937 if (disable_persona_propagate_check
|| (t
->t_flags
& TF_PLATFORM
)) {
945 * Routine: proc_is_persona_modify_entitled
946 * Purpose: Check if the process has persona modify entitlement.
947 * Returns: TRUE if entitled.
951 bank_task_is_persona_modify_entitled(task_t t
)
953 boolean_t entitled
= FALSE
;
954 entitled
= IOTaskHasEntitlement(t
, ENTITLEMENT_PERSONA_MODIFY
);
959 * Routine: bank_account_alloc_init
960 * Purpose: Allocate and Initialize the bank account struct.
961 * Returns: bank_account_t : On Success.
962 * BANK_ACCOUNT_NULL: On Failure.
964 static bank_account_t
965 bank_account_alloc_init(
966 bank_task_t bank_holder
,
967 bank_task_t bank_merchant
,
968 bank_task_t bank_secureoriginator
,
969 bank_task_t bank_proximateprocess
,
970 struct thread_group
*thread_group
,
973 bank_account_t new_bank_account
;
974 bank_account_t bank_account
;
975 boolean_t entry_found
= FALSE
;
976 ledger_t new_ledger
= ledger_instantiate(bank_ledger_template
, LEDGER_CREATE_INACTIVE_ENTRIES
);
978 if (new_ledger
== LEDGER_NULL
) {
979 return BANK_ACCOUNT_NULL
;
982 ledger_entry_setactive(new_ledger
, bank_ledgers
.cpu_time
);
983 ledger_entry_setactive(new_ledger
, bank_ledgers
.energy
);
984 new_bank_account
= (bank_account_t
) zalloc(bank_account_zone
);
985 if (new_bank_account
== BANK_ACCOUNT_NULL
) {
986 ledger_dereference(new_ledger
);
987 return BANK_ACCOUNT_NULL
;
990 new_bank_account
->ba_type
= BANK_ACCOUNT
;
991 new_bank_account
->ba_voucher_ref
= 0;
992 new_bank_account
->ba_refs
= 1;
993 new_bank_account
->ba_made
= 1;
994 new_bank_account
->ba_bill
= new_ledger
;
995 new_bank_account
->ba_merchant
= bank_merchant
;
996 new_bank_account
->ba_holder
= bank_holder
;
997 new_bank_account
->ba_secureoriginator
= bank_secureoriginator
;
998 new_bank_account
->ba_proximateprocess
= bank_proximateprocess
;
999 #if CONFIG_THREAD_GROUPS
1000 new_bank_account
->ba_thread_group
= thread_group
;
1002 new_bank_account
->ba_so_persona_id
= persona_id
;
1004 /* Iterate through accounts need to pay list to find the existing entry */
1005 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
1006 queue_iterate(&bank_holder
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
) {
1007 if (bank_account
->ba_merchant
!= bank_merchant
||
1008 bank_account
->ba_secureoriginator
!= bank_secureoriginator
||
1009 bank_account
->ba_proximateprocess
!= bank_proximateprocess
||
1010 bank_get_bank_account_thread_group(bank_account
) != thread_group
||
1011 bank_account
->ba_so_persona_id
!= persona_id
) {
1016 /* Take a made ref, since this value would be returned to voucher system. */
1017 bank_account_made_reference(bank_account
);
1022 /* Create a linkage between the holder and the merchant task, Grab both the list locks before adding it to the list. */
1023 lck_mtx_lock(&bank_merchant
->bt_acc_to_charge_lock
);
1025 /* Add the account entry into Accounts need to pay account link list. */
1026 queue_enter(&bank_holder
->bt_accounts_to_pay
, new_bank_account
, bank_account_t
, ba_next_acc_to_pay
);
1028 /* Add the account entry into Accounts need to charge account link list. */
1029 queue_enter(&bank_merchant
->bt_accounts_to_charge
, new_bank_account
, bank_account_t
, ba_next_acc_to_charge
);
1031 lck_mtx_unlock(&bank_merchant
->bt_acc_to_charge_lock
);
1034 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
1037 ledger_dereference(new_ledger
);
1038 zfree(bank_account_zone
, new_bank_account
);
1039 return bank_account
;
1042 bank_task_reference(bank_holder
);
1043 bank_task_reference(bank_merchant
);
1044 bank_task_reference(bank_secureoriginator
);
1045 bank_task_reference(bank_proximateprocess
);
1046 #if CONFIG_THREAD_GROUPS
1047 assert(new_bank_account
->ba_thread_group
!= NULL
);
1048 thread_group_retain(new_bank_account
->ba_thread_group
);
1051 #if DEVELOPMENT || DEBUG
1052 new_bank_account
->ba_task
= NULL
;
1053 lck_mtx_lock(&bank_accounts_list_lock
);
1054 queue_enter(&bank_accounts_list
, new_bank_account
, bank_account_t
, ba_global_elt
);
1055 lck_mtx_unlock(&bank_accounts_list_lock
);
1058 return new_bank_account
;
1062 * Routine: get_bank_task_context
1063 * Purpose: Get the bank context of the given task
1064 * Returns: bank_task_t on Success.
1065 * BANK_TASK_NULL: on Failure.
1066 * Note: Initialize bank context if NULL.
1069 get_bank_task_context
1071 boolean_t initialize
)
1073 bank_task_t bank_task
;
1075 if (task
->bank_context
|| !initialize
) {
1076 assert(task
->bank_context
!= NULL
);
1077 return task
->bank_context
;
1080 bank_task
= bank_task_alloc_init(task
);
1082 /* Grab the task lock and check if we won the race. */
1084 if (task
->bank_context
) {
1086 if (bank_task
!= BANK_TASK_NULL
) {
1087 bank_task_dealloc(bank_task
, 1);
1089 return task
->bank_context
;
1090 } else if (bank_task
== BANK_TASK_NULL
) {
1092 return BANK_TASK_NULL
;
1094 /* We won the race. Take a ref on the ledger and initialize bank task. */
1095 bank_task
->bt_ledger
= task
->ledger
;
1096 #if DEVELOPMENT || DEBUG
1097 bank_task
->bt_task
= task
;
1099 ledger_reference(task
->ledger
);
1101 /* Grab the global bank task lock before setting the bank context on a task */
1102 global_bank_task_lock();
1103 task
->bank_context
= bank_task
;
1104 global_bank_task_unlock();
1112 * Routine: bank_task_dealloc
1113 * Purpose: Drops the reference on bank task.
1118 bank_task_t bank_task
,
1119 mach_voucher_attr_value_reference_t sync
)
1121 assert(bank_task
->bt_refs
>= 0);
1123 if (bank_task_release_num(bank_task
, sync
) > (int)sync
) {
1127 assert(bank_task
->bt_refs
== 0);
1128 assert(queue_empty(&bank_task
->bt_accounts_to_pay
));
1129 assert(queue_empty(&bank_task
->bt_accounts_to_charge
));
1131 assert(!LEDGER_VALID(bank_task
->bt_ledger
));
1132 lck_mtx_destroy(&bank_task
->bt_acc_to_pay_lock
, &bank_lock_grp
);
1133 lck_mtx_destroy(&bank_task
->bt_acc_to_charge_lock
, &bank_lock_grp
);
1135 #if CONFIG_THREAD_GROUPS
1136 thread_group_release(bank_task
->bt_thread_group
);
1139 #if DEVELOPMENT || DEBUG
1140 lck_mtx_lock(&bank_tasks_list_lock
);
1141 queue_remove(&bank_tasks_list
, bank_task
, bank_task_t
, bt_global_elt
);
1142 lck_mtx_unlock(&bank_tasks_list_lock
);
1145 zfree(bank_task_zone
, bank_task
);
1149 * Routine: bank_account_dealloc_with_sync
1150 * Purpose: Drop the reference on bank account if the sync matches.
1151 * Returns: KERN_SUCCESS if sync matches.
1152 * KERN_FAILURE on mismatch.
1154 static kern_return_t
1155 bank_account_dealloc_with_sync(
1156 bank_account_t bank_account
,
1157 mach_voucher_attr_value_reference_t sync
)
1159 bank_task_t bank_holder
= bank_account
->ba_holder
;
1160 bank_task_t bank_merchant
= bank_account
->ba_merchant
;
1161 bank_task_t bank_secureoriginator
= bank_account
->ba_secureoriginator
;
1162 bank_task_t bank_proximateprocess
= bank_account
->ba_proximateprocess
;
1163 ledger_t bank_merchant_ledger
= LEDGER_NULL
;
1166 * Grab a reference on the bank_merchant_ledger, since we would not be able
1167 * to take bt_acc_to_pay_lock for bank_merchant later.
1169 bank_merchant_ledger
= bank_get_bank_task_ledger_with_ref(bank_merchant
);
1171 /* Grab the acc to pay list lock and check the sync value */
1172 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
1174 if (bank_account
->ba_made
!= sync
) {
1175 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
1176 if (bank_merchant_ledger
) {
1177 ledger_dereference(bank_merchant_ledger
);
1179 return KERN_FAILURE
;
1182 bank_account_made_release_num(bank_account
, sync
);
1184 if (bank_account_release_num(bank_account
, 1) > 1) {
1185 panic("Releasing a non zero ref bank account %p\n", bank_account
);
1189 /* Grab both the acc to pay and acc to charge locks */
1190 lck_mtx_lock(&bank_merchant
->bt_acc_to_charge_lock
);
1192 /* No need to take ledger reference for bank_holder ledger since bt_acc_to_pay_lock is locked */
1193 bank_rollup_chit_to_tasks(bank_account
->ba_bill
, bank_holder
->bt_ledger
, bank_merchant_ledger
,
1194 bank_holder
->bt_pid
, bank_merchant
->bt_pid
);
1196 /* Remove the account entry from Accounts need to pay account link list. */
1197 queue_remove(&bank_holder
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
);
1199 /* Remove the account entry from Accounts need to charge account link list. */
1200 queue_remove(&bank_merchant
->bt_accounts_to_charge
, bank_account
, bank_account_t
, ba_next_acc_to_charge
);
1202 lck_mtx_unlock(&bank_merchant
->bt_acc_to_charge_lock
);
1203 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
1205 if (bank_merchant_ledger
) {
1206 ledger_dereference(bank_merchant_ledger
);
1208 ledger_dereference(bank_account
->ba_bill
);
1210 /* Drop the reference of bank holder and merchant */
1211 bank_task_dealloc(bank_holder
, 1);
1212 bank_task_dealloc(bank_merchant
, 1);
1213 bank_task_dealloc(bank_secureoriginator
, 1);
1214 bank_task_dealloc(bank_proximateprocess
, 1);
1215 #if CONFIG_THREAD_GROUPS
1216 assert(bank_account
->ba_thread_group
!= NULL
);
1217 thread_group_release(bank_account
->ba_thread_group
);
1220 #if DEVELOPMENT || DEBUG
1221 lck_mtx_lock(&bank_accounts_list_lock
);
1222 queue_remove(&bank_accounts_list
, bank_account
, bank_account_t
, ba_global_elt
);
1223 lck_mtx_unlock(&bank_accounts_list_lock
);
1226 zfree(bank_account_zone
, bank_account
);
1227 return KERN_SUCCESS
;
1231 * Routine: bank_rollup_chit_to_tasks
1232 * Purpose: Debit and Credit holder's and merchant's ledgers.
1236 bank_rollup_chit_to_tasks(
1238 ledger_t bank_holder_ledger
,
1239 ledger_t bank_merchant_ledger
,
1240 int bank_holder_pid
,
1241 int bank_merchant_pid
)
1243 ledger_amount_t credit
;
1244 ledger_amount_t debit
;
1247 if (bank_holder_ledger
== bank_merchant_ledger
) {
1251 ret
= ledger_get_entries(bill
, bank_ledgers
.cpu_time
, &credit
, &debit
);
1252 if (ret
== KERN_SUCCESS
) {
1253 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
1254 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SETTLE_CPU_TIME
))) | DBG_FUNC_NONE
,
1255 bank_merchant_pid
, bank_holder_pid
, credit
, debit
, 0);
1257 if (bank_holder_ledger
) {
1258 ledger_credit(bank_holder_ledger
, task_ledgers
.cpu_time_billed_to_me
, credit
);
1259 ledger_debit(bank_holder_ledger
, task_ledgers
.cpu_time_billed_to_me
, debit
);
1262 if (bank_merchant_ledger
) {
1263 ledger_credit(bank_merchant_ledger
, task_ledgers
.cpu_time_billed_to_others
, credit
);
1264 ledger_debit(bank_merchant_ledger
, task_ledgers
.cpu_time_billed_to_others
, debit
);
1268 ret
= ledger_get_entries(bill
, bank_ledgers
.energy
, &credit
, &debit
);
1269 if (ret
== KERN_SUCCESS
) {
1270 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
1271 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SETTLE_ENERGY
))) | DBG_FUNC_NONE
,
1272 bank_merchant_pid
, bank_holder_pid
, credit
, debit
, 0);
1274 if (bank_holder_ledger
) {
1275 ledger_credit(bank_holder_ledger
, task_ledgers
.energy_billed_to_me
, credit
);
1276 ledger_debit(bank_holder_ledger
, task_ledgers
.energy_billed_to_me
, debit
);
1279 if (bank_merchant_ledger
) {
1280 ledger_credit(bank_merchant_ledger
, task_ledgers
.energy_billed_to_others
, credit
);
1281 ledger_debit(bank_merchant_ledger
, task_ledgers
.energy_billed_to_others
, debit
);
1289 * Routine: bank_task_destroy
1290 * Purpose: Drops reference on bank task.
1294 bank_task_destroy(task_t task
)
1296 bank_task_t bank_task
;
1298 /* Grab the global bank task lock before dropping the ref on task bank context */
1299 global_bank_task_lock();
1300 bank_task
= task
->bank_context
;
1301 task
->bank_context
= NULL
;
1302 global_bank_task_unlock();
1304 bank_destroy_bank_task_ledger(bank_task
);
1305 bank_task_dealloc(bank_task
, 1);
1309 * Routine: bank_task_initialize
1310 * Purpose: Initialize the bank context of a task.
1314 bank_task_initialize(task_t task
)
1316 get_bank_task_context(task
, TRUE
);
1320 * Routine: init_bank_ledgers
1321 * Purpose: Initialize template for bank ledgers.
1325 init_bank_ledgers(void)
1327 ledger_template_t t
;
1330 assert(bank_ledger_template
== NULL
);
1332 if ((t
= ledger_template_create("Bank ledger")) == NULL
) {
1333 panic("couldn't create bank ledger template");
1336 if ((idx
= ledger_entry_add(t
, "cpu_time", "sched", "ns")) < 0) {
1337 panic("couldn't create cpu_time entry for bank ledger template");
1339 bank_ledgers
.cpu_time
= idx
;
1341 if ((idx
= ledger_entry_add(t
, "energy", "power", "nj")) < 0) {
1342 panic("couldn't create energy entry for bank ledger template");
1344 bank_ledgers
.energy
= idx
;
1346 ledger_template_complete(t
);
1347 bank_ledger_template
= t
;
1350 /* Routine: bank_billed_balance_safe
1351 * Purpose: Walk through all the bank accounts billed to me by other tasks and get the current billing balance.
1352 * Called from another task. It takes global bank task lock to make sure the bank context is
1353 * not deallocated while accesing it.
1354 * Returns: cpu balance and energy balance in out paremeters.
1357 bank_billed_balance_safe(task_t task
, uint64_t *cpu_time
, uint64_t *energy
)
1359 bank_task_t bank_task
= BANK_TASK_NULL
;
1360 ledger_amount_t credit
, debit
;
1361 uint64_t cpu_balance
= 0;
1362 uint64_t energy_balance
= 0;
1365 /* Task might be in exec, grab the global bank task lock before accessing bank context. */
1366 global_bank_task_lock();
1367 /* Grab a reference on bank context */
1368 if (task
->bank_context
!= NULL
) {
1369 bank_task
= task
->bank_context
;
1370 bank_task_reference(bank_task
);
1372 global_bank_task_unlock();
1375 bank_billed_balance(bank_task
, &cpu_balance
, &energy_balance
);
1376 bank_task_dealloc(bank_task
, 1);
1378 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.cpu_time_billed_to_me
,
1380 if (kr
== KERN_SUCCESS
) {
1381 cpu_balance
= credit
- debit
;
1383 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.energy_billed_to_me
,
1385 if (kr
== KERN_SUCCESS
) {
1386 energy_balance
= credit
- debit
;
1390 *cpu_time
= cpu_balance
;
1391 *energy
= energy_balance
;
1396 * Routine: bank_billed_time
1397 * Purpose: Walk through the Accounts need to pay account list and get the current billing balance.
1398 * Returns: cpu balance and energy balance in out paremeters.
1401 bank_billed_balance(bank_task_t bank_task
, uint64_t *cpu_time
, uint64_t *energy
)
1403 int64_t cpu_balance
= 0;
1404 int64_t energy_balance
= 0;
1405 bank_account_t bank_account
;
1408 if (bank_task
== BANK_TASK_NULL
) {
1414 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1416 /* bt_acc_to_pay_lock locked, no need to take ledger reference for bt_ledger */
1417 if (bank_task
->bt_ledger
!= LEDGER_NULL
) {
1418 kr
= ledger_get_balance(bank_task
->bt_ledger
, task_ledgers
.cpu_time_billed_to_me
, &temp
);
1419 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1420 cpu_balance
+= temp
;
1422 #if DEVELOPMENT || DEBUG
1424 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1426 #endif /* DEVELOPMENT || DEBUG */
1428 kr
= ledger_get_balance(bank_task
->bt_ledger
, task_ledgers
.energy_billed_to_me
, &temp
);
1429 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1430 energy_balance
+= temp
;
1434 queue_iterate(&bank_task
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
) {
1436 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.cpu_time
, &temp
);
1437 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1438 cpu_balance
+= temp
;
1440 #if DEVELOPMENT || DEBUG
1442 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1444 #endif /* DEVELOPMENT || DEBUG */
1446 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.energy
, &temp
);
1447 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1448 energy_balance
+= temp
;
1451 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1452 *cpu_time
= (uint64_t)cpu_balance
;
1453 *energy
= (uint64_t)energy_balance
;
1457 /* Routine: bank_serviced_balance_safe
1458 * Purpose: Walk through the bank accounts billed to other tasks by me and get the current balance to be charged.
1459 * Called from another task. It takes global bank task lock to make sure the bank context is
1460 * not deallocated while accesing it.
1461 * Returns: cpu balance and energy balance in out paremeters.
1464 bank_serviced_balance_safe(task_t task
, uint64_t *cpu_time
, uint64_t *energy
)
1466 bank_task_t bank_task
= BANK_TASK_NULL
;
1467 ledger_amount_t credit
, debit
;
1468 uint64_t cpu_balance
= 0;
1469 uint64_t energy_balance
= 0;
1472 /* Task might be in exec, grab the global bank task lock before accessing bank context. */
1473 global_bank_task_lock();
1474 /* Grab a reference on bank context */
1475 if (task
->bank_context
!= NULL
) {
1476 bank_task
= task
->bank_context
;
1477 bank_task_reference(bank_task
);
1479 global_bank_task_unlock();
1482 bank_serviced_balance(bank_task
, &cpu_balance
, &energy_balance
);
1483 bank_task_dealloc(bank_task
, 1);
1485 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.cpu_time_billed_to_others
,
1487 if (kr
== KERN_SUCCESS
) {
1488 cpu_balance
= credit
- debit
;
1491 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.energy_billed_to_others
,
1493 if (kr
== KERN_SUCCESS
) {
1494 energy_balance
= credit
- debit
;
1498 *cpu_time
= cpu_balance
;
1499 *energy
= energy_balance
;
1504 * Routine: bank_serviced_balance
1505 * Purpose: Walk through the Account need to charge account list and get the current balance to be charged.
1506 * Returns: cpu balance and energy balance in out paremeters.
1509 bank_serviced_balance(bank_task_t bank_task
, uint64_t *cpu_time
, uint64_t *energy
)
1511 int64_t cpu_balance
= 0;
1512 int64_t energy_balance
= 0;
1513 bank_account_t bank_account
;
1516 ledger_t ledger
= LEDGER_NULL
;
1517 if (bank_task
== BANK_TASK_NULL
) {
1523 /* Grab a ledger reference on bt_ledger for bank_task */
1524 ledger
= bank_get_bank_task_ledger_with_ref(bank_task
);
1526 lck_mtx_lock(&bank_task
->bt_acc_to_charge_lock
);
1529 kr
= ledger_get_balance(ledger
, task_ledgers
.cpu_time_billed_to_others
, &temp
);
1530 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1531 cpu_balance
+= temp
;
1533 #if DEVELOPMENT || DEBUG
1535 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1537 #endif /* DEVELOPMENT || DEBUG */
1539 kr
= ledger_get_balance(ledger
, task_ledgers
.energy_billed_to_others
, &temp
);
1540 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1541 energy_balance
+= temp
;
1545 queue_iterate(&bank_task
->bt_accounts_to_charge
, bank_account
, bank_account_t
, ba_next_acc_to_charge
) {
1547 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.cpu_time
, &temp
);
1548 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1549 cpu_balance
+= temp
;
1551 #if DEVELOPMENT || DEBUG
1553 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1555 #endif /* DEVELOPMENT || DEBUG */
1557 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.energy
, &temp
);
1558 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1559 energy_balance
+= temp
;
1562 lck_mtx_unlock(&bank_task
->bt_acc_to_charge_lock
);
1564 ledger_dereference(ledger
);
1566 *cpu_time
= (uint64_t)cpu_balance
;
1567 *energy
= (uint64_t)energy_balance
;
1572 * Routine: bank_get_voucher_bank_account
1573 * Purpose: Get the bank account from the voucher.
1574 * Returns: bank_account if bank_account attribute present in voucher.
1575 * NULL on no attribute or no bank_element
1577 static bank_account_t
1578 bank_get_voucher_bank_account(ipc_voucher_t voucher
)
1580 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
1581 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
1582 mach_voucher_attr_value_handle_t vals
[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED
];
1583 mach_voucher_attr_value_handle_array_size_t val_count
;
1586 val_count
= MACH_VOUCHER_ATTR_VALUE_MAX_NESTED
;
1587 kr
= mach_voucher_attr_control_get_values(bank_voucher_attr_control
,
1592 if (kr
!= KERN_SUCCESS
|| val_count
== 0) {
1593 return BANK_ACCOUNT_NULL
;
1596 bank_element
= HANDLE_TO_BANK_ELEMENT(vals
[0]);
1597 if (bank_element
== BANK_DEFAULT_VALUE
) {
1598 return BANK_ACCOUNT_NULL
;
1600 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
1601 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
1604 if (bank_element
->be_type
== BANK_TASK
) {
1605 return BANK_ACCOUNT_NULL
;
1606 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
1607 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
1608 return bank_account
;
1610 panic("Bogus bank type: %d passed in bank_get_voucher_bank_account\n", bank_element
->be_type
);
1612 return BANK_ACCOUNT_NULL
;
1616 * Routine: bank_get_bank_task_ledger_with_ref
1617 * Purpose: Get the bank ledger from the bank task and return a reference to it.
1620 bank_get_bank_task_ledger_with_ref(bank_task_t bank_task
)
1622 ledger_t ledger
= LEDGER_NULL
;
1624 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1625 ledger
= bank_task
->bt_ledger
;
1627 ledger_reference(ledger
);
1629 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1635 * Routine: bank_destroy_bank_task_ledger
1636 * Purpose: Drop the bank task reference on the task ledger.
1639 bank_destroy_bank_task_ledger(bank_task_t bank_task
)
1643 /* Remove the ledger reference from the bank task */
1644 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1645 assert(LEDGER_VALID(bank_task
->bt_ledger
));
1646 ledger
= bank_task
->bt_ledger
;
1647 bank_task
->bt_ledger
= LEDGER_NULL
;
1648 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1650 ledger_dereference(ledger
);
1654 * Routine: bank_get_bank_account_ledger
1655 * Purpose: Get the bankledger from the bank account if ba_merchant different than ba_holder
1658 bank_get_bank_account_ledger(bank_account_t bank_account
)
1660 ledger_t bankledger
= LEDGER_NULL
;
1662 if (bank_account
!= BANK_ACCOUNT_NULL
&&
1663 bank_account
->ba_holder
!= bank_account
->ba_merchant
) {
1664 bankledger
= bank_account
->ba_bill
;
1671 * Routine: bank_get_bank_task_thread_group
1672 * Purpose: Get the bank task's thread group from the bank task
1674 static struct thread_group
*
1675 bank_get_bank_task_thread_group(bank_task_t bank_task __unused
)
1677 struct thread_group
*banktg
= NULL
;
1679 #if CONFIG_THREAD_GROUPS
1680 if (bank_task
!= BANK_TASK_NULL
) {
1681 banktg
= bank_task
->bt_thread_group
;
1683 #endif /* CONFIG_THREAD_GROUPS */
1689 * Routine: bank_get_bank_account_thread_group
1690 * Purpose: Get the bank account's thread group from the bank account
1692 static struct thread_group
*
1693 bank_get_bank_account_thread_group(bank_account_t bank_account __unused
)
1695 struct thread_group
*banktg
= NULL
;
1697 #if CONFIG_THREAD_GROUPS
1698 if (bank_account
!= BANK_ACCOUNT_NULL
) {
1699 banktg
= bank_account
->ba_thread_group
;
1701 #endif /* CONFIG_THREAD_GROUPS */
1707 * Routine: bank_get_bank_ledger_thread_group_and_persona
1708 * Purpose: Get the bankledger (chit), thread group and persona id from the voucher.
1709 * Returns: bankledger, thread group if bank_account attribute present in voucher
1713 bank_get_bank_ledger_thread_group_and_persona(
1714 ipc_voucher_t voucher
,
1715 ledger_t
*bankledger
,
1716 struct thread_group
**banktg
,
1717 uint32_t *persona_id
)
1719 bank_account_t bank_account
;
1720 bank_task_t bank_task
;
1721 struct thread_group
*thread_group
= NULL
;
1723 bank_account
= bank_get_voucher_bank_account(voucher
);
1724 bank_task
= get_bank_task_context(current_task(), FALSE
);
1725 if (persona_id
!= NULL
) {
1726 if (bank_account
!= BANK_ACCOUNT_NULL
) {
1727 *persona_id
= bank_account
->ba_so_persona_id
;
1729 *persona_id
= bank_task
->bt_persona_id
;
1733 * Use BANK_ACCOUNT_NULL if the ba_holder is same as ba_merchant
1734 * and bank account thread group is same as current thread group
1735 * i.e. ba_merchant's thread group.
1737 * The bank account might have ba_holder same as ba_merchant but different
1738 * thread group if daemon sends a voucher to an App and then App sends the
1739 * same voucher back to the daemon (IPC code will replace thread group in the
1740 * voucher to App's thread group when it gets auto redeemed by the App).
1742 if ((bank_account
!= NULL
) &&
1743 (bank_account
->ba_holder
== bank_account
->ba_merchant
) &&
1744 (bank_get_bank_account_thread_group(bank_account
) ==
1745 bank_get_bank_task_thread_group(bank_account
->ba_merchant
))) {
1746 bank_account
= BANK_ACCOUNT_NULL
;
1749 if (bankledger
!= NULL
) {
1750 *bankledger
= bank_get_bank_account_ledger(bank_account
);
1753 if (banktg
!= NULL
) {
1754 thread_group
= bank_get_bank_account_thread_group(bank_account
);
1756 /* Return NULL thread group if voucher has current task's thread group */
1757 if (thread_group
== bank_get_bank_task_thread_group(bank_task
)) {
1758 thread_group
= NULL
;
1760 *banktg
= thread_group
;
1762 return KERN_SUCCESS
;
1766 * Routine: bank_swap_thread_bank_ledger
1767 * Purpose: swap the bank ledger on the thread.
1769 * Note: Should be only called for current thread or thread which is not started.
1772 bank_swap_thread_bank_ledger(thread_t thread __unused
, ledger_t new_ledger __unused
)
1775 processor_t processor
;
1776 ledger_t old_ledger
= thread
->t_bankledger
;
1777 int64_t ctime
, effective_ledger_time_consumed
= 0;
1778 int64_t remainder
= 0, consumed
= 0;
1779 int64_t effective_energy_consumed
= 0;
1780 uint64_t thread_energy
;
1782 if (old_ledger
== LEDGER_NULL
&& new_ledger
== LEDGER_NULL
) {
1786 assert((thread
== current_thread() || thread
->started
== 0));
1789 thread_lock(thread
);
1792 * Calculation of time elapsed by the thread before voucher swap.
1793 * Following is the timeline which shows all the variables used in the calculation below.
1797 * |<- consumed ->|<- remainder ->|
1798 * timeline ----------------------------------------------------------------->
1800 * thread_dispatch ctime quantum end
1802 * |<-effective_ledger_time -> |
1803 * deduct_bank_ledger_time
1806 ctime
= mach_absolute_time();
1807 processor
= thread
->last_processor
;
1808 if (processor
!= NULL
) {
1809 if ((int64_t)processor
->quantum_end
> ctime
) {
1810 remainder
= (int64_t)processor
->quantum_end
- ctime
;
1813 consumed
= thread
->quantum_remaining
- remainder
;
1814 effective_ledger_time_consumed
= consumed
- thread
->t_deduct_bank_ledger_time
;
1817 thread
->t_deduct_bank_ledger_time
= consumed
;
1819 thread_energy
= ml_energy_stat(thread
);
1820 effective_energy_consumed
=
1821 thread_energy
- thread
->t_deduct_bank_ledger_energy
;
1822 assert(effective_energy_consumed
>= 0);
1823 thread
->t_deduct_bank_ledger_energy
= thread_energy
;
1825 thread
->t_bankledger
= new_ledger
;
1827 thread_unlock(thread
);
1830 if (old_ledger
!= LEDGER_NULL
) {
1831 ledger_credit(old_ledger
,
1832 bank_ledgers
.cpu_time
,
1833 effective_ledger_time_consumed
);
1834 ledger_credit(old_ledger
,
1835 bank_ledgers
.energy
,
1836 effective_energy_consumed
);
1841 * Routine: bank_verify_persona_id
1842 * Purpose: Verifies if the persona id is valid
1844 * The caller should check if the task is entitled
1848 bank_verify_persona_id(uint32_t persona_id
)
1850 /* A successful lookup implies that the persona id is valid */
1851 void *persona
= persona_lookup(persona_id
);
1855 persona_put(persona
);