X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/osfmk/ipc/ipc_voucher.c diff --git a/osfmk/ipc/ipc_voucher.c b/osfmk/ipc/ipc_voucher.c index 36e77dfd5..4a753c737 100644 --- a/osfmk/ipc/ipc_voucher.c +++ b/osfmk/ipc/ipc_voucher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Apple Inc. All rights reserved. + * Copyright (c) 2013-2020 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -42,14 +43,23 @@ #include #include #include +#include /* * Sysctl variable; enable and disable tracing of voucher contents */ uint32_t ipc_voucher_trace_contents = 0; -static zone_t ipc_voucher_zone; -static zone_t ipc_voucher_attr_control_zone; +static SECURITY_READ_ONLY_LATE(zone_t) ipc_voucher_zone; +static ZONE_DECLARE(ipc_voucher_attr_control_zone, "ipc voucher attr controls", + sizeof(struct ipc_voucher_attr_control), ZC_NOENCRYPT | ZC_ZFREE_CLEARMEM); + +ZONE_INIT(&ipc_voucher_zone, "ipc vouchers", sizeof(struct ipc_voucher), + ZC_NOENCRYPT | ZC_ZFREE_CLEARMEM | ZC_NOSEQUESTER, + ZONE_ID_IPC_VOUCHERS, NULL); + +#define voucher_require(v) \ + zone_id_require(ZONE_ID_IPC_VOUCHERS, sizeof(struct ipc_voucher), v) /* * Voucher hash table @@ -58,18 +68,16 @@ static zone_t ipc_voucher_attr_control_zone; #define IV_HASH_BUCKET(x) ((x) % IV_HASH_BUCKETS) static queue_head_t ivht_bucket[IV_HASH_BUCKETS]; -static lck_spin_t ivht_lock_data; +static LCK_SPIN_DECLARE_ATTR(ivht_lock_data, &ipc_lck_grp, &ipc_lck_attr); static uint32_t ivht_count = 0; -#define ivht_lock_init() \ - lck_spin_init(&ivht_lock_data, &ipc_lck_grp, &ipc_lck_attr) #define ivht_lock_destroy() \ lck_spin_destroy(&ivht_lock_data, &ipc_lck_grp) -#define ivht_lock() \ - lck_spin_lock(&ivht_lock_data) -#define ivht_lock_try() \ - lck_spin_try_lock(&ivht_lock_data) -#define ivht_unlock() \ +#define ivht_lock() \ + lck_spin_lock_grp(&ivht_lock_data, &ipc_lck_grp) +#define ivht_lock_try() \ + lck_spin_try_lock_grp(&ivht_lock_data, &ipc_lck_grp) +#define ivht_unlock() \ lck_spin_unlock(&ivht_lock_data) /* @@ -81,40 +89,35 @@ static uint32_t ivht_count = 0; */ static iv_index_t ivgt_keys_in_use = MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN; static ipc_voucher_global_table_element iv_global_table[MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN]; -static lck_spin_t ivgt_lock_data; +static LCK_SPIN_DECLARE_ATTR(ivgt_lock_data, &ipc_lck_grp, &ipc_lck_attr); -#define ivgt_lock_init() \ - lck_spin_init(&ivgt_lock_data, &ipc_lck_grp, &ipc_lck_attr) #define ivgt_lock_destroy() \ lck_spin_destroy(&ivgt_lock_data, &ipc_lck_grp) -#define ivgt_lock() \ - lck_spin_lock(&ivgt_lock_data) -#define ivgt_lock_try() \ - lck_spin_try_lock(&ivgt_lock_data) -#define ivgt_unlock() \ +#define ivgt_lock() \ + lck_spin_lock_grp(&ivgt_lock_data, &ipc_lck_grp) +#define ivgt_lock_try() \ + lck_spin_try_lock_grp(&ivgt_lock_data, &ipc_lck_grp) +#define ivgt_unlock() \ lck_spin_unlock(&ivgt_lock_data) ipc_voucher_t iv_alloc(iv_index_t entries); void iv_dealloc(ipc_voucher_t iv, boolean_t unhash); -static inline iv_refs_t +os_refgrp_decl(static, iv_refgrp, "voucher", NULL); +os_refgrp_decl(static, ivac_refgrp, "voucher attribute control", NULL); + +static inline void iv_reference(ipc_voucher_t iv) { - iv_refs_t refs; - - refs = hw_atomic_add(&iv->iv_refs, 1); - return refs; + os_ref_retain(&iv->iv_refs); } static inline void iv_release(ipc_voucher_t iv) { - iv_refs_t refs; - - assert(0 < iv->iv_refs); - refs = hw_atomic_sub(&iv->iv_refs, 1); - if (0 == refs) + if (os_ref_release(&iv->iv_refs) == 0) { iv_dealloc(iv, TRUE); + } } /* @@ -156,69 +159,53 @@ static inline iv_index_t iv_key_to_index(mach_voucher_attr_key_t key) { if (MACH_VOUCHER_ATTR_KEY_ALL == key || - MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN < key) + MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN < key) { return IV_UNUSED_KEYINDEX; + } return (iv_index_t)key - 1; } static inline mach_voucher_attr_key_t iv_index_to_key(iv_index_t key_index) { - if (MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN > key_index) + if (MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN > key_index) { return iv_global_table[key_index].ivgte_key; + } return MACH_VOUCHER_ATTR_KEY_NONE; - } static void ivace_release(iv_index_t key_index, iv_index_t value_index); -static void ivace_lookup_values(iv_index_t key_index, iv_index_t value_index, - mach_voucher_attr_value_handle_array_t values, - mach_voucher_attr_value_handle_array_size_t *count); +static void ivace_lookup_values(iv_index_t key_index, iv_index_t value_index, + mach_voucher_attr_value_handle_array_t values, + mach_voucher_attr_value_handle_array_size_t *count); static iv_index_t iv_lookup(ipc_voucher_t, iv_index_t); - -static void ivgt_lookup(iv_index_t, - boolean_t, - ipc_voucher_attr_manager_t *, - ipc_voucher_attr_control_t *); +static void ivgt_lookup(iv_index_t, + boolean_t, + ipc_voucher_attr_manager_t *, + ipc_voucher_attr_control_t *); -#if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) || defined(MACH_VOUCHER_ATTR_KEY_TEST) -void user_data_attr_manager_init(void); -#endif +static kern_return_t +ipc_voucher_prepare_processing_recipe( + ipc_voucher_t voucher, + ipc_voucher_attr_raw_recipe_array_t recipes, + ipc_voucher_attr_raw_recipe_array_size_t *in_out_size, + mach_voucher_attr_recipe_command_t command, + ipc_voucher_attr_manager_flags flags, + int *need_processing); -void +__startup_func +static void ipc_voucher_init(void) { - natural_t ipc_voucher_max = (task_max + thread_max) * 2; - natural_t attr_manager_max = MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN; - iv_index_t i; - - ipc_voucher_zone = zinit(sizeof(struct ipc_voucher), - ipc_voucher_max * sizeof(struct ipc_voucher), - sizeof(struct ipc_voucher), - "ipc vouchers"); - zone_change(ipc_voucher_zone, Z_NOENCRYPT, TRUE); - - ipc_voucher_attr_control_zone = zinit(sizeof(struct ipc_voucher_attr_control), - attr_manager_max * sizeof(struct ipc_voucher_attr_control), - sizeof(struct ipc_voucher_attr_control), - "ipc voucher attr controls"); - zone_change(ipc_voucher_attr_control_zone, Z_NOENCRYPT, TRUE); - /* initialize voucher hash */ - ivht_lock_init(); - for (i = 0; i < IV_HASH_BUCKETS; i++) + for (iv_index_t i = 0; i < IV_HASH_BUCKETS; i++) { queue_init(&ivht_bucket[i]); - - /* initialize global table locking */ - ivgt_lock_init(); - -#if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) || defined(MACH_VOUCHER_ATTR_KEY_TEST) - user_data_attr_manager_init(); -#endif + } } +STARTUP(MACH_IPC, STARTUP_RANK_FIRST, ipc_voucher_init); ipc_voucher_t iv_alloc(iv_index_t entries) @@ -228,10 +215,11 @@ iv_alloc(iv_index_t entries) iv = (ipc_voucher_t)zalloc(ipc_voucher_zone); - if (IV_NULL == iv) + if (IV_NULL == iv) { return IV_NULL; - - iv->iv_refs = 1; + } + + os_ref_init(&iv->iv_refs, &iv_refgrp); iv->iv_sum = 0; iv->iv_hash = 0; iv->iv_port = IP_NULL; @@ -253,10 +241,11 @@ iv_alloc(iv_index_t entries) } /* initialize the table entries */ - for (i=0; i < iv->iv_table_size; i++) + for (i = 0; i < iv->iv_table_size; i++) { iv->iv_table[i] = IV_UNUSED_VALINDEX; - - return (iv); + } + + return iv; } /* @@ -268,9 +257,9 @@ iv_alloc(iv_index_t entries) * they are immutable once references are distributed. */ static void -iv_set(ipc_voucher_t iv, - iv_index_t key_index, - iv_index_t value_index) +iv_set(ipc_voucher_t iv, + iv_index_t key_index, + iv_index_t value_index) { assert(key_index < iv->iv_table_size); iv->iv_table[key_index] = value_index; @@ -287,17 +276,18 @@ iv_dealloc(ipc_voucher_t iv, boolean_t unhash) */ if (unhash) { ivht_lock(); - assert(0 == iv->iv_refs); + assert(os_ref_get_count(&iv->iv_refs) == 0); assert(IV_HASH_BUCKETS > iv->iv_hash); queue_remove(&ivht_bucket[iv->iv_hash], iv, ipc_voucher_t, iv_hash_link); ivht_count--; ivht_unlock(); - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_VOUCHER_DESTROY) | DBG_FUNC_NONE, - VM_KERNEL_ADDRPERM((uintptr_t)iv), 0, ivht_count, 0, 0); - - } else - assert(0 == --iv->iv_refs); + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_VOUCHER_DESTROY) | DBG_FUNC_NONE, + VM_KERNEL_ADDRPERM((uintptr_t)iv), 0, ivht_count, 0, 0); + } else { + os_ref_count_t cnt __assert_only = os_ref_release(&iv->iv_refs); + assert(cnt == 0); + } /* * if a port was allocated for this voucher, @@ -306,7 +296,7 @@ iv_dealloc(ipc_voucher_t iv, boolean_t unhash) * is gone. We can just discard it now. */ if (IP_VALID(port)) { - assert(ip_active(port)); + require_ip_active(port); assert(port->ip_srights == 0); ipc_port_dealloc_kernel(port); @@ -319,10 +309,11 @@ iv_dealloc(ipc_voucher_t iv, boolean_t unhash) iv_set(iv, i, ~0); #endif } - - if (iv->iv_table != iv->iv_inline_table) - kfree(iv->iv_table, - iv->iv_table_size * sizeof(*iv->iv_table)); + + if (iv->iv_table != iv->iv_inline_table) { + kfree(iv->iv_table, + iv->iv_table_size * sizeof(*iv->iv_table)); + } zfree(ipc_voucher_zone, iv); } @@ -338,8 +329,9 @@ iv_dealloc(ipc_voucher_t iv, boolean_t unhash) static inline iv_index_t iv_lookup(ipc_voucher_t iv, iv_index_t key_index) { - if (key_index < iv->iv_table_size) + if (key_index < iv->iv_table_size) { return iv->iv_table[key_index]; + } return IV_UNUSED_VALINDEX; } @@ -358,22 +350,35 @@ iv_lookup(ipc_voucher_t iv, iv_index_t key_index) */ uintptr_t unsafe_convert_port_to_voucher( - ipc_port_t port) + ipc_port_t port) { if (IP_VALID(port)) { - uintptr_t voucher = (uintptr_t) port->ip_kobject; + /* vouchers never labeled (they get transformed before use) */ + if (ip_is_kolabeled(port)) { + return (uintptr_t)IV_NULL; + } /* * No need to lock because we have a reference on the * port, and if it is a true voucher port, that reference * keeps the voucher bound to the port (and active). */ - if (ip_kotype(port) == IKOT_VOUCHER) - return (voucher); + if (ip_kotype(port) == IKOT_VOUCHER) { + return (uintptr_t)port->ip_kobject; + } } return (uintptr_t)IV_NULL; } +static ipc_voucher_t +ip_get_voucher(ipc_port_t port) +{ + ipc_voucher_t voucher = (ipc_voucher_t)ip_get_kobject(port); + require_ip_active(port); + voucher_require(voucher); + return voucher; +} + /* * Routine: convert_port_to_voucher * Purpose: @@ -386,23 +391,17 @@ unsafe_convert_port_to_voucher( */ ipc_voucher_t convert_port_to_voucher( - ipc_port_t port) + ipc_port_t port) { - if (IP_VALID(port)) { - ipc_voucher_t voucher = (ipc_voucher_t) port->ip_kobject; - + if (IP_VALID(port) && ip_kotype(port) == IKOT_VOUCHER) { /* * No need to lock because we have a reference on the * port, and if it is a true voucher port, that reference * keeps the voucher bound to the port (and active). */ - if (ip_kotype(port) != IKOT_VOUCHER) - return IV_NULL; - - assert(ip_active(port)); - + ipc_voucher_t voucher = ip_get_voucher(port); ipc_voucher_reference(voucher); - return (voucher); + return voucher; } return IV_NULL; } @@ -418,7 +417,7 @@ convert_port_to_voucher( ipc_voucher_t convert_port_name_to_voucher( - mach_port_name_t voucher_name) + mach_port_name_t voucher_name) { ipc_voucher_t iv; kern_return_t kr; @@ -426,8 +425,9 @@ convert_port_name_to_voucher( if (MACH_PORT_VALID(voucher_name)) { kr = ipc_port_translate_send(current_space(), voucher_name, &port); - if (KERN_SUCCESS != kr) + if (KERN_SUCCESS != kr) { return IV_NULL; + } iv = convert_port_to_voucher(port); ip_unlock(port); @@ -440,20 +440,19 @@ convert_port_name_to_voucher( void ipc_voucher_reference(ipc_voucher_t voucher) { - iv_refs_t refs; - - if (IPC_VOUCHER_NULL == voucher) + if (IPC_VOUCHER_NULL == voucher) { return; + } - refs = iv_reference(voucher); - assert(1 < refs); + iv_reference(voucher); } void ipc_voucher_release(ipc_voucher_t voucher) { - if (IPC_VOUCHER_NULL != voucher) + if (IPC_VOUCHER_NULL != voucher) { iv_release(voucher); + } } /* @@ -461,26 +460,18 @@ ipc_voucher_release(ipc_voucher_t voucher) * Purpose: * Called whenever the Mach port system detects no-senders * on the voucher port. - * - * Each time the send-right count goes positive, a no-senders - * notification is armed (and a voucher reference is donated). - * So, each notification that comes in must release a voucher - * reference. If more send rights have been added since it - * fired (asynchronously), they will be protected by a different - * reference hold. */ void ipc_voucher_notify(mach_msg_header_t *msg) { mach_no_senders_notification_t *notification = (void *)msg; ipc_port_t port = notification->not_header.msgh_remote_port; - ipc_voucher_t iv; + ipc_voucher_t voucher = ip_get_voucher(port); - assert(ip_active(port)); assert(IKOT_VOUCHER == ip_kotype(port)); - iv = (ipc_voucher_t)port->ip_kobject; - ipc_voucher_release(iv); + /* consume the reference donated by convert_voucher_to_port */ + ipc_voucher_release(voucher); } /* @@ -489,52 +480,28 @@ ipc_voucher_notify(mach_msg_header_t *msg) ipc_port_t convert_voucher_to_port(ipc_voucher_t voucher) { - ipc_port_t port, send; - - if (IV_NULL == voucher) - return (IP_NULL); - - assert(0 < voucher->iv_refs); - - /* create a port if needed */ - port = voucher->iv_port; - if (!IP_VALID(port)) { - port = ipc_port_alloc_kernel(); - assert(IP_VALID(port)); - ipc_kobject_set_atomically(port, (ipc_kobject_t) voucher, IKOT_VOUCHER); - - /* If we lose the race, deallocate and pick up the other guy's port */ - if (!OSCompareAndSwapPtr(IP_NULL, port, &voucher->iv_port)) { - ipc_port_dealloc_kernel(port); - port = voucher->iv_port; - assert(ip_kotype(port) == IKOT_VOUCHER); - assert(port->ip_kobject == (ipc_kobject_t)voucher); - } + if (IV_NULL == voucher) { + return IP_NULL; } - - ip_lock(port); - assert(ip_active(port)); - send = ipc_port_make_send_locked(port); - if (1 == port->ip_srights) { - ipc_port_t old_notify; + voucher_require(voucher); + assert(os_ref_get_count(&voucher->iv_refs) > 0); - /* transfer our ref to the port, and arm the no-senders notification */ - assert(IP_NULL == port->ip_nsrequest); - ipc_port_nsrequest(port, port->ip_mscount, ipc_port_make_sonce_locked(port), &old_notify); - /* port unlocked */ - assert(IP_NULL == old_notify); - } else { - /* piggyback on the existing port reference, so consume ours */ - ip_unlock(port); + /* + * make a send right and donate our reference for ipc_voucher_notify + * if this is the first send right + */ + if (!ipc_kobject_make_send_lazy_alloc_port(&voucher->iv_port, + (ipc_kobject_t)voucher, IKOT_VOUCHER, false, 0)) { ipc_voucher_release(voucher); } - return (send); + return voucher->iv_port; } #define ivace_reset_data(ivace_elem, next_index) { \ (ivace_elem)->ivace_value = 0xDEADC0DEDEADC0DE; \ (ivace_elem)->ivace_refs = 0; \ + (ivace_elem)->ivace_persist = 0; \ (ivace_elem)->ivace_made = 0; \ (ivace_elem)->ivace_free = TRUE; \ (ivace_elem)->ivace_releasing = FALSE; \ @@ -546,6 +513,7 @@ convert_voucher_to_port(ipc_voucher_t voucher) #define ivace_copy_data(ivace_src_elem, ivace_dst_elem) { \ (ivace_dst_elem)->ivace_value = (ivace_src_elem)->ivace_value; \ (ivace_dst_elem)->ivace_refs = (ivace_src_elem)->ivace_refs; \ + (ivace_dst_elem)->ivace_persist = (ivace_src_elem)->ivace_persist; \ (ivace_dst_elem)->ivace_made = (ivace_src_elem)->ivace_made; \ (ivace_dst_elem)->ivace_free = (ivace_src_elem)->ivace_free; \ (ivace_dst_elem)->ivace_layered = (ivace_src_elem)->ivace_layered; \ @@ -563,32 +531,33 @@ ivac_alloc(iv_index_t key_index) ivac = (ipc_voucher_attr_control_t)zalloc(ipc_voucher_attr_control_zone); - if (IVAC_NULL == ivac) + if (IVAC_NULL == ivac) { return IVAC_NULL; - - ivac->ivac_refs = 1; + } + + os_ref_init(&ivac->ivac_refs, &ivac_refgrp); ivac->ivac_is_growing = FALSE; ivac->ivac_port = IP_NULL; /* start with just the inline table */ - table = (ivac_entry_t) kalloc(IVAC_ENTRIES_MIN * sizeof(ivac_entry)); + table = (ivac_entry_t) kalloc(IVAC_ENTRIES_MIN * sizeof(ivac_entry)); ivac->ivac_table = table; ivac->ivac_table_size = IVAC_ENTRIES_MIN; ivac->ivac_init_table_size = IVAC_ENTRIES_MIN; for (i = 0; i < ivac->ivac_table_size; i++) { - ivace_reset_data(&table[i], i+1); + ivace_reset_data(&table[i], i + 1); } /* the default table entry is never on freelist */ table[0].ivace_next = IV_HASH_END; table[0].ivace_free = FALSE; - table[i-1].ivace_next = IV_FREELIST_END; + table[i - 1].ivace_next = IV_FREELIST_END; ivac->ivac_freelist = 1; ivac_lock_init(ivac); ivac->ivac_key_index = key_index; - return (ivac); + return ivac; } - + void ivac_dealloc(ipc_voucher_attr_control_t ivac) @@ -604,7 +573,7 @@ ivac_dealloc(ipc_voucher_attr_control_t ivac) * that the reference count is still zero. */ ivgt_lock(); - if (ivac->ivac_refs > 0) { + if (os_ref_get_count(&ivac->ivac_refs) > 0) { ivgt_unlock(); return; } @@ -619,8 +588,9 @@ ivac_dealloc(ipc_voucher_attr_control_t ivac) ivgt_unlock(); /* release the reference held on the resource manager */ - if (IVAM_NULL != ivam) + if (IVAM_NULL != ivam) { (ivam->ivam_release)(ivam); + } /* * if a port was allocated for this voucher, @@ -629,7 +599,7 @@ ivac_dealloc(ipc_voucher_attr_control_t ivac) * is gone. We can just discard it now. */ if (IP_VALID(port)) { - assert(ip_active(port)); + require_ip_active(port); assert(port->ip_srights == 0); ipc_port_dealloc_kernel(port); @@ -641,9 +611,11 @@ ivac_dealloc(ipc_voucher_attr_control_t ivac) * table. */ #ifdef MACH_DEBUG - for (i = 0; i < ivac->ivac_table_size; i++) - if (ivac->ivac_table[i].ivace_refs != 0) + for (i = 0; i < ivac->ivac_table_size; i++) { + if (ivac->ivac_table[i].ivace_refs != 0) { panic("deallocing a resource manager with live refs to its attr values\n"); + } + } #endif kfree(ivac->ivac_table, ivac->ivac_table_size * sizeof(*ivac->ivac_table)); ivac_lock_destroy(ivac); @@ -673,10 +645,10 @@ ipc_voucher_attr_control_release(ipc_voucher_attr_control_t control) */ ipc_voucher_attr_control_t convert_port_to_voucher_attr_control( - ipc_port_t port) + ipc_port_t port) { if (IP_VALID(port)) { - ipc_voucher_attr_control_t ivac = (ipc_voucher_attr_control_t) port->ip_kobject; + ipc_voucher_attr_control_t ivac = (ipc_voucher_attr_control_t) ip_get_kobject(port); /* * No need to lock because we have a reference on the @@ -684,17 +656,24 @@ convert_port_to_voucher_attr_control( * that reference keeps the voucher bound to the port * (and active). */ - if (ip_kotype(port) != IKOT_VOUCHER_ATTR_CONTROL) + if (ip_kotype(port) != IKOT_VOUCHER_ATTR_CONTROL) { return IVAC_NULL; + } + require_ip_active(port); - assert(ip_active(port)); - + zone_require(ipc_voucher_attr_control_zone, ivac); ivac_reference(ivac); - return (ivac); + return ivac; } return IVAC_NULL; } +/* + * Routine: ipc_voucher_notify + * Purpose: + * Called whenever the Mach port system detects no-senders + * on the voucher attr control port. + */ void ipc_voucher_attr_control_notify(mach_msg_header_t *msg) { @@ -702,18 +681,12 @@ ipc_voucher_attr_control_notify(mach_msg_header_t *msg) ipc_port_t port = notification->not_header.msgh_remote_port; ipc_voucher_attr_control_t ivac; + require_ip_active(port); assert(IKOT_VOUCHER_ATTR_CONTROL == ip_kotype(port)); - ip_lock(port); - assert(ip_active(port)); - - /* if no new send rights, drop a control reference */ - if (port->ip_mscount == notification->not_count) { - ivac = (ipc_voucher_attr_control_t)port->ip_kobject; - ip_unlock(port); - ivac_release(ivac); - } - ip_unlock(port); + /* release the reference donated by convert_voucher_attr_control_to_port */ + ivac = (ipc_voucher_attr_control_t)ip_get_kobject(port); + ivac_release(ivac); } /* @@ -722,46 +695,21 @@ ipc_voucher_attr_control_notify(mach_msg_header_t *msg) ipc_port_t convert_voucher_attr_control_to_port(ipc_voucher_attr_control_t control) { - ipc_port_t port, send; - - if (IVAC_NULL == control) - return (IP_NULL); - - /* create a port if needed */ - port = control->ivac_port; - if (!IP_VALID(port)) { - port = ipc_port_alloc_kernel(); - assert(IP_VALID(port)); - if (OSCompareAndSwapPtr(IP_NULL, port, &control->ivac_port)) { - ip_lock(port); - ipc_kobject_set_atomically(port, (ipc_kobject_t) control, IKOT_VOUCHER_ATTR_CONTROL); - } else { - ipc_port_dealloc_kernel(port); - port = control->ivac_port; - ip_lock(port); - assert(ip_kotype(port) == IKOT_VOUCHER_ATTR_CONTROL); - assert(port->ip_kobject == (ipc_kobject_t)control); - } - } else - ip_lock(port); - - assert(ip_active(port)); - send = ipc_port_make_send_locked(port); + if (IVAC_NULL == control) { + return IP_NULL; + } - if (1 == port->ip_srights) { - ipc_port_t old_notify; + zone_require(ipc_voucher_attr_control_zone, control); - /* transfer our ref to the port, and arm the no-senders notification */ - assert(IP_NULL == port->ip_nsrequest); - ipc_port_nsrequest(port, port->ip_mscount, ipc_port_make_sonce_locked(port), &old_notify); - assert(IP_NULL == old_notify); - ip_unlock(port); - } else { - /* piggyback on the existing port reference, so consume ours */ - ip_unlock(port); + /* + * make a send right and donate our reference for + * ipc_voucher_attr_control_notify if this is the first send right + */ + if (!ipc_kobject_make_send_lazy_alloc_port(&control->ivac_port, + (ipc_kobject_t)control, IKOT_VOUCHER_ATTR_CONTROL, false, 0)) { ivac_release(control); } - return (send); + return control->ivac_port; } /* @@ -769,10 +717,10 @@ convert_voucher_attr_control_to_port(ipc_voucher_attr_control_t control) */ static void ivace_lookup_values( - iv_index_t key_index, - iv_index_t value_index, - mach_voucher_attr_value_handle_array_t values, - mach_voucher_attr_value_handle_array_size_t *count) + iv_index_t key_index, + iv_index_t value_index, + mach_voucher_attr_value_handle_array_t values, + mach_voucher_attr_value_handle_array_size_t *count) { ipc_voucher_attr_control_t ivac; ivac_entry_t ivace; @@ -824,37 +772,31 @@ ivac_grow_table(ipc_voucher_attr_control_t ivac) ivac->ivac_is_growing = 1; if (ivac->ivac_table_size >= IVAC_ENTRIES_MAX) { panic("Cannot grow ipc space beyond IVAC_ENTRIES_MAX. Some process is leaking vouchers"); + return; } old_size = ivac->ivac_table_size; ivac_unlock(ivac); - /* - * if initial size is not leading to page aligned allocations, - * set new_size such that new_size * sizeof(ivac_entry) is page aligned. - */ - - if ((old_size * sizeof(ivac_entry)) & PAGE_MASK){ - new_size = (iv_index_t)round_page((old_size * sizeof(ivac_entry)))/(sizeof (ivac_entry)); - } else { - new_size = old_size * 2; - } + new_size = old_size * 2; assert(new_size > old_size); + assert(new_size < IVAC_ENTRIES_MAX); + new_table = kalloc(sizeof(ivac_entry) * new_size); - if (!new_table){ + if (!new_table) { panic("Failed to grow ivac table to size %d\n", new_size); return; } /* setup the free list for new entries */ for (i = old_size; i < new_size; i++) { - ivace_reset_data(&new_table[i], i+1); + ivace_reset_data(&new_table[i], i + 1); } ivac_lock(ivac); - - for (i = 0; i < ivac->ivac_table_size; i++){ + + for (i = 0; i < ivac->ivac_table_size; i++) { ivace_copy_data(&ivac->ivac_table[i], &new_table[i]); } @@ -862,14 +804,14 @@ ivac_grow_table(ipc_voucher_attr_control_t ivac) ivac->ivac_table = new_table; ivac->ivac_table_size = new_size; - + /* adding new free entries at head of freelist */ ivac->ivac_table[new_size - 1].ivace_next = ivac->ivac_freelist; ivac->ivac_freelist = old_size; ivac->ivac_is_growing = 0; ivac_wakeup(ivac); - if (old_table){ + if (old_table) { ivac_unlock(ivac); kfree(old_table, old_size * sizeof(ivac_entry)); ivac_lock(ivac); @@ -885,14 +827,15 @@ ivac_grow_table(ipc_voucher_attr_control_t ivac) */ static void ivace_reference_by_index( - iv_index_t key_index, - iv_index_t val_index) + iv_index_t key_index, + iv_index_t val_index) { ipc_voucher_attr_control_t ivac; ivac_entry_t ivace; - if (IV_UNUSED_VALINDEX == val_index) + if (IV_UNUSED_VALINDEX == val_index) { return; + } ivgt_lookup(key_index, FALSE, NULL, &ivac); assert(IVAC_NULL != ivac); @@ -904,7 +847,11 @@ ivace_reference_by_index( assert(0xdeadc0dedeadc0de != ivace->ivace_value); assert(0 < ivace->ivace_refs); assert(!ivace->ivace_free); - ivace->ivace_refs++; + + /* Take ref only on non-persistent values */ + if (!ivace->ivace_persist) { + ivace->ivace_refs++; + } ivac_unlock(ivac); } @@ -919,8 +866,9 @@ ivace_reference_by_index( */ static iv_index_t ivace_reference_by_value( - ipc_voucher_attr_control_t ivac, - mach_voucher_attr_value_handle_t value) + ipc_voucher_attr_control_t ivac, + mach_voucher_attr_value_handle_t value, + mach_voucher_attr_value_flags_t flag) { ivac_entry_t ivace = IVACE_NULL; iv_index_t hash_index; @@ -930,7 +878,7 @@ ivace_reference_by_value( return IV_UNUSED_VALINDEX; } - ivac_lock(ivac); + ivac_lock(ivac); restart: hash_index = IV_HASH_VAL(ivac->ivac_init_table_size, value); index = ivac->ivac_table[hash_index].ivace_index; @@ -939,17 +887,18 @@ restart: ivace = &ivac->ivac_table[index]; assert(!ivace->ivace_free); - if (ivace->ivace_value == value) + if (ivace->ivace_value == value) { break; + } assert(ivace->ivace_next != index); index = ivace->ivace_next; } /* found it? */ - if (index != IV_HASH_END) { - /* only add reference on non-default value */ - if (IV_UNUSED_VALINDEX != index) { + if (index != IV_HASH_END) { + /* only add reference on non-persistent value */ + if (!ivace->ivace_persist) { ivace->ivace_refs++; ivace->ivace_made++; } @@ -976,6 +925,7 @@ restart: ivace->ivace_refs = 1; ivace->ivace_made = 1; ivace->ivace_free = FALSE; + ivace->ivace_persist = (flag & MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST) ? TRUE : FALSE; /* insert the new entry in the proper hash chain */ ivace->ivace_next = ivac->ivac_table[hash_index].ivace_index; @@ -991,11 +941,12 @@ restart: * Release a reference on the given pair. * * Conditions: called with nothing locked, as it may cause - * callouts and/or messaging to the resource + * callouts and/or messaging to the resource * manager. */ -static void ivace_release( - iv_index_t key_index, +static void +ivace_release( + iv_index_t key_index, iv_index_t value_index) { ipc_voucher_attr_control_t ivac; @@ -1008,8 +959,9 @@ static void ivace_release( kern_return_t kr; /* cant release the default value */ - if (IV_UNUSED_VALINDEX == value_index) + if (IV_UNUSED_VALINDEX == value_index) { return; + } ivgt_lookup(key_index, FALSE, &ivam, &ivac); assert(IVAC_NULL != ivac); @@ -1021,6 +973,12 @@ static void ivace_release( assert(0 < ivace->ivace_refs); + /* cant release persistent values */ + if (ivace->ivace_persist) { + ivac_unlock(ivac); + return; + } + if (0 < --ivace->ivace_refs) { ivac_unlock(ivac); return; @@ -1043,7 +1001,7 @@ static void ivace_release( ivace->ivace_releasing = TRUE; value = ivace->ivace_value; - redrive: +redrive: assert(value == ivace->ivace_value); assert(!ivace->ivace_free); made = ivace->ivace_made; @@ -1065,20 +1023,20 @@ static void ivace_release( * re-drive the release. */ if (ivace->ivace_made != made) { - assert(made < ivace->ivace_made); - - if (KERN_SUCCESS == kr) + if (KERN_SUCCESS == kr) { ivace->ivace_made -= made; + } - if (0 == ivace->ivace_refs) + if (0 == ivace->ivace_refs) { goto redrive; + } ivace->ivace_releasing = FALSE; ivac_unlock(ivac); return; } else { /* - * If the manager returned FAILURE, someone took a + * If the manager returned FAILURE, someone took a * reference on the value but have not updated the ivace, * release the lock and return since thread who got * the new reference will update the ivace and will have @@ -1142,16 +1100,17 @@ static void ivace_release( */ static void ivgt_lookup(iv_index_t key_index, - boolean_t take_reference, - ipc_voucher_attr_manager_t *manager, - ipc_voucher_attr_control_t *control) + boolean_t take_reference, + ipc_voucher_attr_manager_t *manager, + ipc_voucher_attr_control_t *control) { ipc_voucher_attr_control_t ivac; if (key_index < MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN) { ivgt_lock(); - if (NULL != manager) + if (NULL != manager) { *manager = iv_global_table[key_index].ivgte_manager; + } ivac = iv_global_table[key_index].ivgte_control; if (IVAC_NULL != ivac) { assert(key_index == ivac->ivac_key_index); @@ -1161,18 +1120,21 @@ ivgt_lookup(iv_index_t key_index, } } ivgt_unlock(); - if (NULL != control) + if (NULL != control) { *control = ivac; + } } else { - if (NULL != manager) + if (NULL != manager) { *manager = IVAM_NULL; - if (NULL != control) + } + if (NULL != control) { *control = IVAC_NULL; + } } } /* - * Routine: ipc_replace_voucher_value + * Routine: ipc_replace_voucher_value * Purpose: * Replace the value with the results of * running the supplied command through the resource @@ -1183,16 +1145,17 @@ ivgt_lookup(iv_index_t key_index, */ static kern_return_t ipc_replace_voucher_value( - ipc_voucher_t voucher, - mach_voucher_attr_key_t key, - mach_voucher_attr_recipe_command_t command, - ipc_voucher_t prev_voucher, - mach_voucher_attr_content_t content, + ipc_voucher_t voucher, + mach_voucher_attr_key_t key, + mach_voucher_attr_recipe_command_t command, + ipc_voucher_t prev_voucher, + mach_voucher_attr_content_t content, mach_voucher_attr_content_size_t content_size) { mach_voucher_attr_value_handle_t previous_vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED]; mach_voucher_attr_value_handle_array_size_t previous_vals_count; mach_voucher_attr_value_handle_t new_value; + mach_voucher_attr_value_flags_t new_flag; ipc_voucher_t new_value_voucher; ipc_voucher_attr_manager_t ivam; ipc_voucher_attr_control_t ivac; @@ -1201,15 +1164,16 @@ ipc_replace_voucher_value( iv_index_t val_index; iv_index_t key_index; kern_return_t kr; - + /* * Get the manager for this key_index. * Returns a reference on the control. */ key_index = iv_key_to_index(key); ivgt_lookup(key_index, TRUE, &ivam, &ivac); - if (IVAM_NULL == ivam) + if (IVAM_NULL == ivam) { return KERN_INVALID_ARGUMENT; + } /* save the current value stored in the forming voucher */ save_val_index = iv_lookup(voucher, key_index); @@ -1221,26 +1185,27 @@ ipc_replace_voucher_value( * in the forming voucher. */ prev_val_index = (IV_NULL != prev_voucher) ? - iv_lookup(prev_voucher, key_index) : - save_val_index; + iv_lookup(prev_voucher, key_index) : + save_val_index; ivace_lookup_values(key_index, prev_val_index, - previous_vals, &previous_vals_count); + previous_vals, &previous_vals_count); /* Call out to resource manager to get new value */ new_value_voucher = IV_NULL; kr = (ivam->ivam_get_value)( - ivam, key, command, - previous_vals, previous_vals_count, - content, content_size, - &new_value, &new_value_voucher); + ivam, key, command, + previous_vals, previous_vals_count, + content, content_size, + &new_value, &new_flag, &new_value_voucher); if (KERN_SUCCESS != kr) { ivac_release(ivac); return kr; } /* TODO: value insertion from returned voucher */ - if (IV_NULL != new_value_voucher) + if (IV_NULL != new_value_voucher) { iv_release(new_value_voucher); + } /* * Find or create a slot in the table associated @@ -1248,7 +1213,7 @@ ipc_replace_voucher_value( * is transferred to a new value, or consumed if * we find a matching existing value. */ - val_index = ivace_reference_by_value(ivac, new_value); + val_index = ivace_reference_by_value(ivac, new_value, new_flag); iv_set(voucher, key_index, val_index); /* @@ -1258,12 +1223,12 @@ ipc_replace_voucher_value( * as was there before. */ ivace_release(key_index, save_val_index); - + return KERN_SUCCESS; } /* - * Routine: ipc_directly_replace_voucher_value + * Routine: ipc_directly_replace_voucher_value * Purpose: * Replace the value with the value-handle * supplied directly by the attribute manager. @@ -1274,24 +1239,25 @@ ipc_replace_voucher_value( */ static kern_return_t ipc_directly_replace_voucher_value( - ipc_voucher_t voucher, - mach_voucher_attr_key_t key, - mach_voucher_attr_value_handle_t new_value) + ipc_voucher_t voucher, + mach_voucher_attr_key_t key, + mach_voucher_attr_value_handle_t new_value) { ipc_voucher_attr_manager_t ivam; ipc_voucher_attr_control_t ivac; iv_index_t save_val_index; iv_index_t val_index; iv_index_t key_index; - + /* * Get the manager for this key_index. * Returns a reference on the control. */ key_index = iv_key_to_index(key); ivgt_lookup(key_index, TRUE, &ivam, &ivac); - if (IVAM_NULL == ivam) + if (IVAM_NULL == ivam) { return KERN_INVALID_ARGUMENT; + } /* save the current value stored in the forming voucher */ save_val_index = iv_lookup(voucher, key_index); @@ -1302,7 +1268,8 @@ ipc_directly_replace_voucher_value( * is transferred to a new value, or consumed if * we find a matching existing value. */ - val_index = ivace_reference_by_value(ivac, new_value); + val_index = ivace_reference_by_value(ivac, new_value, + MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE); iv_set(voucher, key_index, val_index); /* @@ -1312,26 +1279,25 @@ ipc_directly_replace_voucher_value( * as was there before. */ ivace_release(key_index, save_val_index); - + return KERN_SUCCESS; } static kern_return_t ipc_execute_voucher_recipe_command( - ipc_voucher_t voucher, - mach_voucher_attr_key_t key, - mach_voucher_attr_recipe_command_t command, - ipc_voucher_t prev_iv, - mach_voucher_attr_content_t content, - mach_voucher_attr_content_size_t content_size, - boolean_t key_priv) + ipc_voucher_t voucher, + mach_voucher_attr_key_t key, + mach_voucher_attr_recipe_command_t command, + ipc_voucher_t prev_iv, + mach_voucher_attr_content_t content, + mach_voucher_attr_content_size_t content_size, + boolean_t key_priv) { iv_index_t prev_val_index; iv_index_t val_index; kern_return_t kr; switch (command) { - /* * MACH_VOUCHER_ATTR_COPY * Copy the attribute(s) from the previous voucher to the new @@ -1340,22 +1306,24 @@ ipc_execute_voucher_recipe_command( * voucher. */ case MACH_VOUCHER_ATTR_COPY: - + /* no recipe data on a copy */ - if (0 < content_size) + if (0 < content_size) { return KERN_INVALID_ARGUMENT; + } /* nothing to copy from? - done */ - if (IV_NULL == prev_iv) + if (IV_NULL == prev_iv) { return KERN_SUCCESS; + } if (MACH_VOUCHER_ATTR_KEY_ALL == key) { iv_index_t limit, j; /* reconcile possible difference in voucher sizes */ limit = (prev_iv->iv_table_size < voucher->iv_table_size) ? - prev_iv->iv_table_size : - voucher->iv_table_size; + prev_iv->iv_table_size : + voucher->iv_table_size; /* wildcard matching */ for (j = 0; j < limit; j++) { @@ -1373,8 +1341,9 @@ ipc_execute_voucher_recipe_command( /* copy just one key */ key_index = iv_key_to_index(key); - if (ivgt_keys_in_use < key_index) + if (ivgt_keys_in_use < key_index) { return KERN_INVALID_ARGUMENT; + } /* release old value being replaced */ val_index = iv_lookup(voucher, key_index); @@ -1397,16 +1366,17 @@ ipc_execute_voucher_recipe_command( */ case MACH_VOUCHER_ATTR_REMOVE: /* no recipe data on a remove */ - if (0 < content_size) + if (0 < content_size) { return KERN_INVALID_ARGUMENT; + } if (MACH_VOUCHER_ATTR_KEY_ALL == key) { iv_index_t limit, j; /* reconcile possible difference in voucher sizes */ limit = (IV_NULL == prev_iv) ? voucher->iv_table_size : - ((prev_iv->iv_table_size < voucher->iv_table_size) ? - prev_iv->iv_table_size : voucher->iv_table_size); + ((prev_iv->iv_table_size < voucher->iv_table_size) ? + prev_iv->iv_table_size : voucher->iv_table_size); /* wildcard matching */ for (j = 0; j < limit; j++) { @@ -1415,8 +1385,9 @@ ipc_execute_voucher_recipe_command( /* If not matched in previous, skip */ if (IV_NULL != prev_iv) { prev_val_index = iv_lookup(prev_iv, j); - if (val_index != prev_val_index) + if (val_index != prev_val_index) { continue; + } } /* release and clear */ ivace_release(j, val_index); @@ -1427,16 +1398,18 @@ ipc_execute_voucher_recipe_command( /* copy just one key */ key_index = iv_key_to_index(key); - if (ivgt_keys_in_use < key_index) + if (ivgt_keys_in_use < key_index) { return KERN_INVALID_ARGUMENT; + } val_index = iv_lookup(voucher, key_index); /* If not matched in previous, skip */ if (IV_NULL != prev_iv) { prev_val_index = iv_lookup(prev_iv, key_index); - if (val_index != prev_val_index) + if (val_index != prev_val_index) { break; + } } /* release and clear */ @@ -1455,17 +1428,19 @@ ipc_execute_voucher_recipe_command( if (key_priv) { mach_voucher_attr_value_handle_t new_value; - if (sizeof(mach_voucher_attr_value_handle_t) != content_size) + if (sizeof(mach_voucher_attr_value_handle_t) != content_size) { return KERN_INVALID_ARGUMENT; - + } + new_value = *(mach_voucher_attr_value_handle_t *)(void *)content; kr = ipc_directly_replace_voucher_value(voucher, - key, - new_value); - if (KERN_SUCCESS != kr) + key, new_value); + if (KERN_SUCCESS != kr) { return kr; - } else + } + } else { return KERN_INVALID_CAPABILITY; + } break; /* @@ -1473,19 +1448,20 @@ ipc_execute_voucher_recipe_command( * Redeem the attribute(s) from the previous voucher for a possibly * new value in the new voucher. A wildcard key is an acceptable value, * indicating a desire to redeem all the values. - */ + */ case MACH_VOUCHER_ATTR_REDEEM: if (MACH_VOUCHER_ATTR_KEY_ALL == key) { iv_index_t limit, j; /* reconcile possible difference in voucher sizes */ - if (IV_NULL != prev_iv) + if (IV_NULL != prev_iv) { limit = (prev_iv->iv_table_size < voucher->iv_table_size) ? - prev_iv->iv_table_size : - voucher->iv_table_size; - else + prev_iv->iv_table_size : + voucher->iv_table_size; + } else { limit = voucher->iv_table_size; + } /* wildcard matching */ for (j = 0; j < limit; j++) { @@ -1494,22 +1470,24 @@ ipc_execute_voucher_recipe_command( j_key = iv_index_to_key(j); /* skip non-existent managers */ - if (MACH_VOUCHER_ATTR_KEY_NONE == j_key) + if (MACH_VOUCHER_ATTR_KEY_NONE == j_key) { continue; + } /* get the new value from redeem (skip empty previous) */ kr = ipc_replace_voucher_value(voucher, - j_key, - command, - prev_iv, - content, - content_size); - if (KERN_SUCCESS != kr) + j_key, + command, + prev_iv, + content, + content_size); + if (KERN_SUCCESS != kr) { return kr; + } } break; } - /* fall thru for single key redemption */ + OS_FALLTHROUGH; /* fall thru for single key redemption */ /* * DEFAULT: @@ -1519,13 +1497,14 @@ ipc_execute_voucher_recipe_command( */ default: kr = ipc_replace_voucher_value(voucher, - key, - command, - prev_iv, - content, - content_size); - if (KERN_SUCCESS != kr) + key, + command, + prev_iv, + content, + content_size); + if (KERN_SUCCESS != kr) { return kr; + } break; } @@ -1533,7 +1512,7 @@ ipc_execute_voucher_recipe_command( } /* - * Routine: iv_checksum + * Routine: iv_checksum * Purpose: * Compute the voucher sum. This is more position- * relevant than many other checksums - important for @@ -1547,13 +1526,13 @@ iv_checksum(ipc_voucher_t voucher, boolean_t *emptyp) boolean_t empty = TRUE; if (0 < voucher->iv_table_size) { iv_index_t i = voucher->iv_table_size - 1; - + do { iv_index_t v = voucher->iv_table[i]; - c = c << 3 | c >> (32 - 3); /* rotate */ - c = ~c; /* invert */ + c = c << 3 | c >> (32 - 3); /* rotate */ + c = ~c; /* invert */ if (0 < v) { - c += v; /* add in */ + c += v; /* add in */ empty = FALSE; } } while (0 < i--); @@ -1563,7 +1542,7 @@ iv_checksum(ipc_voucher_t voucher, boolean_t *emptyp) } /* - * Routine: iv_dedup + * Routine: iv_dedup * Purpose: * See if the set of values represented by this new voucher * already exist in another voucher. If so return a reference @@ -1578,7 +1557,7 @@ static ipc_voucher_t iv_dedup(ipc_voucher_t new_iv) { boolean_t empty; - iv_index_t sum; + iv_index_t sum; iv_index_t hash; ipc_voucher_t iv; @@ -1597,40 +1576,41 @@ iv_dedup(ipc_voucher_t new_iv) assert(iv->iv_hash == hash); /* if not already deallocating and sums match... */ - if (0 < iv->iv_refs && iv->iv_sum == sum) { - iv_refs_t refs; + if ((os_ref_get_count(&iv->iv_refs) > 0) && (iv->iv_sum == sum)) { iv_index_t i; assert(iv->iv_table_size <= new_iv->iv_table_size); - + /* and common entries match... */ - for (i = 0; i < iv->iv_table_size; i++) - if (iv->iv_table[i] != new_iv->iv_table[i]) + for (i = 0; i < iv->iv_table_size; i++) { + if (iv->iv_table[i] != new_iv->iv_table[i]) { break; - if (i < iv->iv_table_size) + } + } + if (i < iv->iv_table_size) { continue; + } /* and all extra entries in new one are unused... */ - while (i < new_iv->iv_table_size) - if (new_iv->iv_table[i++] != IV_UNUSED_VALINDEX) + while (i < new_iv->iv_table_size) { + if (new_iv->iv_table[i++] != IV_UNUSED_VALINDEX) { break; - if (i < new_iv->iv_table_size) + } + } + if (i < new_iv->iv_table_size) { continue; + } /* ... we found a match... */ /* can we get a ref before it hits 0 * - * This is thread safe. The reference is just an atomic - * add. If the reference count is zero when we adjust it, - * no other thread can have a reference to the voucher. + * This is thread safe. If the reference count is zero before we + * adjust it, no other thread can have a reference to the voucher. * The dealloc code requires holding the ivht_lock, so * the voucher cannot be yanked out from under us. */ - refs = iv_reference(iv); - if (1 == refs) { - /* drats! going away. Put back to zero */ - iv->iv_refs = 0; + if (!os_ref_retain_try(&iv->iv_refs)) { continue; } @@ -1682,7 +1662,7 @@ iv_dedup(ipc_voucher_t new_iv) #define PAYLOAD_PER_TRACEPOINT (4 * sizeof(uintptr_t)) #define PAYLOAD_SIZE 1024 - _Static_assert(PAYLOAD_SIZE % PAYLOAD_PER_TRACEPOINT == 0, "size invariant violated"); + static_assert(PAYLOAD_SIZE % PAYLOAD_PER_TRACEPOINT == 0, "size invariant violated"); mach_voucher_attr_raw_recipe_array_size_t payload_size = PAYLOAD_SIZE; uintptr_t payload[PAYLOAD_SIZE / sizeof(uintptr_t)]; @@ -1700,28 +1680,25 @@ iv_dedup(ipc_voucher_t new_iv) size_t remainder = payload_size % PAYLOAD_PER_TRACEPOINT; if (remainder) { bzero((uint8_t*)payload + payload_size, - PAYLOAD_PER_TRACEPOINT - remainder); + PAYLOAD_PER_TRACEPOINT - remainder); } } - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_VOUCHER_CREATE) | DBG_FUNC_NONE, - voucher_addr, - new_iv->iv_table_size, ivht_count, payload_size, 0); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_VOUCHER_CREATE), + voucher_addr, new_iv->iv_table_size, ivht_count, + payload_size); uintptr_t index = 0; while (attr_tracepoints_needed--) { - KERNEL_DEBUG_CONSTANT1(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_VOUCHER_CREATE_ATTR_DATA) | DBG_FUNC_NONE, - payload[index], - payload[index+1], - payload[index+2], - payload[index+3], - voucher_addr); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, + MACH_IPC_VOUCHER_CREATE_ATTR_DATA), payload[index], + payload[index + 1], payload[index + 2], + payload[index + 3]); index += 4; } } else { - KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_VOUCHER_CREATE) | DBG_FUNC_NONE, - voucher_addr, - new_iv->iv_table_size, ivht_count, 0, 0); + KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_VOUCHER_CREATE), + voucher_addr, new_iv->iv_table_size, ivht_count); } } #endif /* KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD */ @@ -1730,7 +1707,7 @@ iv_dedup(ipc_voucher_t new_iv) } /* - * Routine: ipc_create_mach_voucher + * Routine: ipc_create_mach_voucher * Purpose: * Create a new mach voucher and initialize it with the * value(s) created by having the appropriate resource @@ -1743,9 +1720,9 @@ iv_dedup(ipc_voucher_t new_iv) */ kern_return_t ipc_create_mach_voucher( - ipc_voucher_attr_raw_recipe_array_t recipes, - ipc_voucher_attr_raw_recipe_array_size_t recipe_size, - ipc_voucher_t *new_voucher) + ipc_voucher_attr_raw_recipe_array_t recipes, + ipc_voucher_attr_raw_recipe_array_size_t recipe_size, + ipc_voucher_t *new_voucher) { ipc_voucher_attr_recipe_t sub_recipe; ipc_voucher_attr_recipe_size_t recipe_used = 0; @@ -1760,12 +1737,12 @@ ipc_create_mach_voucher( /* allocate a voucher */ voucher = iv_alloc(ivgt_keys_in_use); - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_RESOURCE_SHORTAGE; + } /* iterate over the recipe items */ while (0 < recipe_size - recipe_used) { - if (recipe_size - recipe_used < sizeof(*sub_recipe)) { kr = KERN_INVALID_ARGUMENT; break; @@ -1780,14 +1757,15 @@ ipc_create_mach_voucher( recipe_used += sizeof(*sub_recipe) + sub_recipe->content_size; kr = ipc_execute_voucher_recipe_command(voucher, - sub_recipe->key, - sub_recipe->command, - sub_recipe->previous_voucher, - sub_recipe->content, - sub_recipe->content_size, - FALSE); - if (KERN_SUCCESS != kr) + sub_recipe->key, + sub_recipe->command, + sub_recipe->previous_voucher, + sub_recipe->content, + sub_recipe->content_size, + FALSE); + if (KERN_SUCCESS != kr) { break; + } } if (KERN_SUCCESS == kr) { @@ -1800,7 +1778,7 @@ ipc_create_mach_voucher( } /* - * Routine: ipc_voucher_attr_control_create_mach_voucher + * Routine: ipc_voucher_attr_control_create_mach_voucher * Purpose: * Create a new mach voucher and initialize it with the * value(s) created by having the appropriate resource @@ -1821,10 +1799,10 @@ ipc_create_mach_voucher( */ kern_return_t ipc_voucher_attr_control_create_mach_voucher( - ipc_voucher_attr_control_t control, - ipc_voucher_attr_raw_recipe_array_t recipes, - ipc_voucher_attr_raw_recipe_array_size_t recipe_size, - ipc_voucher_t *new_voucher) + ipc_voucher_attr_control_t control, + ipc_voucher_attr_raw_recipe_array_t recipes, + ipc_voucher_attr_raw_recipe_array_size_t recipe_size, + ipc_voucher_t *new_voucher) { mach_voucher_attr_key_t control_key; ipc_voucher_attr_recipe_t sub_recipe; @@ -1832,8 +1810,9 @@ ipc_voucher_attr_control_create_mach_voucher( ipc_voucher_t voucher = IV_NULL; kern_return_t kr = KERN_SUCCESS; - if (IPC_VOUCHER_ATTR_CONTROL_NULL == control) + if (IPC_VOUCHER_ATTR_CONTROL_NULL == control) { return KERN_INVALID_CAPABILITY; + } /* if nothing to do ... */ if (0 == recipe_size) { @@ -1843,14 +1822,14 @@ ipc_voucher_attr_control_create_mach_voucher( /* allocate new voucher */ voucher = iv_alloc(ivgt_keys_in_use); - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_RESOURCE_SHORTAGE; + } control_key = iv_index_to_key(control->ivac_key_index); /* iterate over the recipe items */ while (0 < recipe_size - recipe_used) { - if (recipe_size - recipe_used < sizeof(*sub_recipe)) { kr = KERN_INVALID_ARGUMENT; break; @@ -1865,14 +1844,15 @@ ipc_voucher_attr_control_create_mach_voucher( recipe_used += sizeof(*sub_recipe) + sub_recipe->content_size; kr = ipc_execute_voucher_recipe_command(voucher, - sub_recipe->key, - sub_recipe->command, - sub_recipe->previous_voucher, - sub_recipe->content, - sub_recipe->content_size, - (sub_recipe->key == control_key)); - if (KERN_SUCCESS != kr) + sub_recipe->key, + sub_recipe->command, + sub_recipe->previous_voucher, + sub_recipe->content, + sub_recipe->content_size, + (sub_recipe->key == control_key)); + if (KERN_SUCCESS != kr) { break; + } } if (KERN_SUCCESS == kr) { @@ -1885,7 +1865,7 @@ ipc_voucher_attr_control_create_mach_voucher( } /* - * ipc_register_well_known_mach_voucher_attr_manager + * ipc_register_well_known_mach_voucher_attr_manager * * Register the resource manager responsible for a given key value. */ @@ -1893,28 +1873,32 @@ kern_return_t ipc_register_well_known_mach_voucher_attr_manager( ipc_voucher_attr_manager_t manager, mach_voucher_attr_value_handle_t default_value, - mach_voucher_attr_key_t key, + mach_voucher_attr_key_t key, ipc_voucher_attr_control_t *control) { ipc_voucher_attr_control_t new_control; iv_index_t key_index; iv_index_t hash_index; - if (IVAM_NULL == manager) + if (IVAM_NULL == manager) { return KERN_INVALID_ARGUMENT; + } key_index = iv_key_to_index(key); - if (IV_UNUSED_KEYINDEX == key_index) + if (IV_UNUSED_KEYINDEX == key_index) { return KERN_INVALID_ARGUMENT; + } new_control = ivac_alloc(key_index); - if (IVAC_NULL == new_control) + if (IVAC_NULL == new_control) { return KERN_RESOURCE_SHORTAGE; + } /* insert the default value into slot 0 */ new_control->ivac_table[IV_UNUSED_VALINDEX].ivace_value = default_value; new_control->ivac_table[IV_UNUSED_VALINDEX].ivace_refs = IVACE_REFS_MAX; new_control->ivac_table[IV_UNUSED_VALINDEX].ivace_made = IVACE_REFS_MAX; + new_control->ivac_table[IV_UNUSED_VALINDEX].ivace_persist = TRUE; assert(IV_HASH_END == new_control->ivac_table[IV_UNUSED_VALINDEX].ivace_next); ivgt_lock(); @@ -1935,7 +1919,7 @@ ipc_register_well_known_mach_voucher_attr_manager( new_control->ivac_table[hash_index].ivace_index = IV_UNUSED_VALINDEX; ivgt_unlock(); - + /* return the reference on the new cache control to the caller */ *control = new_control; @@ -1943,7 +1927,7 @@ ipc_register_well_known_mach_voucher_attr_manager( } /* - * Routine: mach_voucher_extract_attr_content + * Routine: mach_voucher_extract_attr_content * Purpose: * Extract the content for a given pair. * @@ -1958,10 +1942,10 @@ ipc_register_well_known_mach_voucher_attr_manager( */ kern_return_t mach_voucher_extract_attr_content( - ipc_voucher_t voucher, - mach_voucher_attr_key_t key, - mach_voucher_attr_content_t content, - mach_voucher_attr_content_size_t *in_out_size) + ipc_voucher_t voucher, + mach_voucher_attr_key_t key, + mach_voucher_attr_content_t content, + mach_voucher_attr_content_size_t *in_out_size) { mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED]; mach_voucher_attr_value_handle_array_size_t vals_count; @@ -1972,8 +1956,9 @@ mach_voucher_extract_attr_content( kern_return_t kr; - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_INVALID_ARGUMENT; + } key_index = iv_key_to_index(key); @@ -1990,27 +1975,27 @@ mach_voucher_extract_attr_content( * manager referenced during the callout. */ ivgt_lookup(key_index, FALSE, &manager, NULL); - assert(IVAM_NULL != manager); + if (IVAM_NULL == manager) { + return KERN_INVALID_ARGUMENT; + } /* * Get the value(s) to pass to the manager * for this value_index. */ ivace_lookup_values(key_index, value_index, - vals, &vals_count); + vals, &vals_count); assert(0 < vals_count); /* callout to manager */ - - kr = (manager->ivam_extract_content)(manager, key, - vals, vals_count, - &command, - content, in_out_size); + + kr = (manager->ivam_extract_content)(manager, key, + vals, vals_count, &command, content, in_out_size); return kr; } /* - * Routine: mach_voucher_extract_attr_recipe + * Routine: mach_voucher_extract_attr_recipe * Purpose: * Extract a recipe for a given pair. * @@ -2025,10 +2010,10 @@ mach_voucher_extract_attr_content( */ kern_return_t mach_voucher_extract_attr_recipe( - ipc_voucher_t voucher, - mach_voucher_attr_key_t key, - mach_voucher_attr_raw_recipe_t raw_recipe, - mach_voucher_attr_raw_recipe_size_t *in_out_size) + ipc_voucher_t voucher, + mach_voucher_attr_key_t key, + mach_voucher_attr_raw_recipe_t raw_recipe, + mach_voucher_attr_raw_recipe_size_t *in_out_size) { mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED]; mach_voucher_attr_value_handle_array_size_t vals_count; @@ -2039,8 +2024,9 @@ mach_voucher_extract_attr_recipe( kern_return_t kr; - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_INVALID_ARGUMENT; + } key_index = iv_key_to_index(key); @@ -2050,8 +2036,9 @@ mach_voucher_extract_attr_recipe( return KERN_SUCCESS; } - if (*in_out_size < sizeof(*recipe)) + if (*in_out_size < sizeof(*recipe)) { return KERN_NO_SPACE; + } recipe = (mach_voucher_attr_recipe_t)(void *)raw_recipe; recipe->key = key; @@ -2066,24 +2053,26 @@ mach_voucher_extract_attr_recipe( * manager referenced during the callout. */ ivgt_lookup(key_index, FALSE, &manager, NULL); - assert(IVAM_NULL != manager); + if (IVAM_NULL == manager) { + return KERN_INVALID_ARGUMENT; + } /* * Get the value(s) to pass to the manager * for this value_index. */ ivace_lookup_values(key_index, value_index, - vals, &vals_count); + vals, &vals_count); assert(0 < vals_count); /* callout to manager */ - kr = (manager->ivam_extract_content)(manager, key, - vals, vals_count, - &recipe->command, - recipe->content, &recipe->content_size); + kr = (manager->ivam_extract_content)(manager, key, + vals, vals_count, + &recipe->command, + recipe->content, &recipe->content_size); if (KERN_SUCCESS == kr) { - assert(*in_out_size - sizeof(*recipe) >= recipe->content_size); - *in_out_size = sizeof(*recipe) + recipe->content_size; + assert(*in_out_size - sizeof(*recipe) >= recipe->content_size); + *in_out_size = sizeof(*recipe) + recipe->content_size; } return kr; @@ -2092,27 +2081,28 @@ mach_voucher_extract_attr_recipe( /* - * Routine: mach_voucher_extract_all_attr_recipes + * Routine: mach_voucher_extract_all_attr_recipes * Purpose: * Extract all the (non-default) contents for a given voucher, - * building up a recipe that could be provided to a future + * building up a recipe that could be provided to a future * voucher creation call. - * Conditions: + * Conditions: * Nothing locked (may invoke user-space). * Caller holds a reference on the supplied voucher. */ kern_return_t mach_voucher_extract_all_attr_recipes( - ipc_voucher_t voucher, - mach_voucher_attr_raw_recipe_array_t recipes, - mach_voucher_attr_raw_recipe_array_size_t *in_out_size) + ipc_voucher_t voucher, + mach_voucher_attr_raw_recipe_array_t recipes, + mach_voucher_attr_raw_recipe_array_size_t *in_out_size) { mach_voucher_attr_recipe_size_t recipe_size = *in_out_size; mach_voucher_attr_recipe_size_t recipe_used = 0; iv_index_t key_index; - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_INVALID_ARGUMENT; + } for (key_index = 0; key_index < voucher->iv_table_size; key_index++) { mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED]; @@ -2126,15 +2116,14 @@ mach_voucher_extract_all_attr_recipes( /* don't output anything for a default value */ value_index = iv_lookup(voucher, key_index); - if (IV_UNUSED_VALINDEX == value_index) + if (IV_UNUSED_VALINDEX == value_index) { continue; + } - if (recipe_size - recipe_used < sizeof(*recipe)) + if (recipe_size - recipe_used < sizeof(*recipe)) { return KERN_NO_SPACE; + } - recipe = (mach_voucher_attr_recipe_t)(void *)&recipes[recipe_used]; - content_size = recipe_size - recipe_used - sizeof(*recipe); - /* * Get the manager for this key_index. The * existence of a non-default value for this @@ -2143,13 +2132,19 @@ mach_voucher_extract_all_attr_recipes( */ ivgt_lookup(key_index, FALSE, &manager, NULL); assert(IVAM_NULL != manager); + if (IVAM_NULL == manager) { + continue; + } + + recipe = (mach_voucher_attr_recipe_t)(void *)&recipes[recipe_used]; + content_size = recipe_size - recipe_used - sizeof(*recipe); /* * Get the value(s) to pass to the manager * for this value_index. */ ivace_lookup_values(key_index, value_index, - vals, &vals_count); + vals, &vals_count); assert(0 < vals_count); key = iv_index_to_key(key_index); @@ -2159,12 +2154,13 @@ mach_voucher_extract_all_attr_recipes( recipe->content_size = content_size; /* callout to manager */ - kr = (manager->ivam_extract_content)(manager, key, - vals, vals_count, - &recipe->command, - recipe->content, &recipe->content_size); - if (KERN_SUCCESS != kr) + kr = (manager->ivam_extract_content)(manager, key, + vals, vals_count, + &recipe->command, + recipe->content, &recipe->content_size); + if (KERN_SUCCESS != kr) { return kr; + } assert(recipe->content_size <= content_size); recipe_used += sizeof(*recipe) + recipe->content_size; @@ -2175,10 +2171,10 @@ mach_voucher_extract_all_attr_recipes( } /* - * Routine: mach_voucher_debug_info + * Routine: mach_voucher_debug_info * Purpose: * Extract all the (non-default) contents for a given mach port name, - * building up a recipe that could be provided to a future + * building up a recipe that could be provided to a future * voucher creation call. * Conditions: * Nothing locked (may invoke user-space). @@ -2187,32 +2183,37 @@ mach_voucher_extract_all_attr_recipes( #if !(DEVELOPMENT || DEBUG) kern_return_t mach_voucher_debug_info( - ipc_space_t __unused space, - mach_port_name_t __unused voucher_name, - mach_voucher_attr_raw_recipe_array_t __unused recipes, - mach_voucher_attr_raw_recipe_array_size_t __unused *in_out_size) + ipc_space_t __unused space, + mach_port_name_t __unused voucher_name, + mach_voucher_attr_raw_recipe_array_t __unused recipes, + mach_voucher_attr_raw_recipe_array_size_t __unused *in_out_size) { return KERN_NOT_SUPPORTED; } #else kern_return_t mach_voucher_debug_info( - ipc_space_t space, - mach_port_name_t voucher_name, - mach_voucher_attr_raw_recipe_array_t recipes, - mach_voucher_attr_raw_recipe_array_size_t *in_out_size) + ipc_space_t space, + mach_port_name_t voucher_name, + mach_voucher_attr_raw_recipe_array_t recipes, + mach_voucher_attr_raw_recipe_array_size_t *in_out_size) { ipc_voucher_t voucher = IPC_VOUCHER_NULL; kern_return_t kr; ipc_port_t port = MACH_PORT_NULL; + if (space == IS_NULL) { + return KERN_INVALID_TASK; + } + if (!MACH_PORT_VALID(voucher_name)) { return KERN_INVALID_ARGUMENT; } kr = ipc_port_translate_send(space, voucher_name, &port); - if (KERN_SUCCESS != kr) + if (KERN_SUCCESS != kr) { return KERN_INVALID_ARGUMENT; + } voucher = convert_port_to_voucher(port); ip_unlock(port); @@ -2228,7 +2229,7 @@ mach_voucher_debug_info( #endif /* - * Routine: mach_voucher_attr_command + * Routine: mach_voucher_attr_command * Purpose: * Invoke an attribute-specific command through this voucher. * @@ -2241,13 +2242,13 @@ mach_voucher_debug_info( */ kern_return_t mach_voucher_attr_command( - ipc_voucher_t voucher, - mach_voucher_attr_key_t key, - mach_voucher_attr_command_t command, - mach_voucher_attr_content_t in_content, - mach_voucher_attr_content_size_t in_content_size, - mach_voucher_attr_content_t out_content, - mach_voucher_attr_content_size_t *out_content_size) + ipc_voucher_t voucher, + mach_voucher_attr_key_t key, + mach_voucher_attr_command_t command, + mach_voucher_attr_content_t in_content, + mach_voucher_attr_content_size_t in_content_size, + mach_voucher_attr_content_t out_content, + mach_voucher_attr_content_size_t *out_content_size) { mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED]; mach_voucher_attr_value_handle_array_size_t vals_count; @@ -2258,8 +2259,9 @@ mach_voucher_attr_command( kern_return_t kr; - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_INVALID_ARGUMENT; + } key_index = iv_key_to_index(key); @@ -2272,7 +2274,9 @@ mach_voucher_attr_command( * execution. */ ivgt_lookup(key_index, TRUE, &manager, &control); - assert(IVAM_NULL != manager); + if (IVAM_NULL == manager) { + return KERN_INVALID_ARGUMENT; + } /* * Get the values for this pair @@ -2282,14 +2286,14 @@ mach_voucher_attr_command( */ value_index = iv_lookup(voucher, key_index); ivace_lookup_values(key_index, value_index, - vals, &vals_count); + vals, &vals_count); /* callout to manager */ - kr = (manager->ivam_command)(manager, key, - vals, vals_count, - command, - in_content, in_content_size, - out_content, out_content_size); + kr = (manager->ivam_command)(manager, key, + vals, vals_count, + command, + in_content, in_content_size, + out_content, out_content_size); /* release reference on control */ ivac_release(control); @@ -2298,7 +2302,7 @@ mach_voucher_attr_command( } /* - * Routine: mach_voucher_attr_control_get_values + * Routine: mach_voucher_attr_control_get_values * Purpose: * For a given voucher, get the value handle associated with the * specified attribute manager. @@ -2312,27 +2316,29 @@ mach_voucher_attr_control_get_values( { iv_index_t key_index, value_index; - if (IPC_VOUCHER_ATTR_CONTROL_NULL == control) + if (IPC_VOUCHER_ATTR_CONTROL_NULL == control) { return KERN_INVALID_CAPABILITY; + } - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_INVALID_ARGUMENT; + } - if (0 == *in_out_size) + if (0 == *in_out_size) { return KERN_SUCCESS; + } key_index = control->ivac_key_index; - assert(0 < voucher->iv_refs); + assert(os_ref_get_count(&voucher->iv_refs) > 0); value_index = iv_lookup(voucher, key_index); ivace_lookup_values(key_index, value_index, - out_values, in_out_size); + out_values, in_out_size); return KERN_SUCCESS; } - /* - * Routine: mach_voucher_attr_control_create_mach_voucher + * Routine: mach_voucher_attr_control_create_mach_voucher * Purpose: * Create a new mach voucher and initialize it by processing the * supplied recipe(s). @@ -2360,8 +2366,9 @@ mach_voucher_attr_control_create_mach_voucher( ipc_voucher_t voucher = IV_NULL; kern_return_t kr = KERN_SUCCESS; - if (IPC_VOUCHER_ATTR_CONTROL_NULL == control) + if (IPC_VOUCHER_ATTR_CONTROL_NULL == control) { return KERN_INVALID_CAPABILITY; + } /* if nothing to do ... */ if (0 == recipe_size) { @@ -2371,8 +2378,9 @@ mach_voucher_attr_control_create_mach_voucher( /* allocate new voucher */ voucher = iv_alloc(ivgt_keys_in_use); - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_RESOURCE_SHORTAGE; + } control_key = iv_index_to_key(control->ivac_key_index); @@ -2401,16 +2409,17 @@ mach_voucher_attr_control_create_mach_voucher( } kr = ipc_execute_voucher_recipe_command(voucher, - sub_recipe->key, - sub_recipe->command, - prev_iv, - sub_recipe->content, - sub_recipe->content_size, - (sub_recipe->key == control_key)); + sub_recipe->key, + sub_recipe->command, + prev_iv, + sub_recipe->content, + sub_recipe->content_size, + (sub_recipe->key == control_key)); ipc_voucher_release(prev_iv); - if (KERN_SUCCESS != kr) + if (KERN_SUCCESS != kr) { break; + } } if (KERN_SUCCESS == kr) { @@ -2423,7 +2432,7 @@ mach_voucher_attr_control_create_mach_voucher( } /* - * Routine: host_create_mach_voucher + * Routine: host_create_mach_voucher * Purpose: * Create a new mach voucher and initialize it by processing the * supplied recipe(s). @@ -2447,8 +2456,9 @@ host_create_mach_voucher( ipc_voucher_t voucher = IV_NULL; kern_return_t kr = KERN_SUCCESS; - if (host == HOST_NULL) + if (host == HOST_NULL) { return KERN_INVALID_ARGUMENT; + } /* if nothing to do ... */ if (0 == recipe_size) { @@ -2458,8 +2468,9 @@ host_create_mach_voucher( /* allocate new voucher */ voucher = iv_alloc(ivgt_keys_in_use); - if (IV_NULL == voucher) + if (IV_NULL == voucher) { return KERN_RESOURCE_SHORTAGE; + } /* iterate over the recipe items */ while (0 < recipe_size - recipe_used) { @@ -2486,16 +2497,17 @@ host_create_mach_voucher( } kr = ipc_execute_voucher_recipe_command(voucher, - sub_recipe->key, - sub_recipe->command, - prev_iv, - sub_recipe->content, - sub_recipe->content_size, - FALSE); + sub_recipe->key, + sub_recipe->command, + prev_iv, + sub_recipe->content, + sub_recipe->content_size, + FALSE); ipc_voucher_release(prev_iv); - if (KERN_SUCCESS != kr) + if (KERN_SUCCESS != kr) { break; + } } if (KERN_SUCCESS == kr) { @@ -2508,10 +2520,10 @@ host_create_mach_voucher( } /* - * Routine: host_register_well_known_mach_voucher_attr_manager + * Routine: host_register_well_known_mach_voucher_attr_manager * Purpose: * Register the user-level resource manager responsible for a given - * key value. + * key value. * Conditions: * The manager port passed in has to be converted/wrapped * in an ipc_voucher_attr_manager_t structure and then call the @@ -2521,14 +2533,15 @@ host_create_mach_voucher( */ kern_return_t host_register_well_known_mach_voucher_attr_manager( - host_t host, + host_t host, mach_voucher_attr_manager_t __unused manager, mach_voucher_attr_value_handle_t __unused default_value, - mach_voucher_attr_key_t __unused key, + mach_voucher_attr_key_t __unused key, ipc_voucher_attr_control_t __unused *control) { - if (HOST_NULL == host) + if (HOST_NULL == host) { return KERN_INVALID_HOST; + } #if 1 return KERN_NOT_SUPPORTED; @@ -2547,18 +2560,19 @@ host_register_well_known_mach_voucher_attr_manager( proxy = mvam_alloc(manager); kr = ipc_register_well_known_mach_voucher_attr_manager(&proxy->mvam_manager, - default_value, - key, - control); - if (KERN_SUCCESS != kr) + default_value, + key, + control); + if (KERN_SUCCESS != kr) { mvam_release(proxy); + } return kr; #endif } /* - * Routine: host_register_mach_voucher_attr_manager + * Routine: host_register_mach_voucher_attr_manager * Purpose: * Register the user-space resource manager and return a * dynamically allocated key. @@ -2569,33 +2583,300 @@ host_register_well_known_mach_voucher_attr_manager( */ kern_return_t host_register_mach_voucher_attr_manager( - host_t host, + host_t host, mach_voucher_attr_manager_t __unused manager, mach_voucher_attr_value_handle_t __unused default_value, - mach_voucher_attr_key_t __unused *key, + mach_voucher_attr_key_t __unused *key, ipc_voucher_attr_control_t __unused *control) { - if (HOST_NULL == host) + if (HOST_NULL == host) { return KERN_INVALID_HOST; + } return KERN_NOT_SUPPORTED; } +/* + * Routine: ipc_get_pthpriority_from_kmsg_voucher + * Purpose: + * Get the canonicalized pthread priority from the voucher attached in the kmsg. + */ +kern_return_t +ipc_get_pthpriority_from_kmsg_voucher( + ipc_kmsg_t kmsg, + ipc_pthread_priority_value_t *canonicalize_priority_value) +{ + ipc_voucher_t pthread_priority_voucher; + mach_voucher_attr_raw_recipe_size_t content_size = + sizeof(mach_voucher_attr_recipe_data_t) + sizeof(ipc_pthread_priority_value_t); + uint8_t content_data[content_size]; + mach_voucher_attr_recipe_t cur_content; + kern_return_t kr = KERN_SUCCESS; + + if (!IP_VALID(kmsg->ikm_voucher)) { + return KERN_FAILURE; + } + + pthread_priority_voucher = ip_get_voucher(kmsg->ikm_voucher); + kr = mach_voucher_extract_attr_recipe(pthread_priority_voucher, + MACH_VOUCHER_ATTR_KEY_PTHPRIORITY, + content_data, + &content_size); + if (kr != KERN_SUCCESS) { + return kr; + } + + /* return KERN_INVALID_VALUE for default value */ + if (content_size < sizeof(mach_voucher_attr_recipe_t)) { + return KERN_INVALID_VALUE; + } + + cur_content = (mach_voucher_attr_recipe_t) (void *) &content_data[0]; + assert(cur_content->content_size == sizeof(ipc_pthread_priority_value_t)); + memcpy(canonicalize_priority_value, cur_content->content, sizeof(ipc_pthread_priority_value_t)); + + return KERN_SUCCESS; +} + + +/* + * Routine: ipc_voucher_send_preprocessing + * Purpose: + * Processing of the voucher in the kmsg before sending it. + * Currently use to switch PERSONA_TOKEN in case of process with + * no com.apple.private.personas.propagate entitlement. + */ +void +ipc_voucher_send_preprocessing(ipc_kmsg_t kmsg) +{ + uint8_t recipes[(MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN + 1) * sizeof(ipc_voucher_attr_recipe_data_t)]; + ipc_voucher_attr_raw_recipe_array_size_t recipe_size = (MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN + 1) * + sizeof(ipc_voucher_attr_recipe_data_t); + ipc_voucher_t pre_processed_voucher; + ipc_voucher_t voucher_to_send; + kern_return_t kr; + int need_preprocessing = FALSE; + + if (!IP_VALID(kmsg->ikm_voucher) || current_task() == kernel_task) { + return; + } + + /* setup recipe for preprocessing of all the attributes. */ + pre_processed_voucher = ip_get_voucher(kmsg->ikm_voucher); + + kr = ipc_voucher_prepare_processing_recipe(pre_processed_voucher, + (mach_voucher_attr_raw_recipe_array_t)recipes, + &recipe_size, MACH_VOUCHER_ATTR_SEND_PREPROCESS, + IVAM_FLAGS_SUPPORT_SEND_PREPROCESS, &need_preprocessing); + + assert(KERN_SUCCESS == kr); + /* + * Only do send preprocessing if the voucher needs any pre processing. + */ + if (need_preprocessing) { + kr = ipc_create_mach_voucher(recipes, + recipe_size, + &voucher_to_send); + assert(KERN_SUCCESS == kr); + ipc_port_release_send(kmsg->ikm_voucher); + kmsg->ikm_voucher = convert_voucher_to_port(voucher_to_send); + } +} + +/* + * Routine: ipc_voucher_receive_postprocessing + * Purpose: + * Redeems the voucher attached to the kmsg. + * Note: + * Although it is possible to call ipc_importance_receive + * here, it is called in mach_msg_receive_results and not here + * in order to maintain symmetry with ipc_voucher_send_preprocessing. + */ +void +ipc_voucher_receive_postprocessing( + ipc_kmsg_t kmsg, + mach_msg_option_t option) +{ + uint8_t recipes[(MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN + 1) * sizeof(ipc_voucher_attr_recipe_data_t)]; + ipc_voucher_attr_raw_recipe_array_size_t recipe_size = (MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN + 1) * + sizeof(ipc_voucher_attr_recipe_data_t); + ipc_voucher_t recv_voucher; + ipc_voucher_t sent_voucher; + kern_return_t kr; + int need_postprocessing = FALSE; + + if ((option & MACH_RCV_VOUCHER) == 0 || (!IP_VALID(kmsg->ikm_voucher)) || + current_task() == kernel_task) { + return; + } + + /* setup recipe for auto redeem of all the attributes. */ + sent_voucher = ip_get_voucher(kmsg->ikm_voucher); + + kr = ipc_voucher_prepare_processing_recipe(sent_voucher, + (mach_voucher_attr_raw_recipe_array_t)recipes, + &recipe_size, MACH_VOUCHER_ATTR_AUTO_REDEEM, + IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS, &need_postprocessing); + + assert(KERN_SUCCESS == kr); + + /* + * Only do receive postprocessing if the voucher needs any post processing. + */ + if (need_postprocessing) { + kr = ipc_create_mach_voucher(recipes, + recipe_size, + &recv_voucher); + assert(KERN_SUCCESS == kr); + /* swap the voucher port (and set voucher bits in case it didn't already exist) */ + kmsg->ikm_header->msgh_bits |= (MACH_MSG_TYPE_MOVE_SEND << 16); + ipc_port_release_send(kmsg->ikm_voucher); + kmsg->ikm_voucher = convert_voucher_to_port(recv_voucher); + } +} + +/* + * Routine: ipc_voucher_prepare_processing_recipe + * Purpose: + * Check if the given voucher has an attribute which supports + * the given flag and prepare a recipe to apply that supported + * command. + */ +static kern_return_t +ipc_voucher_prepare_processing_recipe( + ipc_voucher_t voucher, + ipc_voucher_attr_raw_recipe_array_t recipes, + ipc_voucher_attr_raw_recipe_array_size_t *in_out_size, + mach_voucher_attr_recipe_command_t command, + ipc_voucher_attr_manager_flags flags, + int *need_processing) +{ + ipc_voucher_attr_raw_recipe_array_size_t recipe_size = *in_out_size; + ipc_voucher_attr_raw_recipe_array_size_t recipe_used = 0; + iv_index_t key_index; + ipc_voucher_attr_recipe_t recipe; + + if (IV_NULL == voucher) { + return KERN_INVALID_ARGUMENT; + } + + /* Setup a recipe to copy all attributes. */ + if (recipe_size < sizeof(*recipe)) { + return KERN_NO_SPACE; + } + + *need_processing = FALSE; + recipe = (ipc_voucher_attr_recipe_t)(void *)&recipes[recipe_used]; + recipe->key = MACH_VOUCHER_ATTR_KEY_ALL; + recipe->command = MACH_VOUCHER_ATTR_COPY; + recipe->previous_voucher = voucher; + recipe->content_size = 0; + recipe_used += sizeof(*recipe) + recipe->content_size; + + for (key_index = 0; key_index < voucher->iv_table_size; key_index++) { + ipc_voucher_attr_manager_t manager; + mach_voucher_attr_key_t key; + iv_index_t value_index; + + /* don't output anything for a default value */ + value_index = iv_lookup(voucher, key_index); + if (IV_UNUSED_VALINDEX == value_index) { + continue; + } + + if (recipe_size - recipe_used < sizeof(*recipe)) { + return KERN_NO_SPACE; + } + + recipe = (ipc_voucher_attr_recipe_t)(void *)&recipes[recipe_used]; + + /* + * Get the manager for this key_index. The + * existence of a non-default value for this + * slot within our voucher will keep the + * manager referenced during the callout. + */ + ivgt_lookup(key_index, FALSE, &manager, NULL); + assert(IVAM_NULL != manager); + if (IVAM_NULL == manager) { + continue; + } + + /* Check if the supported flag is set in the manager */ + if ((manager->ivam_flags & flags) == 0) { + continue; + } + + key = iv_index_to_key(key_index); + + recipe->key = key; + recipe->command = command; + recipe->content_size = 0; + recipe->previous_voucher = voucher; + + recipe_used += sizeof(*recipe) + recipe->content_size; + *need_processing = TRUE; + } + + *in_out_size = recipe_used; + return KERN_SUCCESS; +} + +/* + * Activity id Generation + */ +uint64_t voucher_activity_id; + +#define generate_activity_id(x) \ + ((uint64_t)OSAddAtomic64((x), (int64_t *)&voucher_activity_id)) + +/* + * Routine: mach_init_activity_id + * Purpose: + * Initialize voucher activity id. + */ +void +mach_init_activity_id(void) +{ + voucher_activity_id = 1; +} + +/* + * Routine: mach_generate_activity_id + * Purpose: + * Generate a system wide voucher activity id. + */ +kern_return_t +mach_generate_activity_id( + struct mach_generate_activity_id_args *args) +{ + uint64_t activity_id; + kern_return_t kr = KERN_SUCCESS; + + if (args->count <= 0 || args->count > MACH_ACTIVITY_ID_COUNT_MAX) { + return KERN_INVALID_ARGUMENT; + } + + activity_id = generate_activity_id(args->count); + kr = copyout(&activity_id, args->activity_id, sizeof(activity_id)); + + return kr; +} #if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) || defined(MACH_VOUCHER_ATTR_KEY_TEST) /* * Build-in a simple User Data Resource Manager */ -#define USER_DATA_MAX_DATA (16*1024) +#define USER_DATA_MAX_DATA (16*1024) struct user_data_value_element { - mach_voucher_attr_value_reference_t e_made; - mach_voucher_attr_content_size_t e_size; - iv_index_t e_sum; - iv_index_t e_hash; - queue_chain_t e_hash_link; - uint8_t e_data[]; + mach_voucher_attr_value_reference_t e_made; + mach_voucher_attr_content_size_t e_size; + iv_index_t e_sum; + iv_index_t e_hash; + queue_chain_t e_hash_link; + uint8_t e_data[]; }; typedef struct user_data_value_element *user_data_element_t; @@ -2607,78 +2888,78 @@ typedef struct user_data_value_element *user_data_element_t; #define USER_DATA_HASH_BUCKET(x) ((x) % USER_DATA_HASH_BUCKETS) static queue_head_t user_data_bucket[USER_DATA_HASH_BUCKETS]; -static lck_spin_t user_data_lock_data; +static LCK_SPIN_DECLARE_ATTR(user_data_lock_data, &ipc_lck_grp, &ipc_lck_attr); -#define user_data_lock_init() \ - lck_spin_init(&user_data_lock_data, &ipc_lck_grp, &ipc_lck_attr) #define user_data_lock_destroy() \ lck_spin_destroy(&user_data_lock_data, &ipc_lck_grp) -#define user_data_lock() \ - lck_spin_lock(&user_data_lock_data) -#define user_data_lock_try() \ - lck_spin_try_lock(&user_data_lock_data) -#define user_data_unlock() \ +#define user_data_lock() \ + lck_spin_lock_grp(&user_data_lock_data, &ipc_lck_grp) +#define user_data_lock_try() \ + lck_spin_try_lock_grp(&user_data_lock_data, &ipc_lck_grp) +#define user_data_unlock() \ lck_spin_unlock(&user_data_lock_data) static kern_return_t user_data_release_value( - ipc_voucher_attr_manager_t manager, - mach_voucher_attr_key_t key, - mach_voucher_attr_value_handle_t value, - mach_voucher_attr_value_reference_t sync); + ipc_voucher_attr_manager_t manager, + mach_voucher_attr_key_t key, + mach_voucher_attr_value_handle_t value, + mach_voucher_attr_value_reference_t sync); static kern_return_t user_data_get_value( - ipc_voucher_attr_manager_t manager, - mach_voucher_attr_key_t key, - mach_voucher_attr_recipe_command_t command, - mach_voucher_attr_value_handle_array_t prev_values, - mach_voucher_attr_value_handle_array_size_t prev_value_count, - mach_voucher_attr_content_t content, - mach_voucher_attr_content_size_t content_size, - mach_voucher_attr_value_handle_t *out_value, - ipc_voucher_t *out_value_voucher); + ipc_voucher_attr_manager_t manager, + mach_voucher_attr_key_t key, + mach_voucher_attr_recipe_command_t command, + mach_voucher_attr_value_handle_array_t prev_values, + mach_voucher_attr_value_handle_array_size_t prev_value_count, + mach_voucher_attr_content_t content, + mach_voucher_attr_content_size_t content_size, + mach_voucher_attr_value_handle_t *out_value, + mach_voucher_attr_value_flags_t *out_flags, + ipc_voucher_t *out_value_voucher); static kern_return_t user_data_extract_content( - ipc_voucher_attr_manager_t manager, - mach_voucher_attr_key_t key, - mach_voucher_attr_value_handle_array_t values, - mach_voucher_attr_value_handle_array_size_t value_count, - mach_voucher_attr_recipe_command_t *out_command, - mach_voucher_attr_content_t out_content, - mach_voucher_attr_content_size_t *in_out_content_size); + ipc_voucher_attr_manager_t manager, + mach_voucher_attr_key_t key, + mach_voucher_attr_value_handle_array_t values, + mach_voucher_attr_value_handle_array_size_t value_count, + mach_voucher_attr_recipe_command_t *out_command, + mach_voucher_attr_content_t out_content, + mach_voucher_attr_content_size_t *in_out_content_size); static kern_return_t user_data_command( - ipc_voucher_attr_manager_t manager, - mach_voucher_attr_key_t key, - mach_voucher_attr_value_handle_array_t values, - mach_msg_type_number_t value_count, - mach_voucher_attr_command_t command, - mach_voucher_attr_content_t in_content, - mach_voucher_attr_content_size_t in_content_size, - mach_voucher_attr_content_t out_content, - mach_voucher_attr_content_size_t *out_content_size); + ipc_voucher_attr_manager_t manager, + mach_voucher_attr_key_t key, + mach_voucher_attr_value_handle_array_t values, + mach_msg_type_number_t value_count, + mach_voucher_attr_command_t command, + mach_voucher_attr_content_t in_content, + mach_voucher_attr_content_size_t in_content_size, + mach_voucher_attr_content_t out_content, + mach_voucher_attr_content_size_t *out_content_size); static void user_data_release( - ipc_voucher_attr_manager_t manager); - -struct ipc_voucher_attr_manager user_data_manager = { - .ivam_release_value = user_data_release_value, - .ivam_get_value = user_data_get_value, - .ivam_extract_content = user_data_extract_content, - .ivam_command = user_data_command, - .ivam_release = user_data_release, + ipc_voucher_attr_manager_t manager); + +const struct ipc_voucher_attr_manager user_data_manager = { + .ivam_release_value = user_data_release_value, + .ivam_get_value = user_data_get_value, + .ivam_extract_content = user_data_extract_content, + .ivam_command = user_data_command, + .ivam_release = user_data_release, + .ivam_flags = IVAM_FLAGS_NONE, }; ipc_voucher_attr_control_t user_data_control; ipc_voucher_attr_control_t test_control; #if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) && defined(MACH_VOUCHER_ATTR_KEY_TEST) -#define USER_DATA_ASSERT_KEY(key) \ - assert(MACH_VOUCHER_ATTR_KEY_USER_DATA == (key) || \ +#define USER_DATA_ASSERT_KEY(key) \ + assert(MACH_VOUCHER_ATTR_KEY_USER_DATA == (key) || \ MACH_VOUCHER_ATTR_KEY_TEST == (key)); #elif defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) #define USER_DATA_ASSERT_KEY(key) assert(MACH_VOUCHER_ATTR_KEY_USER_DATA == (key)) @@ -2687,7 +2968,7 @@ ipc_voucher_attr_control_t test_control; #endif /* - * Routine: user_data_release_value + * Routine: user_data_release_value * Purpose: * Release a made reference on a specific value managed by * this voucher attribute manager. @@ -2697,15 +2978,15 @@ ipc_voucher_attr_control_t test_control; */ static kern_return_t user_data_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) + 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) { user_data_element_t elem; iv_index_t hash; - assert (&user_data_manager == manager); + assert(&user_data_manager == manager); USER_DATA_ASSERT_KEY(key); elem = (user_data_element_t)value; @@ -2725,28 +3006,28 @@ user_data_release_value( } /* - * Routine: user_data_checksum + * Routine: user_data_checksum * Purpose: * Provide a rudimentary checksum for the data presented * to these voucher attribute managers. */ static iv_index_t user_data_checksum( - mach_voucher_attr_content_t content, - mach_voucher_attr_content_size_t content_size) + mach_voucher_attr_content_t content, + mach_voucher_attr_content_size_t content_size) { mach_voucher_attr_content_size_t i; iv_index_t cksum = 0; - for(i = 0; i < content_size; i++, content++) { + for (i = 0; i < content_size; i++, content++) { cksum = (cksum << 8) ^ (cksum + *(unsigned char *)content); } - return (~cksum); + return ~cksum; } /* - * Routine: user_data_dedup + * Routine: user_data_dedup * Purpose: * See if the content represented by this request already exists * in another user data element. If so return a made reference @@ -2759,10 +3040,10 @@ user_data_checksum( */ static user_data_element_t user_data_dedup( - mach_voucher_attr_content_t content, - mach_voucher_attr_content_size_t content_size) + mach_voucher_attr_content_t content, + mach_voucher_attr_content_size_t content_size) { - iv_index_t sum; + iv_index_t sum; iv_index_t hash; user_data_element_t elem; user_data_element_t alloc = NULL; @@ -2770,7 +3051,7 @@ user_data_dedup( sum = user_data_checksum(content, content_size); hash = USER_DATA_HASH_BUCKET(sum); - retry: +retry: user_data_lock(); queue_iterate(&user_data_bucket[hash], elem, user_data_element_t, e_hash_link) { assert(elem->e_hash == hash); @@ -2780,19 +3061,23 @@ user_data_dedup( iv_index_t i; /* and all data matches */ - for (i = 0; i < content_size; i++) - if (elem->e_data[i] != content[i]) + for (i = 0; i < content_size; i++) { + if (elem->e_data[i] != content[i]) { break; - if (i < content_size) + } + } + if (i < content_size) { continue; + } /* ... we found a match... */ elem->e_made++; user_data_unlock(); - if (NULL != alloc) + if (NULL != alloc) { kfree(alloc, sizeof(*alloc) + content_size); + } return elem; } @@ -2818,34 +3103,39 @@ user_data_dedup( static kern_return_t user_data_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_voucher_attr_value_handle_array_size_t prev_value_count, - mach_voucher_attr_content_t content, - mach_voucher_attr_content_size_t content_size, - mach_voucher_attr_value_handle_t *out_value, - ipc_voucher_t *out_value_voucher) + 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_voucher_attr_value_handle_array_size_t prev_value_count, + mach_voucher_attr_content_t content, + mach_voucher_attr_content_size_t content_size, + mach_voucher_attr_value_handle_t *out_value, + mach_voucher_attr_value_flags_t *out_flags, + ipc_voucher_t *out_value_voucher) { user_data_element_t elem; - assert (&user_data_manager == manager); + assert(&user_data_manager == manager); USER_DATA_ASSERT_KEY(key); /* never an out voucher */ *out_value_voucher = IPC_VOUCHER_NULL; + *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE; switch (command) { - case MACH_VOUCHER_ATTR_REDEEM: /* redeem of previous values is the value */ if (0 < prev_value_count) { elem = (user_data_element_t)prev_values[0]; + + user_data_lock(); assert(0 < elem->e_made); elem->e_made++; - *out_value = prev_values[0]; + user_data_unlock(); + + *out_value = (mach_voucher_attr_value_handle_t)elem; return KERN_SUCCESS; } @@ -2854,8 +3144,9 @@ user_data_get_value( return KERN_SUCCESS; case MACH_VOUCHER_ATTR_USER_DATA_STORE: - if (USER_DATA_MAX_DATA < content_size) + if (USER_DATA_MAX_DATA < content_size) { return KERN_RESOURCE_SHORTAGE; + } /* empty is the default */ if (0 == content_size) { @@ -2875,28 +3166,29 @@ user_data_get_value( static kern_return_t user_data_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_voucher_attr_value_handle_array_size_t value_count, - mach_voucher_attr_recipe_command_t *out_command, - mach_voucher_attr_content_t out_content, - mach_voucher_attr_content_size_t *in_out_content_size) + 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_voucher_attr_value_handle_array_size_t value_count, + mach_voucher_attr_recipe_command_t *out_command, + mach_voucher_attr_content_t out_content, + mach_voucher_attr_content_size_t *in_out_content_size) { mach_voucher_attr_content_size_t size = 0; user_data_element_t elem; unsigned int i; - assert (&user_data_manager == manager); + assert(&user_data_manager == manager); USER_DATA_ASSERT_KEY(key); /* concatenate the stored data items */ - for (i = 0; i < value_count ; i++) { + for (i = 0; i < value_count && *in_out_content_size > 0; i++) { elem = (user_data_element_t)values[i]; assert(USER_DATA_MAX_DATA >= elem->e_size); - if (size + elem->e_size > *in_out_content_size) + if (size + elem->e_size > *in_out_content_size) { return KERN_NO_SPACE; + } memcpy(&out_content[size], elem->e_data, elem->e_size); size += elem->e_size; @@ -2908,70 +3200,62 @@ user_data_extract_content( static kern_return_t user_data_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) -{ - assert (&user_data_manager == manager); + 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) +{ + assert(&user_data_manager == manager); USER_DATA_ASSERT_KEY(key); return KERN_FAILURE; } static void user_data_release( - ipc_voucher_attr_manager_t manager) + ipc_voucher_attr_manager_t manager) { - if (manager != &user_data_manager) + if (manager != &user_data_manager) { return; + } panic("Voucher user-data manager released"); } -static int user_data_manager_inited = 0; - -void -user_data_attr_manager_init() +__startup_func +static void +user_data_attr_manager_init(void) { kern_return_t kr; -#if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) - if ((user_data_manager_inited & 0x1) != 0x1) { - kr = ipc_register_well_known_mach_voucher_attr_manager(&user_data_manager, - (mach_voucher_attr_value_handle_t)0, - MACH_VOUCHER_ATTR_KEY_USER_DATA, - &user_data_control); - if (KERN_SUCCESS != kr) - printf("Voucher user-data manager register(USER-DATA) returned %d", kr); - else - user_data_manager_inited |= 0x1; +#if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) + kr = ipc_register_well_known_mach_voucher_attr_manager(&user_data_manager, + (mach_voucher_attr_value_handle_t)0, + MACH_VOUCHER_ATTR_KEY_USER_DATA, + &user_data_control); + if (KERN_SUCCESS != kr) { + printf("Voucher user-data manager register(USER-DATA) returned %d", kr); } #endif #if defined(MACH_VOUCHER_ATTR_KEY_TEST) - if ((user_data_manager_inited & 0x2) != 0x2) { - kr = ipc_register_well_known_mach_voucher_attr_manager(&user_data_manager, - (mach_voucher_attr_value_handle_t)0, - MACH_VOUCHER_ATTR_KEY_TEST, - &test_control); - if (KERN_SUCCESS != kr) - printf("Voucher user-data manager register(TEST) returned %d", kr); - else - user_data_manager_inited |= 0x2; + kr = ipc_register_well_known_mach_voucher_attr_manager(&user_data_manager, + (mach_voucher_attr_value_handle_t)0, + MACH_VOUCHER_ATTR_KEY_TEST, + &test_control); + if (KERN_SUCCESS != kr) { + printf("Voucher user-data manager register(TEST) returned %d", kr); } #endif #if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) || defined(MACH_VOUCHER_ATTR_KEY_TEST) - int i; - - for (i=0; i < USER_DATA_HASH_BUCKETS; i++) + for (int i = 0; i < USER_DATA_HASH_BUCKETS; i++) { queue_init(&user_data_bucket[i]); - - user_data_lock_init(); + } #endif } +STARTUP(MACH_IPC, STARTUP_RANK_FIRST, user_data_attr_manager_init); -#endif /* MACH_DEBUG */ +#endif /* MACH_VOUCHER_ATTR_KEY_USER_DATA || MACH_VOUCHER_ATTR_KEY_TEST */