2 * Copyright (c) 2012-2013 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/kalloc.h>
41 #include <kern/ledger.h>
42 #include <sys/kdebug.h>
43 #include <IOKit/IOBSD.h>
44 #include <mach/mach_voucher_attr_control.h>
46 static zone_t bank_task_zone
, bank_account_zone
;
47 #define MAX_BANK_TASK (CONFIG_TASK_MAX)
48 #define MAX_BANK_ACCOUNT (CONFIG_TASK_MAX + CONFIG_THREAD_MAX)
50 #define BANK_ELEMENT_TO_HANDLE(x) (CAST_DOWN(bank_handle_t, (x)))
51 #define HANDLE_TO_BANK_ELEMENT(x) (CAST_DOWN(bank_element_t, (x)))
53 /* Need macro since bank_element_t is 4 byte aligned on release kernel and direct type case gives compilation error */
54 #define CAST_TO_BANK_ELEMENT(x) ((bank_element_t)((void *)(x)))
55 #define CAST_TO_BANK_TASK(x) ((bank_task_t)((void *)(x)))
56 #define CAST_TO_BANK_ACCOUNT(x) ((bank_account_t)((void *)(x)))
58 ipc_voucher_attr_control_t bank_voucher_attr_control
; /* communication channel from ATM to voucher system */
60 #if DEVELOPMENT || DEBUG
61 queue_head_t bank_tasks_list
;
62 queue_head_t bank_accounts_list
;
65 static ledger_template_t bank_ledger_template
= NULL
;
66 struct _bank_ledger_indices bank_ledgers
= { -1 };
68 static bank_task_t
bank_task_alloc_init(task_t task
);
69 static bank_account_t
bank_account_alloc_init(bank_task_t bank_holder
, bank_task_t bank_merchant
,
70 bank_task_t bank_secureoriginator
, bank_task_t bank_proximateprocess
);
71 static bank_task_t
get_bank_task_context(task_t task
, boolean_t initialize
);
72 static void bank_task_dealloc(bank_task_t bank_task
, mach_voucher_attr_value_reference_t sync
);
73 static kern_return_t
bank_account_dealloc_with_sync(bank_account_t bank_account
, mach_voucher_attr_value_reference_t sync
);
74 static void bank_rollup_chit_to_tasks(ledger_t bill
, bank_task_t bank_holder
, bank_task_t bank_merchant
);
75 static void init_bank_ledgers(void);
76 static boolean_t
bank_task_is_propagate_entitled(task_t t
);
78 static lck_spin_t g_bank_task_lock_data
; /* lock to protect task->bank_context transition */
80 #define global_bank_task_lock_init() \
81 lck_spin_init(&g_bank_task_lock_data, &bank_lock_grp, &bank_lock_attr)
82 #define global_bank_task_lock_destroy() \
83 lck_spin_destroy(&g_bank_task_lock_data, &bank_lock_grp)
84 #define global_bank_task_lock() \
85 lck_spin_lock(&g_bank_task_lock_data)
86 #define global_bank_task_lock_try() \
87 lck_spin_try_lock(&g_bank_task_lock_data)
88 #define global_bank_task_unlock() \
89 lck_spin_unlock(&g_bank_task_lock_data)
91 extern uint64_t proc_uniqueid(void *p
);
92 extern int32_t proc_pid(void *p
);
93 extern int32_t proc_pidversion(void *p
);
94 extern uint32_t proc_persona_id(void *p
);
95 extern uint32_t proc_getuid(void *p
);
96 extern uint32_t proc_getgid(void *p
);
97 extern void proc_getexecutableuuid(void *p
, unsigned char *uuidbuf
, unsigned long size
);
98 extern int kauth_cred_issuser(void *cred
);
99 extern void* kauth_cred_get(void);
104 ipc_voucher_attr_manager_t __assert_only manager
,
105 mach_voucher_attr_key_t __assert_only key
,
106 mach_voucher_attr_value_handle_t value
,
107 mach_voucher_attr_value_reference_t sync
);
111 ipc_voucher_attr_manager_t __assert_only manager
,
112 mach_voucher_attr_key_t __assert_only key
,
113 mach_voucher_attr_recipe_command_t command
,
114 mach_voucher_attr_value_handle_array_t prev_values
,
115 mach_msg_type_number_t __assert_only prev_value_count
,
116 mach_voucher_attr_content_t recipe
,
117 mach_voucher_attr_content_size_t recipe_size
,
118 mach_voucher_attr_value_handle_t
*out_value
,
119 mach_voucher_attr_value_flags_t
*out_flags
,
120 ipc_voucher_t
*out_value_voucher
);
123 bank_extract_content(
124 ipc_voucher_attr_manager_t __assert_only manager
,
125 mach_voucher_attr_key_t __assert_only key
,
126 mach_voucher_attr_value_handle_array_t values
,
127 mach_msg_type_number_t value_count
,
128 mach_voucher_attr_recipe_command_t
*out_command
,
129 mach_voucher_attr_content_t out_recipe
,
130 mach_voucher_attr_content_size_t
*in_out_recipe_size
);
134 ipc_voucher_attr_manager_t __assert_only manager
,
135 mach_voucher_attr_key_t __assert_only key
,
136 mach_voucher_attr_value_handle_array_t values
,
137 mach_msg_type_number_t value_count
,
138 mach_voucher_attr_command_t command
,
139 mach_voucher_attr_content_t in_content
,
140 mach_voucher_attr_content_size_t in_content_size
,
141 mach_voucher_attr_content_t out_content
,
142 mach_voucher_attr_content_size_t
*in_out_content_size
);
145 bank_release(ipc_voucher_attr_manager_t __assert_only manager
);
148 * communication channel from voucher system to ATM
150 struct ipc_voucher_attr_manager bank_manager
= {
151 .ivam_release_value
= bank_release_value
,
152 .ivam_get_value
= bank_get_value
,
153 .ivam_extract_content
= bank_extract_content
,
154 .ivam_command
= bank_command
,
155 .ivam_release
= bank_release
,
156 .ivam_flags
= (IVAM_FLAGS_SUPPORT_SEND_PREPROCESS
| IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS
),
160 #if DEVELOPMENT || DEBUG
161 decl_lck_mtx_data(, bank_tasks_list_lock
);
162 decl_lck_mtx_data(, bank_accounts_list_lock
);
164 lck_grp_t bank_dev_lock_grp
;
165 lck_attr_t bank_dev_lock_attr
;
166 lck_grp_attr_t bank_dev_lock_grp_attr
;
170 * Lock group attributes for bank sub system.
172 lck_grp_t bank_lock_grp
;
173 lck_attr_t bank_lock_attr
;
174 lck_grp_attr_t bank_lock_grp_attr
;
178 * Purpose: Initialize the BANK subsystem.
184 kern_return_t kr
= KERN_SUCCESS
;
185 /* setup zones for bank_task and bank_account objects */
186 bank_task_zone
= zinit(sizeof(struct bank_task
),
187 MAX_BANK_TASK
* sizeof(struct bank_task
),
188 sizeof(struct bank_task
),
191 bank_account_zone
= zinit(sizeof(struct bank_account
),
192 MAX_BANK_ACCOUNT
* sizeof(struct bank_account
),
193 sizeof(struct bank_account
),
198 /* Initialize bank lock group and lock attributes. */
199 lck_grp_attr_setdefault(&bank_lock_grp_attr
);
200 lck_grp_init(&bank_lock_grp
, "bank_lock", &bank_lock_grp_attr
);
201 lck_attr_setdefault(&bank_lock_attr
);
202 global_bank_task_lock_init();
204 #if DEVELOPMENT || DEBUG
205 /* Initialize global bank development lock group and lock attributes. */
206 lck_grp_attr_setdefault(&bank_dev_lock_grp_attr
);
207 lck_grp_init(&bank_dev_lock_grp
, "bank_dev_lock", &bank_dev_lock_grp_attr
);
208 lck_attr_setdefault(&bank_dev_lock_attr
);
210 lck_mtx_init(&bank_tasks_list_lock
, &bank_dev_lock_grp
, &bank_dev_lock_attr
);
211 lck_mtx_init(&bank_accounts_list_lock
, &bank_dev_lock_grp
, &bank_dev_lock_attr
);
213 queue_init(&bank_tasks_list
);
214 queue_init(&bank_accounts_list
);
217 /* Register the bank manager with the Vouchers sub system. */
218 kr
= ipc_register_well_known_mach_voucher_attr_manager(
221 MACH_VOUCHER_ATTR_KEY_BANK
,
222 &bank_voucher_attr_control
);
223 if (kr
!= KERN_SUCCESS
)
224 panic("BANK subsystem initialization failed");
226 kprintf("BANK subsystem is initialized\n");
232 * BANK Resource Manager Routines.
237 * Routine: bank_release_value
238 * Purpose: Release a value, if sync matches the sync count in value.
239 * Returns: KERN_SUCCESS: on Successful deletion.
240 * KERN_FAILURE: if sync value does not matches.
244 ipc_voucher_attr_manager_t __assert_only manager
,
245 mach_voucher_attr_key_t __assert_only key
,
246 mach_voucher_attr_value_handle_t value
,
247 mach_voucher_attr_value_reference_t sync
)
249 bank_task_t bank_task
= BANK_TASK_NULL
;
250 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
251 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
252 kern_return_t kr
= KERN_SUCCESS
;
254 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
255 assert(manager
== &bank_manager
);
258 bank_element
= HANDLE_TO_BANK_ELEMENT(value
);
259 /* Voucher system should never release the default or persistent value */
260 assert(bank_element
!= BANK_DEFAULT_VALUE
&& bank_element
!= BANK_DEFAULT_TASK_VALUE
);
262 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
263 /* Return success for default and default task value */
268 if (bank_element
->be_type
== BANK_TASK
) {
269 bank_task
= CAST_TO_BANK_TASK(bank_element
);
271 if (bank_task
->bt_made
!= (int)sync
) {
275 bank_task_made_release_num(bank_task
, sync
);
276 bank_task_dealloc(bank_task
, sync
);
277 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
278 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
279 kr
= bank_account_dealloc_with_sync(bank_account
, sync
);
281 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
289 * Routine: bank_get_value
293 ipc_voucher_attr_manager_t __assert_only manager
,
294 mach_voucher_attr_key_t __assert_only key
,
295 mach_voucher_attr_recipe_command_t command
,
296 mach_voucher_attr_value_handle_array_t prev_values
,
297 mach_msg_type_number_t prev_value_count
,
298 mach_voucher_attr_content_t __unused recipe
,
299 mach_voucher_attr_content_size_t __unused recipe_size
,
300 mach_voucher_attr_value_handle_t
*out_value
,
301 mach_voucher_attr_value_flags_t
*out_flags
,
302 ipc_voucher_t
*out_value_voucher
)
304 bank_task_t bank_task
= BANK_TASK_NULL
;
305 bank_task_t bank_holder
= BANK_TASK_NULL
;
306 bank_task_t bank_merchant
= BANK_TASK_NULL
;
307 bank_task_t bank_secureoriginator
= BANK_TASK_NULL
;
308 bank_task_t bank_proximateprocess
= BANK_TASK_NULL
;
309 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
310 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
311 bank_account_t old_bank_account
= BANK_ACCOUNT_NULL
;
312 mach_voucher_attr_value_handle_t bank_handle
;
314 kern_return_t kr
= KERN_SUCCESS
;
315 mach_msg_type_number_t i
;
317 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
318 assert(manager
== &bank_manager
);
320 /* never an out voucher */
321 *out_value_voucher
= IPC_VOUCHER_NULL
;
322 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE
;
326 case MACH_VOUCHER_ATTR_BANK_CREATE
:
328 /* Return the default task value instead of bank task */
329 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
330 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
333 case MACH_VOUCHER_ATTR_AUTO_REDEEM
:
335 for (i
= 0; i
< prev_value_count
; i
++) {
336 bank_handle
= prev_values
[i
];
337 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
339 /* Should not have received default task value from an IPC */
340 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
)
343 task
= current_task();
344 if (bank_element
->be_type
== BANK_TASK
) {
345 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
346 bank_secureoriginator
= bank_holder
;
347 bank_proximateprocess
= bank_holder
;
348 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
349 old_bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
350 bank_holder
= old_bank_account
->ba_holder
;
351 bank_secureoriginator
= old_bank_account
->ba_secureoriginator
;
352 bank_proximateprocess
= old_bank_account
->ba_proximateprocess
;
354 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
357 bank_merchant
= get_bank_task_context(task
, FALSE
);
358 if (bank_merchant
== BANK_TASK_NULL
)
359 return KERN_RESOURCE_SHORTAGE
;
361 /* Check if trying to redeem for self task, return the default bank task */
362 if (bank_holder
== bank_merchant
&&
363 bank_holder
== bank_secureoriginator
&&
364 bank_holder
== bank_proximateprocess
) {
365 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
366 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
370 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
371 bank_secureoriginator
, bank_proximateprocess
);
372 if (bank_account
== BANK_ACCOUNT_NULL
)
373 return KERN_RESOURCE_SHORTAGE
;
375 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
379 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
382 case MACH_VOUCHER_ATTR_SEND_PREPROCESS
:
384 for (i
= 0; i
< prev_value_count
; i
++) {
385 bank_handle
= prev_values
[i
];
386 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
388 if (bank_element
== BANK_DEFAULT_VALUE
)
391 task
= current_task();
392 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
393 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(task
, FALSE
));
396 if (bank_element
->be_type
== BANK_TASK
) {
397 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
398 bank_secureoriginator
= bank_holder
;
399 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
400 old_bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
401 bank_holder
= old_bank_account
->ba_holder
;
402 bank_secureoriginator
= old_bank_account
->ba_secureoriginator
;
404 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
407 bank_merchant
= get_bank_task_context(task
, FALSE
);
408 if (bank_merchant
== BANK_TASK_NULL
)
409 return KERN_RESOURCE_SHORTAGE
;
412 * If the process doesn't have secure persona entitlement,
413 * then replace the secure originator to current task.
415 if (bank_merchant
->bt_hasentitlement
== 0) {
416 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
417 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SECURE_ORIGINATOR_CHANGED
))) | DBG_FUNC_NONE
,
418 bank_secureoriginator
->bt_pid
, bank_merchant
->bt_pid
, 0, 0, 0);
419 bank_secureoriginator
= bank_merchant
;
422 bank_proximateprocess
= bank_merchant
;
424 /* Check if trying to redeem for self task, return the bank task */
425 if (bank_holder
== bank_merchant
&&
426 bank_holder
== bank_secureoriginator
&&
427 bank_holder
== bank_proximateprocess
) {
428 bank_task_reference(bank_holder
);
429 bank_task_made_reference(bank_holder
);
430 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_holder
);
433 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
434 bank_secureoriginator
, bank_proximateprocess
);
435 if (bank_account
== BANK_ACCOUNT_NULL
)
436 return KERN_RESOURCE_SHORTAGE
;
438 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
442 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
445 case MACH_VOUCHER_ATTR_REDEEM
:
447 for (i
= 0; i
< prev_value_count
; i
++) {
448 bank_handle
= prev_values
[i
];
449 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
451 if (bank_element
== BANK_DEFAULT_VALUE
)
454 task
= current_task();
455 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
456 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
457 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
460 if (bank_element
->be_type
== BANK_TASK
) {
461 bank_task
= CAST_TO_BANK_TASK(bank_element
);
462 if (bank_task
!= get_bank_task_context(task
, FALSE
)) {
463 panic("Found a bank task of another task with bank_context: %p", bank_task
);
466 bank_task_reference(bank_task
);
467 bank_task_made_reference(bank_task
);
468 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_task
);
471 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
472 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
473 bank_merchant
= bank_account
->ba_merchant
;
474 if (bank_merchant
!= get_bank_task_context(task
, FALSE
)) {
475 panic("Found another bank task: %p as a bank merchant\n", bank_merchant
);
478 bank_account_reference(bank_account
);
479 bank_account_made_reference(bank_account
);
480 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
483 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
487 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
491 kr
= KERN_INVALID_ARGUMENT
;
500 * Routine: bank_extract_content
501 * Purpose: Extract a set of aid from an array of voucher values.
502 * Returns: KERN_SUCCESS: on Success.
503 * KERN_FAILURE: one of the value is not present in the hash.
504 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of aid.
507 bank_extract_content(
508 ipc_voucher_attr_manager_t __assert_only manager
,
509 mach_voucher_attr_key_t __assert_only key
,
510 mach_voucher_attr_value_handle_array_t values
,
511 mach_msg_type_number_t value_count
,
512 mach_voucher_attr_recipe_command_t
*out_command
,
513 mach_voucher_attr_content_t out_recipe
,
514 mach_voucher_attr_content_size_t
*in_out_recipe_size
)
516 bank_task_t bank_task
= BANK_TASK_NULL
;
517 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
518 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
519 mach_voucher_attr_value_handle_t bank_handle
;
520 char buf
[MACH_VOUCHER_BANK_CONTENT_SIZE
];
521 mach_msg_type_number_t i
;
523 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
524 assert(manager
== &bank_manager
);
526 for (i
= 0; i
< value_count
; i
++) {
527 bank_handle
= values
[i
];
528 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
529 if (bank_element
== BANK_DEFAULT_VALUE
)
532 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
533 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
536 if (MACH_VOUCHER_BANK_CONTENT_SIZE
> *in_out_recipe_size
) {
537 *in_out_recipe_size
= 0;
538 return KERN_NO_SPACE
;
541 if (bank_element
->be_type
== BANK_TASK
) {
542 bank_task
= CAST_TO_BANK_TASK(bank_element
);
543 snprintf(buf
, MACH_VOUCHER_BANK_CONTENT_SIZE
,
544 " Bank Context for a pid %d\n", bank_task
->bt_pid
);
545 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
546 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
547 snprintf(buf
, MACH_VOUCHER_BANK_CONTENT_SIZE
,
548 " Bank Account linking holder pid %d with merchant pid %d, originator PID/persona: %d, %u and proximate PID/persona: %d, %u\n",
549 bank_account
->ba_holder
->bt_pid
,
550 bank_account
->ba_merchant
->bt_pid
,
551 bank_account
->ba_secureoriginator
->bt_pid
,
552 bank_account
->ba_secureoriginator
->bt_persona_id
,
553 bank_account
->ba_proximateprocess
->bt_pid
,
554 bank_account
->ba_proximateprocess
->bt_persona_id
);
556 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
560 memcpy(&out_recipe
[0], buf
, strlen(buf
) + 1);
561 *out_command
= MACH_VOUCHER_ATTR_BANK_NULL
;
562 *in_out_recipe_size
= (mach_voucher_attr_content_size_t
)strlen(buf
) + 1;
570 * Routine: bank_command
571 * Purpose: Execute a command against a set of ATM values.
572 * Returns: KERN_SUCCESS: On successful execution of command.
573 KERN_FAILURE: On failure.
577 ipc_voucher_attr_manager_t __assert_only manager
,
578 mach_voucher_attr_key_t __assert_only key
,
579 mach_voucher_attr_value_handle_array_t __unused values
,
580 mach_msg_type_number_t __unused value_count
,
581 mach_voucher_attr_command_t __unused command
,
582 mach_voucher_attr_content_t __unused in_content
,
583 mach_voucher_attr_content_size_t __unused in_content_size
,
584 mach_voucher_attr_content_t __unused out_content
,
585 mach_voucher_attr_content_size_t __unused
*out_content_size
)
587 bank_task_t bank_task
= BANK_TASK_NULL
;
588 bank_task_t bank_secureoriginator
= BANK_TASK_NULL
;
589 bank_task_t bank_proximateprocess
= BANK_TASK_NULL
;
590 struct persona_token
*token
= NULL
;
591 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
592 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
593 mach_voucher_attr_value_handle_t bank_handle
;
594 mach_msg_type_number_t i
;
597 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
598 assert(manager
== &bank_manager
);
601 case BANK_ORIGINATOR_PID
:
603 if ((sizeof(pid
)) > *out_content_size
) {
604 *out_content_size
= 0;
605 return KERN_NO_SPACE
;
608 for (i
= 0; i
< value_count
; i
++) {
609 bank_handle
= values
[i
];
610 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
611 if (bank_element
== BANK_DEFAULT_VALUE
)
614 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
615 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
618 if (bank_element
->be_type
== BANK_TASK
) {
619 bank_task
= CAST_TO_BANK_TASK(bank_element
);
620 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
621 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
622 bank_task
= bank_account
->ba_holder
;
624 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
626 pid
= bank_task
->bt_pid
;
628 memcpy(&out_content
[0], &pid
, sizeof(pid
));
629 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(pid
);
632 /* In the case of no value, return error KERN_INVALID_VALUE */
633 *out_content_size
= 0;
634 return KERN_INVALID_VALUE
;
638 case BANK_PERSONA_TOKEN
:
640 if ((sizeof(struct persona_token
)) > *out_content_size
) {
641 *out_content_size
= 0;
642 return KERN_NO_SPACE
;
644 for (i
= 0; i
< value_count
; i
++) {
645 bank_handle
= values
[i
];
646 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
647 if (bank_element
== BANK_DEFAULT_VALUE
)
650 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
651 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
654 if (bank_element
->be_type
== BANK_TASK
) {
655 *out_content_size
= 0;
656 return KERN_INVALID_OBJECT
;
657 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
658 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
659 bank_secureoriginator
= bank_account
->ba_secureoriginator
;
660 bank_proximateprocess
= bank_account
->ba_proximateprocess
;
662 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
664 token
= (struct persona_token
*)(void *)&out_content
[0];
665 memcpy(&token
->originator
, &bank_secureoriginator
->bt_proc_persona
, sizeof(struct proc_persona_info
));
666 memcpy(&token
->proximate
, &bank_proximateprocess
->bt_proc_persona
, sizeof(struct proc_persona_info
));
668 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(*token
);
671 /* In the case of no value, return error KERN_INVALID_VALUE */
672 *out_content_size
= 0;
673 return KERN_INVALID_VALUE
;
678 return KERN_INVALID_ARGUMENT
;
686 ipc_voucher_attr_manager_t __assert_only manager
)
688 assert(manager
== &bank_manager
);
694 * Bank Internal Routines.
698 * Routine: bank_task_alloc_init
699 * Purpose: Allocate and initialize a bank task structure.
700 * Returns: bank_task_t on Success.
701 * BANK_TASK_NULL: on Failure.
702 * Notes: Leaves the task and creditcard blank and has only 1 ref,
703 needs to take 1 extra ref after the task field is initialized.
706 bank_task_alloc_init(task_t task
)
708 bank_task_t new_bank_task
;
710 new_bank_task
= (bank_task_t
) zalloc(bank_task_zone
);
711 if (new_bank_task
== BANK_TASK_NULL
)
712 return BANK_TASK_NULL
;
714 new_bank_task
->bt_type
= BANK_TASK
;
715 new_bank_task
->bt_refs
= 1;
716 new_bank_task
->bt_made
= 0;
717 new_bank_task
->bt_creditcard
= NULL
;
718 new_bank_task
->bt_hasentitlement
= bank_task_is_propagate_entitled(task
);
719 queue_init(&new_bank_task
->bt_accounts_to_pay
);
720 queue_init(&new_bank_task
->bt_accounts_to_charge
);
721 lck_mtx_init(&new_bank_task
->bt_acc_to_pay_lock
, &bank_lock_grp
, &bank_lock_attr
);
722 lck_mtx_init(&new_bank_task
->bt_acc_to_charge_lock
, &bank_lock_grp
, &bank_lock_attr
);
725 * Initialize the persona_id struct
727 bzero(&new_bank_task
->bt_proc_persona
, sizeof(new_bank_task
->bt_proc_persona
));
728 new_bank_task
->bt_flags
= 0;
729 new_bank_task
->bt_unique_pid
= proc_uniqueid(task
->bsd_info
);
730 new_bank_task
->bt_pid
= proc_pid(task
->bsd_info
);
731 new_bank_task
->bt_pidversion
= proc_pidversion(task
->bsd_info
);
732 new_bank_task
->bt_persona_id
= proc_persona_id(task
->bsd_info
);
733 new_bank_task
->bt_uid
= proc_getuid(task
->bsd_info
);
734 new_bank_task
->bt_gid
= proc_getgid(task
->bsd_info
);
735 proc_getexecutableuuid(task
->bsd_info
, new_bank_task
->bt_macho_uuid
, sizeof(new_bank_task
->bt_macho_uuid
));
737 #if DEVELOPMENT || DEBUG
738 new_bank_task
->bt_task
= NULL
;
739 lck_mtx_lock(&bank_tasks_list_lock
);
740 queue_enter(&bank_tasks_list
, new_bank_task
, bank_task_t
, bt_global_elt
);
741 lck_mtx_unlock(&bank_tasks_list_lock
);
743 return (new_bank_task
);
747 * Routine: proc_is_propagate_entitled
748 * Purpose: Check if the process has persona propagate entitlement.
749 * Returns: TRUE if entitled.
753 bank_task_is_propagate_entitled(task_t t
)
755 /* Return TRUE if root process */
756 if (0 == kauth_cred_issuser(kauth_cred_get())) {
757 /* If it's a non-root process, it needs to have the entitlement for secure originator propagation */
758 boolean_t entitled
= FALSE
;
759 entitled
= IOTaskHasEntitlement(t
, ENTITLEMENT_PERSONA_PROPAGATE
);
767 * Routine: bank_account_alloc_init
768 * Purpose: Allocate and Initialize the bank account struct.
769 * Returns: bank_account_t : On Success.
770 * BANK_ACCOUNT_NULL: On Failure.
772 static bank_account_t
773 bank_account_alloc_init(
774 bank_task_t bank_holder
,
775 bank_task_t bank_merchant
,
776 bank_task_t bank_secureoriginator
,
777 bank_task_t bank_proximateprocess
)
779 bank_account_t new_bank_account
;
780 bank_account_t bank_account
;
781 boolean_t entry_found
= FALSE
;
782 ledger_t new_ledger
= ledger_instantiate(bank_ledger_template
, LEDGER_CREATE_INACTIVE_ENTRIES
);
784 if (new_ledger
== NULL
)
785 return BANK_ACCOUNT_NULL
;
787 ledger_entry_setactive(new_ledger
, bank_ledgers
.cpu_time
);
788 new_bank_account
= (bank_account_t
) zalloc(bank_account_zone
);
789 if (new_bank_account
== BANK_ACCOUNT_NULL
) {
790 ledger_dereference(new_ledger
);
791 return BANK_ACCOUNT_NULL
;
794 new_bank_account
->ba_type
= BANK_ACCOUNT
;
795 new_bank_account
->ba_refs
= 1;
796 new_bank_account
->ba_made
= 1;
797 new_bank_account
->ba_bill
= new_ledger
;
798 new_bank_account
->ba_merchant
= bank_merchant
;
799 new_bank_account
->ba_holder
= bank_holder
;
800 new_bank_account
->ba_secureoriginator
= bank_secureoriginator
;
801 new_bank_account
->ba_proximateprocess
= bank_proximateprocess
;
803 /* Iterate through accounts need to pay list to find the existing entry */
804 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
805 queue_iterate(&bank_holder
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
) {
806 if (bank_account
->ba_merchant
!= bank_merchant
||
807 bank_account
->ba_secureoriginator
!= bank_secureoriginator
||
808 bank_account
->ba_proximateprocess
!= bank_proximateprocess
)
812 /* Take a made ref, since this value would be returned to voucher system. */
813 bank_account_reference(bank_account
);
814 bank_account_made_reference(bank_account
);
820 /* Create a linkage between the holder and the merchant task, Grab both the list locks before adding it to the list. */
821 lck_mtx_lock(&bank_merchant
->bt_acc_to_charge_lock
);
823 /* Add the account entry into Accounts need to pay account link list. */
824 queue_enter(&bank_holder
->bt_accounts_to_pay
, new_bank_account
, bank_account_t
, ba_next_acc_to_pay
);
826 /* Add the account entry into Accounts need to charge account link list. */
827 queue_enter(&bank_merchant
->bt_accounts_to_charge
, new_bank_account
, bank_account_t
, ba_next_acc_to_charge
);
829 lck_mtx_unlock(&bank_merchant
->bt_acc_to_charge_lock
);
832 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
835 ledger_dereference(new_ledger
);
836 zfree(bank_account_zone
, new_bank_account
);
840 bank_task_reference(bank_holder
);
841 bank_task_reference(bank_merchant
);
842 bank_task_reference(bank_secureoriginator
);
843 bank_task_reference(bank_proximateprocess
);
845 #if DEVELOPMENT || DEBUG
846 new_bank_account
->ba_task
= NULL
;
847 lck_mtx_lock(&bank_accounts_list_lock
);
848 queue_enter(&bank_accounts_list
, new_bank_account
, bank_account_t
, ba_global_elt
);
849 lck_mtx_unlock(&bank_accounts_list_lock
);
852 return (new_bank_account
);
856 * Routine: get_bank_task_context
857 * Purpose: Get the bank context of the given task
858 * Returns: bank_task_t on Success.
859 * BANK_TASK_NULL: on Failure.
860 * Note: Initialize bank context if NULL.
863 get_bank_task_context
865 boolean_t initialize
)
867 bank_task_t bank_task
;
869 if (task
->bank_context
|| !initialize
) {
870 assert(task
->bank_context
!= NULL
);
871 return (task
->bank_context
);
874 bank_task
= bank_task_alloc_init(task
);
876 /* Grab the task lock and check if we won the race. */
878 if (task
->bank_context
) {
880 if (bank_task
!= BANK_TASK_NULL
)
881 bank_task_dealloc(bank_task
, 1);
882 return (task
->bank_context
);
883 } else if (bank_task
== BANK_TASK_NULL
) {
885 return BANK_TASK_NULL
;
887 /* We won the race. Take a ref on the ledger and initialize bank task. */
888 bank_task
->bt_creditcard
= task
->ledger
;
889 #if DEVELOPMENT || DEBUG
890 bank_task
->bt_task
= task
;
892 ledger_reference(task
->ledger
);
894 /* Grab the global bank task lock before setting the bank context on a task */
895 global_bank_task_lock();
896 task
->bank_context
= bank_task
;
897 global_bank_task_unlock();
905 * Routine: bank_task_dealloc
906 * Purpose: Drops the reference on bank task.
911 bank_task_t bank_task
,
912 mach_voucher_attr_value_reference_t sync
)
914 assert(bank_task
->bt_refs
>= 0);
916 if (bank_task_release_num(bank_task
, sync
) > (int)sync
)
919 assert(bank_task
->bt_refs
== 0);
920 assert(queue_empty(&bank_task
->bt_accounts_to_pay
));
921 assert(queue_empty(&bank_task
->bt_accounts_to_charge
));
923 ledger_dereference(bank_task
->bt_creditcard
);
924 lck_mtx_destroy(&bank_task
->bt_acc_to_pay_lock
, &bank_lock_grp
);
925 lck_mtx_destroy(&bank_task
->bt_acc_to_charge_lock
, &bank_lock_grp
);
927 #if DEVELOPMENT || DEBUG
928 lck_mtx_lock(&bank_tasks_list_lock
);
929 queue_remove(&bank_tasks_list
, bank_task
, bank_task_t
, bt_global_elt
);
930 lck_mtx_unlock(&bank_tasks_list_lock
);
933 zfree(bank_task_zone
, bank_task
);
937 * Routine: bank_account_dealloc_with_sync
938 * Purpose: Drop the reference on bank account if the sync matches.
939 * Returns: KERN_SUCCESS if sync matches.
940 * KERN_FAILURE on mismatch.
943 bank_account_dealloc_with_sync(
944 bank_account_t bank_account
,
945 mach_voucher_attr_value_reference_t sync
)
947 bank_task_t bank_holder
= bank_account
->ba_holder
;
948 bank_task_t bank_merchant
= bank_account
->ba_merchant
;
949 bank_task_t bank_secureoriginator
= bank_account
->ba_secureoriginator
;
950 bank_task_t bank_proximateprocess
= bank_account
->ba_proximateprocess
;
952 /* Grab the acc to pay list lock and check the sync value */
953 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
955 if (bank_account
->ba_made
!= (int)sync
) {
956 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
960 bank_account_made_release_num(bank_account
, sync
);
962 if (bank_account_release_num(bank_account
, sync
) > (int)sync
)
963 panic("Sync and ref value did not match for bank account %p\n", bank_account
);
966 /* Grab both the acc to pay and acc to charge locks */
967 lck_mtx_lock(&bank_merchant
->bt_acc_to_charge_lock
);
969 bank_rollup_chit_to_tasks(bank_account
->ba_bill
, bank_holder
, bank_merchant
);
971 /* Remove the account entry from Accounts need to pay account link list. */
972 queue_remove(&bank_holder
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
);
974 /* Remove the account entry from Accounts need to charge account link list. */
975 queue_remove(&bank_merchant
->bt_accounts_to_charge
, bank_account
, bank_account_t
, ba_next_acc_to_charge
);
977 lck_mtx_unlock(&bank_merchant
->bt_acc_to_charge_lock
);
978 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
980 ledger_dereference(bank_account
->ba_bill
);
982 /* Drop the reference of bank holder and merchant */
983 bank_task_dealloc(bank_holder
, 1);
984 bank_task_dealloc(bank_merchant
, 1);
985 bank_task_dealloc(bank_secureoriginator
, 1);
986 bank_task_dealloc(bank_proximateprocess
, 1);
988 #if DEVELOPMENT || DEBUG
989 lck_mtx_lock(&bank_accounts_list_lock
);
990 queue_remove(&bank_accounts_list
, bank_account
, bank_account_t
, ba_global_elt
);
991 lck_mtx_unlock(&bank_accounts_list_lock
);
994 zfree(bank_account_zone
, bank_account
);
999 * Routine: bank_rollup_chit_to_tasks
1000 * Purpose: Debit and Credit holder's and merchant's ledgers.
1004 bank_rollup_chit_to_tasks(
1006 bank_task_t bank_holder
,
1007 bank_task_t bank_merchant
)
1009 ledger_amount_t credit
;
1010 ledger_amount_t debit
;
1013 if (bank_holder
== bank_merchant
)
1016 ret
= ledger_get_entries(bill
, bank_ledgers
.cpu_time
, &credit
, &debit
);
1017 if (ret
!= KERN_SUCCESS
) {
1021 #if DEVELOPMENT || DEBUG
1023 panic("bank_rollup: debit: %lld non zero\n", debit
);
1027 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SETTLE_CPU_TIME
))) | DBG_FUNC_NONE
,
1028 bank_merchant
->bt_pid
, bank_holder
->bt_pid
, credit
, debit
, 0);
1030 ledger_credit(bank_holder
->bt_creditcard
, task_ledgers
.cpu_time_billed_to_me
, credit
);
1031 ledger_debit(bank_holder
->bt_creditcard
, task_ledgers
.cpu_time_billed_to_me
, debit
);
1033 ledger_credit(bank_merchant
->bt_creditcard
, task_ledgers
.cpu_time_billed_to_others
, credit
);
1034 ledger_debit(bank_merchant
->bt_creditcard
, task_ledgers
.cpu_time_billed_to_others
, debit
);
1041 * Routine: bank_task_destroy
1042 * Purpose: Drops reference on bank task.
1046 bank_task_destroy(task_t task
)
1048 bank_task_t bank_task
;
1050 /* Grab the global bank task lock before dropping the ref on task bank context */
1051 global_bank_task_lock();
1052 bank_task
= task
->bank_context
;
1053 task
->bank_context
= NULL
;
1054 global_bank_task_unlock();
1056 bank_task_dealloc(bank_task
, 1);
1060 * Routine: bank_task_initialize
1061 * Purpose: Initialize the bank context of a task.
1065 bank_task_initialize(task_t task
)
1067 get_bank_task_context(task
, TRUE
);
1071 * Routine: init_bank_ledgers
1072 * Purpose: Initialize template for bank ledgers.
1076 init_bank_ledgers(void) {
1077 ledger_template_t t
;
1080 assert(bank_ledger_template
== NULL
);
1082 if ((t
= ledger_template_create("Bank ledger")) == NULL
)
1083 panic("couldn't create bank ledger template");
1085 if ((idx
= ledger_entry_add(t
, "cpu_time", "sched", "ns")) < 0) {
1086 panic("couldn't create cpu_time entry for bank ledger template");
1089 bank_ledgers
.cpu_time
= idx
;
1090 bank_ledger_template
= t
;
1093 /* Routine: bank_billed_time_safe
1094 * Purpose: Walk through all the bank accounts billed to me by other tasks and get the current billing balance.
1095 * Called from another task. It takes global bank task lock to make sure the bank context is
1096 not deallocated while accesing it.
1100 bank_billed_time_safe(task_t task
)
1102 bank_task_t bank_task
= BANK_TASK_NULL
;
1103 ledger_amount_t credit
, debit
;
1104 uint64_t balance
= 0;
1107 /* Task might be in exec, grab the global bank task lock before accessing bank context. */
1108 global_bank_task_lock();
1109 /* Grab a reference on bank context */
1110 if (task
->bank_context
!= NULL
) {
1111 bank_task
= task
->bank_context
;
1112 bank_task_reference(bank_task
);
1114 global_bank_task_unlock();
1117 balance
= bank_billed_time(bank_task
);
1118 bank_task_dealloc(bank_task
, 1);
1120 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.cpu_time_billed_to_me
,
1122 if (kr
== KERN_SUCCESS
) {
1123 balance
= credit
- debit
;
1131 * Routine: bank_billed_time
1132 * Purpose: Walk through the Accounts need to pay account list and get the current billing balance.
1136 bank_billed_time(bank_task_t bank_task
)
1138 int64_t balance
= 0;
1140 bank_account_t bank_account
;
1144 if (bank_task
== BANK_TASK_NULL
) {
1149 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1151 kr
= ledger_get_balance(bank_task
->bt_creditcard
, task_ledgers
.cpu_time_billed_to_me
, &temp
);
1152 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1155 #if DEVELOPMENT || DEBUG
1157 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1159 #endif /* DEVELOPMENT || DEBUG */
1161 queue_iterate(&bank_task
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
) {
1163 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.cpu_time
, &temp
);
1164 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1167 #if DEVELOPMENT || DEBUG
1169 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1171 #endif /* DEVELOPMENT || DEBUG */
1173 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1175 return (uint64_t)balance
;
1178 /* Routine: bank_serviced_time_safe
1179 * Purpose: Walk through the bank accounts billed to other tasks by me and get the current balance to be charged.
1180 * Called from another task. It takes global bank task lock to make sure the bank context is
1181 not deallocated while accesing it.
1185 bank_serviced_time_safe(task_t task
)
1187 bank_task_t bank_task
= BANK_TASK_NULL
;
1188 ledger_amount_t credit
, debit
;
1189 uint64_t balance
= 0;
1192 /* Task might be in exec, grab the global bank task lock before accessing bank context. */
1193 global_bank_task_lock();
1194 /* Grab a reference on bank context */
1195 if (task
->bank_context
!= NULL
) {
1196 bank_task
= task
->bank_context
;
1197 bank_task_reference(bank_task
);
1199 global_bank_task_unlock();
1202 balance
= bank_serviced_time(bank_task
);
1203 bank_task_dealloc(bank_task
, 1);
1205 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.cpu_time_billed_to_others
,
1207 if (kr
== KERN_SUCCESS
) {
1208 balance
= credit
- debit
;
1216 * Routine: bank_serviced_time
1217 * Purpose: Walk through the Account need to charge account list and get the current balance to be charged.
1221 bank_serviced_time(bank_task_t bank_task
)
1223 int64_t balance
= 0;
1225 bank_account_t bank_account
;
1229 if (bank_task
== BANK_TASK_NULL
) {
1234 lck_mtx_lock(&bank_task
->bt_acc_to_charge_lock
);
1236 kr
= ledger_get_balance(bank_task
->bt_creditcard
, task_ledgers
.cpu_time_billed_to_others
, &temp
);
1237 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1240 #if DEVELOPMENT || DEBUG
1242 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1244 #endif /* DEVELOPMENT || DEBUG */
1246 queue_iterate(&bank_task
->bt_accounts_to_charge
, bank_account
, bank_account_t
, ba_next_acc_to_charge
) {
1248 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.cpu_time
, &temp
);
1249 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1252 #if DEVELOPMENT || DEBUG
1254 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1256 #endif /* DEVELOPMENT || DEBUG */
1258 lck_mtx_unlock(&bank_task
->bt_acc_to_charge_lock
);
1260 return (uint64_t)balance
;
1264 * Routine: bank_get_voucher_ledger
1265 * Purpose: Get the bankledger (chit) from the voucher.
1266 * Returns: bank_ledger if bank_account attribute present in voucher.
1267 * NULL on no attribute ot bank_task attribute.
1270 bank_get_voucher_ledger(ipc_voucher_t voucher
)
1272 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
1273 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
1274 mach_voucher_attr_value_handle_t vals
[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED
];
1275 mach_voucher_attr_value_handle_array_size_t val_count
;
1276 ledger_t bankledger
= NULL
;
1277 bank_task_t bank_merchant
;
1280 val_count
= MACH_VOUCHER_ATTR_VALUE_MAX_NESTED
;
1281 kr
= mach_voucher_attr_control_get_values(bank_voucher_attr_control
,
1286 if (kr
!= KERN_SUCCESS
)
1292 bank_element
= HANDLE_TO_BANK_ELEMENT(vals
[0]);
1293 if (bank_element
== BANK_DEFAULT_VALUE
)
1296 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
1297 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
1300 if (bank_element
->be_type
== BANK_TASK
) {
1302 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
1303 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
1304 if (bank_account
->ba_holder
!= bank_account
->ba_merchant
) {
1305 /* Return the ledger, if the voucher is redeemed by currrent process. */
1306 bank_merchant
= get_bank_task_context(current_task(), FALSE
);
1307 if (bank_account
->ba_merchant
== bank_merchant
) {
1308 bankledger
= bank_account
->ba_bill
;
1312 panic("Bogus bank type: %d passed in bank_get_voucher_ledger\n", bank_element
->be_type
);
1315 return (bankledger
);
1319 * Routine: bank_swap_thread_bank_ledger
1320 * Purpose: swap the bank ledger on the thread.
1322 * Note: Should be only called for current thread or thread which is not started.
1325 bank_swap_thread_bank_ledger(thread_t thread __unused
, ledger_t new_ledger __unused
)
1329 processor_t processor
;
1330 ledger_t old_ledger
= thread
->t_bankledger
;
1331 int64_t ctime
, effective_ledger_time_consumed
= 0;
1332 int64_t remainder
= 0, consumed
= 0;
1334 if (old_ledger
== NULL
&& new_ledger
== NULL
)
1337 assert((thread
== current_thread() || thread
->started
== 0));
1340 thread_lock(thread
);
1343 * Calculation of time elapsed by the thread before voucher swap.
1344 * Following is the timeline which shows all the variables used in the calculation below.
1348 * |<- consumed ->|<- remainder ->|
1349 * timeline ----------------------------------------------------------------->
1351 * thread_dispatch ctime quantum end
1353 * |<-effective_ledger_time -> |
1354 * deduct_bank_ledger_time
1357 ctime
= mach_absolute_time();
1358 processor
= thread
->last_processor
;
1359 if (processor
!= NULL
) {
1360 if ((int64_t)processor
->quantum_end
> ctime
)
1361 remainder
= (int64_t)processor
->quantum_end
- ctime
;
1363 consumed
= thread
->quantum_remaining
- remainder
;
1364 effective_ledger_time_consumed
= consumed
- thread
->t_deduct_bank_ledger_time
;
1367 thread
->t_deduct_bank_ledger_time
= consumed
;
1369 thread
->t_bankledger
= new_ledger
;
1371 thread_unlock(thread
);
1374 if (old_ledger
!= NULL
)
1375 ledger_credit(old_ledger
,
1376 bank_ledgers
.cpu_time
,
1377 effective_ledger_time_consumed
);