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