*/
#include <mach/mach_types.h>
+#include <mach/mach_traps.h>
#include <mach/notify.h>
#include <ipc/ipc_types.h>
#include <ipc/ipc_port.h>
#include <mach/mach_voucher_server.h>
#include <mach/mach_voucher_attr_control_server.h>
#include <mach/mach_host_server.h>
+#include <voucher/ipc_pthread_priority_types.h>
/*
* Sysctl variable; enable and disable tracing of voucher contents
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);
+ }
}
/*
ipc_voucher_attr_manager_t *,
ipc_voucher_attr_control_t *);
+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);
#if defined(MACH_VOUCHER_ATTR_KEY_USER_DATA) || defined(MACH_VOUCHER_ATTR_KEY_TEST)
void user_data_attr_manager_init(void);
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;
*/
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--;
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);
+ } 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,
void
ipc_voucher_reference(ipc_voucher_t voucher)
{
- iv_refs_t refs;
-
if (IPC_VOUCHER_NULL == voucher)
return;
- refs = iv_reference(voucher);
- assert(1 < refs);
+ iv_reference(voucher);
}
void
if (IV_NULL == voucher)
return (IP_NULL);
- assert(0 < voucher->iv_refs);
+ assert(os_ref_get_count(&voucher->iv_refs) > 0);
/* create a port if needed */
port = 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; \
#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; \
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;
* 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;
}
ip_unlock(port);
ivac_release(ivac);
+ } else {
+ ip_unlock(port);
}
- ip_unlock(port);
}
/*
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);
+ /* ipc_port_nsrequest unlocks the port */
} else {
/* piggyback on the existing port reference, so consume ours */
ip_unlock(port);
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){
panic("Failed to grow ivac table to size %d\n", new_size);
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);
}
static iv_index_t
ivace_reference_by_value(
ipc_voucher_attr_control_t ivac,
- mach_voucher_attr_value_handle_t value)
+ 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;
/* found it? */
if (index != IV_HASH_END) {
- /* only add reference on non-default value */
- if (IV_UNUSED_VALINDEX != index) {
+ /* only add reference on non-persistent value */
+ if (!ivace->ivace_persist) {
ivace->ivace_refs++;
ivace->ivace_made++;
}
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;
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;
* re-drive the release.
*/
if (ivace->ivace_made != made) {
- assert(made < ivace->ivace_made);
-
if (KERN_SUCCESS == kr)
ivace->ivace_made -= made;
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;
ivam, key, command,
previous_vals, previous_vals_count,
content, content_size,
- &new_value, &new_value_voucher);
+ &new_value, &new_flag, &new_value_voucher);
if (KERN_SUCCESS != kr) {
ivac_release(ivac);
return kr;
* 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);
/*
* 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);
/*
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);
/* 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;
}
#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)];
}
}
- 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 */
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();
* 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
* 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
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
*/
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
* 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 <voucher, key> pair
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);
return KERN_SUCCESS;
}
-
/*
* Routine: mach_voucher_attr_control_create_mach_voucher
* Purpose:
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 = (ipc_voucher_t)kmsg->ikm_voucher->ip_kobject;
+ 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 = (ipc_voucher_t)kmsg->ikm_voucher->ip_kobject;
+
+ 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 = (ipc_voucher_t)kmsg->ikm_voucher->ip_kobject;
+
+ 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)
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
.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;
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;
/* never an out voucher */
*out_value_voucher = IPC_VOUCHER_NULL;
+ *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
switch (command) {