]> git.saurik.com Git - apple/xnu.git/blob - osfmk/bank/bank.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / osfmk / bank / bank.c
1 /*
2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <bank/bank_internal.h>
30 #include <bank/bank_types.h>
31 #include <mach/mach_types.h>
32 #include <mach/kern_return.h>
33 #include <ipc/ipc_port.h>
34 #include <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>
45
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)
49
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)))
52
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)))
57
58 ipc_voucher_attr_control_t bank_voucher_attr_control; /* communication channel from ATM to voucher system */
59
60 #if DEVELOPMENT || DEBUG
61 queue_head_t bank_tasks_list;
62 queue_head_t bank_accounts_list;
63 #endif
64
65 static ledger_template_t bank_ledger_template = NULL;
66 struct _bank_ledger_indices bank_ledgers = { -1 };
67
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);
77
78 static lck_spin_t g_bank_task_lock_data; /* lock to protect task->bank_context transition */
79
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)
90
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);
100
101
102 kern_return_t
103 bank_release_value(
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);
108
109 kern_return_t
110 bank_get_value(
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);
121
122 kern_return_t
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);
131
132 kern_return_t
133 bank_command(
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);
143
144 void
145 bank_release(ipc_voucher_attr_manager_t __assert_only manager);
146
147 /*
148 * communication channel from voucher system to ATM
149 */
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),
157 };
158
159
160 #if DEVELOPMENT || DEBUG
161 decl_lck_mtx_data(, bank_tasks_list_lock);
162 decl_lck_mtx_data(, bank_accounts_list_lock);
163
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;
167 #endif
168
169 /*
170 * Lock group attributes for bank sub system.
171 */
172 lck_grp_t bank_lock_grp;
173 lck_attr_t bank_lock_attr;
174 lck_grp_attr_t bank_lock_grp_attr;
175
176 /*
177 * Routine: bank_init
178 * Purpose: Initialize the BANK subsystem.
179 * Returns: None.
180 */
181 void
182 bank_init()
183 {
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),
189 "bank_task");
190
191 bank_account_zone = zinit(sizeof(struct bank_account),
192 MAX_BANK_ACCOUNT * sizeof(struct bank_account),
193 sizeof(struct bank_account),
194 "bank_account");
195
196 init_bank_ledgers();
197
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();
203
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);
209
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);
212
213 queue_init(&bank_tasks_list);
214 queue_init(&bank_accounts_list);
215 #endif
216
217 /* Register the bank manager with the Vouchers sub system. */
218 kr = ipc_register_well_known_mach_voucher_attr_manager(
219 &bank_manager,
220 0,
221 MACH_VOUCHER_ATTR_KEY_BANK,
222 &bank_voucher_attr_control);
223 if (kr != KERN_SUCCESS )
224 panic("BANK subsystem initialization failed");
225
226 kprintf("BANK subsystem is initialized\n");
227 return ;
228 }
229
230
231 /*
232 * BANK Resource Manager Routines.
233 */
234
235
236 /*
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.
241 */
242 kern_return_t
243 bank_release_value(
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)
248 {
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;
253
254 assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
255 assert(manager == &bank_manager);
256
257
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);
261
262 if (bank_element == BANK_DEFAULT_VALUE || bank_element == BANK_DEFAULT_TASK_VALUE) {
263 /* Return success for default and default task value */
264 return KERN_SUCCESS;
265 }
266
267
268 if (bank_element->be_type == BANK_TASK) {
269 bank_task = CAST_TO_BANK_TASK(bank_element);
270
271 if (bank_task->bt_made != (int)sync) {
272 return KERN_FAILURE;
273 }
274
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);
280 } else {
281 panic("Bogus bank type: %d passed in get_value\n", bank_element->be_type);
282 }
283
284 return kr;
285 }
286
287
288 /*
289 * Routine: bank_get_value
290 */
291 kern_return_t
292 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)
303 {
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;
313 task_t task;
314 kern_return_t kr = KERN_SUCCESS;
315 mach_msg_type_number_t i;
316
317 assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
318 assert(manager == &bank_manager);
319
320 /* never an out voucher */
321 *out_value_voucher = IPC_VOUCHER_NULL;
322 *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
323
324 switch (command) {
325
326 case MACH_VOUCHER_ATTR_BANK_CREATE:
327
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;
331 break;
332
333 case MACH_VOUCHER_ATTR_AUTO_REDEEM:
334
335 for (i = 0; i < prev_value_count; i++) {
336 bank_handle = prev_values[i];
337 bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
338
339 /* Should not have received default task value from an IPC */
340 if (bank_element == BANK_DEFAULT_VALUE || bank_element == BANK_DEFAULT_TASK_VALUE)
341 continue;
342
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;
353 } else {
354 panic("Bogus bank type: %d passed in get_value\n", bank_element->be_type);
355 }
356
357 bank_merchant = get_bank_task_context(task, FALSE);
358 if (bank_merchant == BANK_TASK_NULL)
359 return KERN_RESOURCE_SHORTAGE;
360
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;
367 return kr;
368 }
369
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;
374
375 *out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
376 return kr;
377 }
378
379 *out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
380 break;
381
382 case MACH_VOUCHER_ATTR_SEND_PREPROCESS:
383
384 for (i = 0; i < prev_value_count; i++) {
385 bank_handle = prev_values[i];
386 bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
387
388 if (bank_element == BANK_DEFAULT_VALUE)
389 continue;
390
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));
394 }
395
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;
403 } else {
404 panic("Bogus bank type: %d passed in get_value\n", bank_element->be_type);
405 }
406
407 bank_merchant = get_bank_task_context(task, FALSE);
408 if (bank_merchant == BANK_TASK_NULL)
409 return KERN_RESOURCE_SHORTAGE;
410
411 /*
412 * If the process doesn't have secure persona entitlement,
413 * then replace the secure originator to current task.
414 */
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;
420 }
421
422 bank_proximateprocess = bank_merchant;
423
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);
431 return kr;
432 }
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;
437
438 *out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
439 return kr;
440 }
441
442 *out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
443 break;
444
445 case MACH_VOUCHER_ATTR_REDEEM:
446
447 for (i = 0; i < prev_value_count; i++) {
448 bank_handle = prev_values[i];
449 bank_element = HANDLE_TO_BANK_ELEMENT(bank_handle);
450
451 if (bank_element == BANK_DEFAULT_VALUE)
452 continue;
453
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;
458 return kr;
459 }
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);
464 }
465
466 bank_task_reference(bank_task);
467 bank_task_made_reference(bank_task);
468 *out_value = BANK_ELEMENT_TO_HANDLE(bank_task);
469 return kr;
470
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);
476 }
477
478 bank_account_reference(bank_account);
479 bank_account_made_reference(bank_account);
480 *out_value = BANK_ELEMENT_TO_HANDLE(bank_account);
481 return kr;
482 } else {
483 panic("Bogus bank type: %d passed in get_value\n", bank_element->be_type);
484 }
485 }
486
487 *out_value = BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE);
488 break;
489
490 default:
491 kr = KERN_INVALID_ARGUMENT;
492 break;
493 }
494
495 return kr;
496 }
497
498
499 /*
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.
505 */
506 kern_return_t
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)
515 {
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;
522
523 assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
524 assert(manager == &bank_manager);
525
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)
530 continue;
531
532 if (bank_element == BANK_DEFAULT_TASK_VALUE) {
533 bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
534 }
535
536 if (MACH_VOUCHER_BANK_CONTENT_SIZE > *in_out_recipe_size) {
537 *in_out_recipe_size = 0;
538 return KERN_NO_SPACE;
539 }
540
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);
555 } else {
556 panic("Bogus bank type: %d passed in get_value\n", bank_element->be_type);
557 }
558
559
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;
563 return KERN_SUCCESS;
564 }
565
566 return KERN_SUCCESS;
567 }
568
569 /*
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.
574 */
575 kern_return_t
576 bank_command(
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)
586 {
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;
595 int32_t pid;
596
597 assert(MACH_VOUCHER_ATTR_KEY_BANK == key);
598 assert(manager == &bank_manager);
599
600 switch (command) {
601 case BANK_ORIGINATOR_PID:
602
603 if ((sizeof(pid)) > *out_content_size) {
604 *out_content_size = 0;
605 return KERN_NO_SPACE;
606 }
607
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)
612 continue;
613
614 if (bank_element == BANK_DEFAULT_TASK_VALUE) {
615 bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
616 }
617
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;
623 } else {
624 panic("Bogus bank type: %d passed in voucher_command\n", bank_element->be_type);
625 }
626 pid = bank_task->bt_pid;
627
628 memcpy(&out_content[0], &pid, sizeof(pid));
629 *out_content_size = (mach_voucher_attr_content_size_t)sizeof(pid);
630 return KERN_SUCCESS;
631 }
632 /* In the case of no value, return error KERN_INVALID_VALUE */
633 *out_content_size = 0;
634 return KERN_INVALID_VALUE;
635
636 break;
637
638 case BANK_PERSONA_TOKEN:
639
640 if ((sizeof(struct persona_token)) > *out_content_size) {
641 *out_content_size = 0;
642 return KERN_NO_SPACE;
643 }
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)
648 continue;
649
650 if (bank_element == BANK_DEFAULT_TASK_VALUE) {
651 bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
652 }
653
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;
661 } else {
662 panic("Bogus bank type: %d passed in voucher_command\n", bank_element->be_type);
663 }
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));
667
668 *out_content_size = (mach_voucher_attr_content_size_t)sizeof(*token);
669 return KERN_SUCCESS;
670 }
671 /* In the case of no value, return error KERN_INVALID_VALUE */
672 *out_content_size = 0;
673 return KERN_INVALID_VALUE;
674
675 break;
676
677 default:
678 return KERN_INVALID_ARGUMENT;
679 }
680 return KERN_SUCCESS;
681 }
682
683
684 void
685 bank_release(
686 ipc_voucher_attr_manager_t __assert_only manager)
687 {
688 assert(manager == &bank_manager);
689 }
690
691
692
693 /*
694 * Bank Internal Routines.
695 */
696
697 /*
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.
704 */
705 static bank_task_t
706 bank_task_alloc_init(task_t task)
707 {
708 bank_task_t new_bank_task;
709
710 new_bank_task = (bank_task_t) zalloc(bank_task_zone);
711 if (new_bank_task == BANK_TASK_NULL)
712 return BANK_TASK_NULL;
713
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);
723
724 /*
725 * Initialize the persona_id struct
726 */
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));
736
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);
742 #endif
743 return (new_bank_task);
744 }
745
746 /*
747 * Routine: proc_is_propagate_entitled
748 * Purpose: Check if the process has persona propagate entitlement.
749 * Returns: TRUE if entitled.
750 * FALSE if not.
751 */
752 static boolean_t
753 bank_task_is_propagate_entitled(task_t t)
754 {
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);
760 return entitled;
761 } else {
762 return TRUE;
763 }
764 }
765
766 /*
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.
771 */
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)
778 {
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);
783
784 if (new_ledger == NULL)
785 return BANK_ACCOUNT_NULL;
786
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;
792 }
793
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;
802
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)
809 continue;
810
811 entry_found = TRUE;
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);
815 break;
816 }
817
818 if (!entry_found) {
819
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);
822
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);
825
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);
828
829 lck_mtx_unlock(&bank_merchant->bt_acc_to_charge_lock);
830 }
831
832 lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
833
834 if (entry_found) {
835 ledger_dereference(new_ledger);
836 zfree(bank_account_zone, new_bank_account);
837 return bank_account;
838 }
839
840 bank_task_reference(bank_holder);
841 bank_task_reference(bank_merchant);
842 bank_task_reference(bank_secureoriginator);
843 bank_task_reference(bank_proximateprocess);
844
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);
850 #endif
851
852 return (new_bank_account);
853 }
854
855 /*
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.
861 */
862 static bank_task_t
863 get_bank_task_context
864 (task_t task,
865 boolean_t initialize)
866 {
867 bank_task_t bank_task;
868
869 if (task->bank_context || !initialize) {
870 assert(task->bank_context != NULL);
871 return (task->bank_context);
872 }
873
874 bank_task = bank_task_alloc_init(task);
875
876 /* Grab the task lock and check if we won the race. */
877 task_lock(task);
878 if (task->bank_context) {
879 task_unlock(task);
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) {
884 task_unlock(task);
885 return BANK_TASK_NULL;
886 }
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;
891 #endif
892 ledger_reference(task->ledger);
893
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();
898
899 task_unlock(task);
900
901 return (bank_task);
902 }
903
904 /*
905 * Routine: bank_task_dealloc
906 * Purpose: Drops the reference on bank task.
907 * Returns: None.
908 */
909 static void
910 bank_task_dealloc(
911 bank_task_t bank_task,
912 mach_voucher_attr_value_reference_t sync)
913 {
914 assert(bank_task->bt_refs >= 0);
915
916 if (bank_task_release_num(bank_task, sync) > (int)sync)
917 return;
918
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));
922
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);
926
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);
931 #endif
932
933 zfree(bank_task_zone, bank_task);
934 }
935
936 /*
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.
941 */
942 static kern_return_t
943 bank_account_dealloc_with_sync(
944 bank_account_t bank_account,
945 mach_voucher_attr_value_reference_t sync)
946 {
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;
951
952 /* Grab the acc to pay list lock and check the sync value */
953 lck_mtx_lock(&bank_holder->bt_acc_to_pay_lock);
954
955 if (bank_account->ba_made != (int)sync) {
956 lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
957 return KERN_FAILURE;
958 }
959
960 bank_account_made_release_num(bank_account, sync);
961
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);
964
965
966 /* Grab both the acc to pay and acc to charge locks */
967 lck_mtx_lock(&bank_merchant->bt_acc_to_charge_lock);
968
969 bank_rollup_chit_to_tasks(bank_account->ba_bill, bank_holder, bank_merchant);
970
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);
973
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);
976
977 lck_mtx_unlock(&bank_merchant->bt_acc_to_charge_lock);
978 lck_mtx_unlock(&bank_holder->bt_acc_to_pay_lock);
979
980 ledger_dereference(bank_account->ba_bill);
981
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);
987
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);
992 #endif
993
994 zfree(bank_account_zone, bank_account);
995 return KERN_SUCCESS;
996 }
997
998 /*
999 * Routine: bank_rollup_chit_to_tasks
1000 * Purpose: Debit and Credit holder's and merchant's ledgers.
1001 * Returns: None.
1002 */
1003 static void
1004 bank_rollup_chit_to_tasks(
1005 ledger_t bill,
1006 bank_task_t bank_holder,
1007 bank_task_t bank_merchant)
1008 {
1009 ledger_amount_t credit;
1010 ledger_amount_t debit;
1011 kern_return_t ret;
1012
1013 if (bank_holder == bank_merchant)
1014 return;
1015
1016 ret = ledger_get_entries(bill, bank_ledgers.cpu_time, &credit, &debit);
1017 if (ret != KERN_SUCCESS) {
1018 return;
1019 }
1020
1021 #if DEVELOPMENT || DEBUG
1022 if (debit != 0) {
1023 panic("bank_rollup: debit: %lld non zero\n", debit);
1024 }
1025 #endif
1026
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);
1029 #if CONFIG_BANK
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);
1032
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);
1035 #endif
1036 }
1037
1038
1039
1040 /*
1041 * Routine: bank_task_destroy
1042 * Purpose: Drops reference on bank task.
1043 * Returns: None.
1044 */
1045 void
1046 bank_task_destroy(task_t task)
1047 {
1048 bank_task_t bank_task;
1049
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();
1055
1056 bank_task_dealloc(bank_task, 1);
1057 }
1058
1059 /*
1060 * Routine: bank_task_initialize
1061 * Purpose: Initialize the bank context of a task.
1062 * Returns: None.
1063 */
1064 void
1065 bank_task_initialize(task_t task)
1066 {
1067 get_bank_task_context(task, TRUE);
1068 }
1069
1070 /*
1071 * Routine: init_bank_ledgers
1072 * Purpose: Initialize template for bank ledgers.
1073 * Returns: None.
1074 */
1075 static void
1076 init_bank_ledgers(void) {
1077 ledger_template_t t;
1078 int idx;
1079
1080 assert(bank_ledger_template == NULL);
1081
1082 if ((t = ledger_template_create("Bank ledger")) == NULL)
1083 panic("couldn't create bank ledger template");
1084
1085 if ((idx = ledger_entry_add(t, "cpu_time", "sched", "ns")) < 0) {
1086 panic("couldn't create cpu_time entry for bank ledger template");
1087 }
1088
1089 bank_ledgers.cpu_time = idx;
1090 bank_ledger_template = t;
1091 }
1092
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.
1097 * Returns: balance.
1098 */
1099 uint64_t
1100 bank_billed_time_safe(task_t task)
1101 {
1102 bank_task_t bank_task = BANK_TASK_NULL;
1103 ledger_amount_t credit, debit;
1104 uint64_t balance = 0;
1105 kern_return_t kr;
1106
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);
1113 }
1114 global_bank_task_unlock();
1115
1116 if (bank_task) {
1117 balance = bank_billed_time(bank_task);
1118 bank_task_dealloc(bank_task, 1);
1119 } else {
1120 kr = ledger_get_entries(task->ledger, task_ledgers.cpu_time_billed_to_me,
1121 &credit, &debit);
1122 if (kr == KERN_SUCCESS) {
1123 balance = credit - debit;
1124 }
1125 }
1126
1127 return balance;
1128 }
1129
1130 /*
1131 * Routine: bank_billed_time
1132 * Purpose: Walk through the Accounts need to pay account list and get the current billing balance.
1133 * Returns: balance.
1134 */
1135 uint64_t
1136 bank_billed_time(bank_task_t bank_task)
1137 {
1138 int64_t balance = 0;
1139 #ifdef CONFIG_BANK
1140 bank_account_t bank_account;
1141 int64_t temp = 0;
1142 kern_return_t kr;
1143 #endif
1144 if (bank_task == BANK_TASK_NULL) {
1145 return balance;
1146 }
1147
1148 #ifdef CONFIG_BANK
1149 lck_mtx_lock(&bank_task->bt_acc_to_pay_lock);
1150
1151 kr = ledger_get_balance(bank_task->bt_creditcard, task_ledgers.cpu_time_billed_to_me, &temp);
1152 if (kr == KERN_SUCCESS && temp >= 0) {
1153 balance += temp;
1154 }
1155 #if DEVELOPMENT || DEBUG
1156 else {
1157 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1158 }
1159 #endif /* DEVELOPMENT || DEBUG */
1160
1161 queue_iterate(&bank_task->bt_accounts_to_pay, bank_account, bank_account_t, ba_next_acc_to_pay) {
1162 temp = 0;
1163 kr = ledger_get_balance(bank_account->ba_bill, bank_ledgers.cpu_time, &temp);
1164 if (kr == KERN_SUCCESS && temp >= 0) {
1165 balance += temp;
1166 }
1167 #if DEVELOPMENT || DEBUG
1168 else {
1169 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1170 }
1171 #endif /* DEVELOPMENT || DEBUG */
1172 }
1173 lck_mtx_unlock(&bank_task->bt_acc_to_pay_lock);
1174 #endif
1175 return (uint64_t)balance;
1176 }
1177
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.
1182 * Returns: balance.
1183 */
1184 uint64_t
1185 bank_serviced_time_safe(task_t task)
1186 {
1187 bank_task_t bank_task = BANK_TASK_NULL;
1188 ledger_amount_t credit, debit;
1189 uint64_t balance = 0;
1190 kern_return_t kr;
1191
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);
1198 }
1199 global_bank_task_unlock();
1200
1201 if (bank_task) {
1202 balance = bank_serviced_time(bank_task);
1203 bank_task_dealloc(bank_task, 1);
1204 } else {
1205 kr = ledger_get_entries(task->ledger, task_ledgers.cpu_time_billed_to_others,
1206 &credit, &debit);
1207 if (kr == KERN_SUCCESS) {
1208 balance = credit - debit;
1209 }
1210 }
1211
1212 return balance;
1213 }
1214
1215 /*
1216 * Routine: bank_serviced_time
1217 * Purpose: Walk through the Account need to charge account list and get the current balance to be charged.
1218 * Returns: balance.
1219 */
1220 uint64_t
1221 bank_serviced_time(bank_task_t bank_task)
1222 {
1223 int64_t balance = 0;
1224 #ifdef CONFIG_BANK
1225 bank_account_t bank_account;
1226 int64_t temp = 0;
1227 kern_return_t kr;
1228 #endif
1229 if (bank_task == BANK_TASK_NULL) {
1230 return balance;
1231 }
1232
1233 #ifdef CONFIG_BANK
1234 lck_mtx_lock(&bank_task->bt_acc_to_charge_lock);
1235
1236 kr = ledger_get_balance(bank_task->bt_creditcard, task_ledgers.cpu_time_billed_to_others, &temp);
1237 if (kr == KERN_SUCCESS && temp >= 0) {
1238 balance += temp;
1239 }
1240 #if DEVELOPMENT || DEBUG
1241 else {
1242 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1243 }
1244 #endif /* DEVELOPMENT || DEBUG */
1245
1246 queue_iterate(&bank_task->bt_accounts_to_charge, bank_account, bank_account_t, ba_next_acc_to_charge) {
1247 temp = 0;
1248 kr = ledger_get_balance(bank_account->ba_bill, bank_ledgers.cpu_time, &temp);
1249 if (kr == KERN_SUCCESS && temp >= 0) {
1250 balance += temp;
1251 }
1252 #if DEVELOPMENT || DEBUG
1253 else {
1254 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp);
1255 }
1256 #endif /* DEVELOPMENT || DEBUG */
1257 }
1258 lck_mtx_unlock(&bank_task->bt_acc_to_charge_lock);
1259 #endif
1260 return (uint64_t)balance;
1261 }
1262
1263 /*
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.
1268 */
1269 ledger_t
1270 bank_get_voucher_ledger(ipc_voucher_t voucher)
1271 {
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;
1278 kern_return_t kr;
1279
1280 val_count = MACH_VOUCHER_ATTR_VALUE_MAX_NESTED;
1281 kr = mach_voucher_attr_control_get_values(bank_voucher_attr_control,
1282 voucher,
1283 vals,
1284 &val_count);
1285
1286 if (kr != KERN_SUCCESS)
1287 return NULL;
1288
1289 if (val_count == 0)
1290 return NULL;
1291
1292 bank_element = HANDLE_TO_BANK_ELEMENT(vals[0]);
1293 if (bank_element == BANK_DEFAULT_VALUE)
1294 return NULL;
1295
1296 if (bank_element == BANK_DEFAULT_TASK_VALUE) {
1297 bank_element = CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE));
1298 }
1299
1300 if (bank_element->be_type == BANK_TASK) {
1301 bankledger = NULL;
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;
1309 }
1310 }
1311 } else {
1312 panic("Bogus bank type: %d passed in bank_get_voucher_ledger\n", bank_element->be_type);
1313 }
1314
1315 return (bankledger);
1316 }
1317
1318 /*
1319 * Routine: bank_swap_thread_bank_ledger
1320 * Purpose: swap the bank ledger on the thread.
1321 * Retunrs: None.
1322 * Note: Should be only called for current thread or thread which is not started.
1323 */
1324 void
1325 bank_swap_thread_bank_ledger(thread_t thread __unused, ledger_t new_ledger __unused)
1326 {
1327 #ifdef CONFIG_BANK
1328 spl_t s;
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;
1333
1334 if (old_ledger == NULL && new_ledger == NULL)
1335 return;
1336
1337 assert((thread == current_thread() || thread->started == 0));
1338
1339 s = splsched();
1340 thread_lock(thread);
1341
1342 /*
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.
1345 *
1346 * thread ledger
1347 * cpu_time
1348 * |<- consumed ->|<- remainder ->|
1349 * timeline ----------------------------------------------------------------->
1350 * | | |
1351 * thread_dispatch ctime quantum end
1352 *
1353 * |<-effective_ledger_time -> |
1354 * deduct_bank_ledger_time
1355 */
1356
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;
1362
1363 consumed = thread->quantum_remaining - remainder;
1364 effective_ledger_time_consumed = consumed - thread->t_deduct_bank_ledger_time;
1365 }
1366
1367 thread->t_deduct_bank_ledger_time = consumed;
1368
1369 thread->t_bankledger = new_ledger;
1370
1371 thread_unlock(thread);
1372 splx(s);
1373
1374 if (old_ledger != NULL)
1375 ledger_credit(old_ledger,
1376 bank_ledgers.cpu_time,
1377 effective_ledger_time_consumed);
1378 #endif
1379 }
1380