+ exit_reason->osr_flags |= OS_REASON_FLAG_FROM_USERSPACE;
+
+ /*
+ * Only apply flags that are allowed to be passed from userspace.
+ */
+ exit_reason->osr_flags |= (reason_flags & OS_REASON_FLAG_MASK_ALLOWED_FROM_USER);
+ if ((reason_flags & OS_REASON_FLAG_MASK_ALLOWED_FROM_USER) != reason_flags) {
+ printf("build_userspace_exit_reason: illegal flags passed from userspace (some masked off) 0x%llx, ns: %u, code 0x%llx\n",
+ reason_flags, reason_namespace, reason_code);
+ }
+
+ if (!(exit_reason->osr_flags & OS_REASON_FLAG_NO_CRASH_REPORT)) {
+ exit_reason->osr_flags |= OS_REASON_FLAG_GENERATE_CRASH_REPORT;
+ }
+
+ if (payload != USER_ADDR_NULL) {
+ if (payload_size == 0) {
+ printf("build_userspace_exit_reason: exit reason with namespace %u, nonzero payload but zero length\n",
+ reason_namespace);
+ exit_reason->osr_flags |= OS_REASON_FLAG_BAD_PARAMS;
+ payload = USER_ADDR_NULL;
+ } else {
+ num_items_to_copy++;
+
+ if (payload_size > EXIT_REASON_PAYLOAD_MAX_LEN) {
+ exit_reason->osr_flags |= OS_REASON_FLAG_PAYLOAD_TRUNCATED;
+ payload_size = EXIT_REASON_PAYLOAD_MAX_LEN;
+ }
+
+ user_data_to_copy += payload_size;
+ }
+ }
+
+ if (reason_string != USER_ADDR_NULL) {
+ reason_user_desc = kheap_alloc(KHEAP_TEMP,
+ EXIT_REASON_USER_DESC_MAX_LEN, Z_WAITOK);
+
+ if (reason_user_desc != NULL) {
+ error = copyinstr(reason_string, (void *) reason_user_desc,
+ EXIT_REASON_USER_DESC_MAX_LEN, &reason_user_desc_len);
+
+ if (error == 0) {
+ num_items_to_copy++;
+ user_data_to_copy += reason_user_desc_len;
+ } else if (error == ENAMETOOLONG) {
+ num_items_to_copy++;
+ reason_user_desc[EXIT_REASON_USER_DESC_MAX_LEN - 1] = '\0';
+ user_data_to_copy += reason_user_desc_len;
+ } else {
+ exit_reason->osr_flags |= OS_REASON_FLAG_FAILED_DATA_COPYIN;
+ kheap_free(KHEAP_TEMP, reason_user_desc,
+ EXIT_REASON_USER_DESC_MAX_LEN);
+ reason_user_desc = NULL;
+ reason_user_desc_len = 0;
+ }
+ }
+ }
+
+ if (num_items_to_copy != 0) {
+ uint32_t reason_buffer_size_estimate = 0;
+ mach_vm_address_t data_addr = 0;
+
+ reason_buffer_size_estimate = kcdata_estimate_required_buffer_size(num_items_to_copy, user_data_to_copy);
+
+ error = os_reason_alloc_buffer(exit_reason, reason_buffer_size_estimate);
+ if (error != 0) {
+ printf("build_userspace_exit_reason: failed to allocate signal reason buffer\n");
+ goto out_failed_copyin;
+ }
+
+ if (reason_user_desc != NULL && reason_user_desc_len != 0) {
+ if (KERN_SUCCESS == kcdata_get_memory_addr(&exit_reason->osr_kcd_descriptor,
+ EXIT_REASON_USER_DESC,
+ (uint32_t)reason_user_desc_len,
+ &data_addr)) {
+ kcdata_memcpy(&exit_reason->osr_kcd_descriptor, (mach_vm_address_t) data_addr,
+ reason_user_desc, (uint32_t)reason_user_desc_len);
+ } else {
+ printf("build_userspace_exit_reason: failed to allocate space for reason string\n");
+ goto out_failed_copyin;
+ }
+ }
+
+ if (payload != USER_ADDR_NULL) {
+ if (KERN_SUCCESS ==
+ kcdata_get_memory_addr(&exit_reason->osr_kcd_descriptor,
+ EXIT_REASON_USER_PAYLOAD,
+ payload_size,
+ &data_addr)) {
+ error = copyin(payload, (void *) data_addr, payload_size);
+ if (error) {
+ printf("build_userspace_exit_reason: failed to copy in payload data with error %d\n", error);
+ goto out_failed_copyin;
+ }
+ } else {
+ printf("build_userspace_exit_reason: failed to allocate space for payload data\n");
+ goto out_failed_copyin;
+ }
+ }
+ }
+
+ if (reason_user_desc != NULL) {
+ kheap_free(KHEAP_TEMP, reason_user_desc, EXIT_REASON_USER_DESC_MAX_LEN);
+ reason_user_desc = NULL;
+ reason_user_desc_len = 0;
+ }
+
+ return exit_reason;
+
+out_failed_copyin:
+
+ if (reason_user_desc != NULL) {
+ kheap_free(KHEAP_TEMP, reason_user_desc, EXIT_REASON_USER_DESC_MAX_LEN);
+ reason_user_desc = NULL;
+ reason_user_desc_len = 0;
+ }
+
+ exit_reason->osr_flags |= OS_REASON_FLAG_FAILED_DATA_COPYIN;
+ os_reason_alloc_buffer(exit_reason, 0);
+ return exit_reason;
+}