X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..5ba3f43ea354af8ad55bea84372a2bc834d8757c:/osfmk/ipc/mach_msg.c diff --git a/osfmk/ipc/mach_msg.c b/osfmk/ipc/mach_msg.c index b83ef8191..128cd9605 100644 --- a/osfmk/ipc/mach_msg.c +++ b/osfmk/ipc/mach_msg.c @@ -85,13 +85,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include @@ -104,13 +104,14 @@ #include #include #include +#include +#include #include #include #include - #ifndef offsetof #define offsetof(type, member) ((size_t)(&((type *)0)->member)) #endif /* offsetof */ @@ -138,10 +139,20 @@ mach_msg_return_t mach_msg_receive( mach_msg_return_t msg_receive_error( ipc_kmsg_t kmsg, - mach_vm_address_t msg_addr, mach_msg_option_t option, + mach_vm_address_t rcv_addr, + mach_msg_size_t rcv_size, mach_port_seqno_t seqno, - ipc_space_t space); + ipc_space_t space, + mach_msg_size_t *out_size); + +static mach_msg_return_t +mach_msg_rcv_link_special_reply_port( + ipc_port_t special_reply_port, + mach_port_name_t dest_name_port); + +static void +mach_msg_rcv_unlink_special_reply_port(void); security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE; audit_token_t KERNEL_AUDIT_TOKEN = KERNEL_AUDIT_TOKEN_VALUE; @@ -154,9 +165,14 @@ mach_msg_format_0_trailer_t trailer_template = { }; /* - * Routine: mach_msg_send + * Routine: mach_msg_send [Kernel Internal] * Purpose: - * Send a message. + * Routine for kernel-task threads to send a message. + * + * Unlike mach_msg_send_from_kernel(), this routine + * looks port names up in the kernel's port namespace + * and copies in the kernel virtual memory (instead + * of taking a vm_map_copy_t pointer for OOL descriptors). * Conditions: * Nothing locked. * Returns: @@ -180,7 +196,7 @@ mach_msg_send( mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_timeout_t send_timeout, - __unused mach_port_name_t notify) + mach_msg_priority_t override) { ipc_space_t space = current_space(); vm_map_t map = current_map(); @@ -189,19 +205,30 @@ mach_msg_send( mach_msg_size_t msg_and_trailer_size; mach_msg_max_trailer_t *trailer; - if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) + if ((send_size & 3) || + send_size < sizeof(mach_msg_header_t) || + (send_size < sizeof(mach_msg_base_t) && (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX))) return MACH_SEND_MSG_TOO_SMALL; if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) return MACH_SEND_TOO_LARGE; + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; kmsg = ipc_kmsg_alloc(msg_and_trailer_size); - if (kmsg == IKM_NULL) + if (kmsg == IKM_NULL) { + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_SEND_NO_BUFFER); return MACH_SEND_NO_BUFFER; + } + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE, + (uintptr_t)0, /* this should only be called from the kernel! */ + VM_KERNEL_ADDRPERM((uintptr_t)kmsg), + 0, 0, + 0); (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); kmsg->ikm_header->msgh_size = send_size; @@ -217,24 +244,42 @@ mach_msg_send( trailer->msgh_audit = current_thread()->task->audit_token; trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; - - mr = ipc_kmsg_copyin(kmsg, space, map, option & MACH_SEND_NOTIFY); + + mr = ipc_kmsg_copyin(kmsg, space, map, override, &option); + if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } - mr = ipc_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, send_timeout); + mr = ipc_kmsg_send(kmsg, option, send_timeout); + if (mr != MACH_MSG_SUCCESS) { mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, kmsg->ikm_header->msgh_size); ipc_kmsg_free(kmsg); + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } return mr; } +/* + * message header as seen at user-space + * (for MACH_RCV_LARGE/IDENTITY updating) + */ +typedef struct +{ + mach_msg_bits_t msgh_bits; + mach_msg_size_t msgh_size; + mach_port_name_t msgh_remote_port; + mach_port_name_t msgh_local_port; + mach_msg_size_t msgh_reserved; + mach_msg_id_t msgh_id; +} mach_msg_user_header_t; + /* * Routine: mach_msg_receive_results * Purpose: @@ -257,146 +302,164 @@ mach_msg_send( */ mach_msg_return_t -mach_msg_receive_results(void) +mach_msg_receive_results( + mach_msg_size_t *sizep) { thread_t self = current_thread(); ipc_space_t space = current_space(); - vm_map_t map = current_map(); + vm_map_t map = current_map(); ipc_object_t object = self->ith_object; mach_msg_return_t mr = self->ith_state; - mach_vm_address_t msg_addr = self->ith_msg_addr; + mach_vm_address_t rcv_addr = self->ith_msg_addr; + mach_msg_size_t rcv_size = self->ith_rsize; mach_msg_option_t option = self->ith_option; ipc_kmsg_t kmsg = self->ith_kmsg; mach_port_seqno_t seqno = self->ith_seqno; - mach_msg_max_trailer_t *trailer; + mach_msg_trailer_size_t trailer_size; + mach_msg_size_t size = 0; - ipc_object_release(object); + /* unlink the special_reply_port before releasing reference to object */ + mach_msg_rcv_unlink_special_reply_port(); + io_release(object); if (mr != MACH_MSG_SUCCESS) { - if (mr == MACH_RCV_TOO_LARGE ) { - if (option & MACH_RCV_LARGE) { - /* - * We need to inform the user-level code that it needs more - * space. The value for how much space was returned in the - * msize save area instead of the message (which was left on - * the queue). - */ - if (copyout((char *) &self->ith_msize, - msg_addr + offsetof(mach_msg_header_t, msgh_size), - sizeof(mach_msg_size_t))) - mr = MACH_RCV_INVALID_DATA; - goto out; - } - - if (msg_receive_error(kmsg, msg_addr, option, seqno, space) - == MACH_RCV_INVALID_DATA) - mr = MACH_RCV_INVALID_DATA; - } - goto out; - } - - trailer = (mach_msg_max_trailer_t *) - ((vm_offset_t)kmsg->ikm_header + - round_msg(kmsg->ikm_header->msgh_size)); - if (option & MACH_RCV_TRAILER_MASK) { - trailer->msgh_seqno = seqno; - trailer->msgh_context = - kmsg->ikm_header->msgh_remote_port->ip_context; - trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); - - if (MACH_RCV_TRAILER_ELEMENTS(option) >= - MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV)){ -#if CONFIG_MACF_MACH - if (kmsg->ikm_sender != NULL && - IP_VALID(kmsg->ikm_header->msgh_remote_port) && - mac_port_check_method(kmsg->ikm_sender, - &kmsg->ikm_sender->maclabel, - &kmsg->ikm_header->msgh_remote_port->ip_label, - kmsg->ikm_header->msgh_id) == 0) - trailer->msgh_ad = 1; - else -#endif - trailer->msgh_ad = 0; + if (mr == MACH_RCV_TOO_LARGE) { + + /* + * If the receive operation occurs with MACH_RCV_LARGE set + * then no message was extracted from the queue, and the size + * and (optionally) receiver names were the only thing captured. + * Just copyout the size (and optional port name) in a fake + * header. + */ + if (option & MACH_RCV_LARGE) { + + if ((option & MACH_RCV_STACK) == 0 && + rcv_size >= offsetof(mach_msg_user_header_t, msgh_reserved)) { + + /* + * We need to inform the user-level code that it needs more + * space. The value for how much space was returned in the + * msize save area instead of the message (which was left on + * the queue). + */ + if (option & MACH_RCV_LARGE_IDENTITY) { + if (copyout((char *) &self->ith_receiver_name, + rcv_addr + offsetof(mach_msg_user_header_t, msgh_local_port), + sizeof(mach_port_name_t))) + mr = MACH_RCV_INVALID_DATA; + } + if (copyout((char *) &self->ith_msize, + rcv_addr + offsetof(mach_msg_user_header_t, msgh_size), + sizeof(mach_msg_size_t))) + mr = MACH_RCV_INVALID_DATA; + } + } else { + + /* discard importance in message */ + ipc_importance_clean(kmsg); + + if (msg_receive_error(kmsg, option, rcv_addr, rcv_size, seqno, space, &size) + == MACH_RCV_INVALID_DATA) + mr = MACH_RCV_INVALID_DATA; + } } - /* - * The ipc_kmsg_t holds a reference to the label of a label - * handle, not the port. We must get a reference to the port - * and a send right to copyout to the receiver. - */ - - if (option & MACH_RCV_TRAILER_ELEMENTS (MACH_RCV_TRAILER_LABELS)) { -#if CONFIG_MACF_MACH - if (kmsg->ikm_sender != NULL) { - ipc_labelh_t lh = kmsg->ikm_sender->label; - kern_return_t kr; - - ip_lock(lh->lh_port); - lh->lh_port->ip_mscount++; - lh->lh_port->ip_srights++; - ip_reference(lh->lh_port); - ip_unlock(lh->lh_port); - - kr = ipc_object_copyout(space, (ipc_object_t)lh->lh_port, - MACH_MSG_TYPE_PORT_SEND, 0, - &trailer->msgh_labels.sender); - if (kr != KERN_SUCCESS) { - ip_lock(lh->lh_port); - ip_release(lh->lh_port); - ip_check_unlock(lh->lh_port); - - trailer->msgh_labels.sender = 0; - } - } else { - trailer->msgh_labels.sender = 0; - } -#else - trailer->msgh_labels.sender = 0; -#endif - } + if (sizep) + *sizep = size; + return mr; } - /* - * If MACH_RCV_OVERWRITE was specified, try to get the scatter - * list and verify it against the contents of the message. If - * there is any problem with it, we will continue without it as - * normal. - */ - if (option & MACH_RCV_OVERWRITE) { - mach_msg_size_t slist_size = self->ith_scatter_list_size; - mach_msg_body_t *slist; + /* MACH_MSG_SUCCESS */ - slist = ipc_kmsg_get_scatter(msg_addr, slist_size, kmsg); - mr = ipc_kmsg_copyout(kmsg, space, map, slist); - ipc_kmsg_free_scatter(slist, slist_size); - } else { - mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL); - } +#if IMPORTANCE_INHERITANCE + + /* adopt/transform any importance attributes carried in the message */ + ipc_importance_receive(kmsg, option); + +#endif /* IMPORTANCE_INHERITANCE */ + + /* auto redeem the voucher in the message */ + ipc_voucher_receive_postprocessing(kmsg, option); + + trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, self, seqno, FALSE, + kmsg->ikm_header->msgh_remote_port->ip_context); + + mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL, option); if (mr != MACH_MSG_SUCCESS) { + + /* already received importance, so have to undo that here */ + ipc_importance_unreceive(kmsg, option); + + /* if we had a body error copyout what we have, otherwise a simple header/trailer */ if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { - if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + - trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA) + if (ipc_kmsg_put(kmsg, option, rcv_addr, rcv_size, trailer_size, &size) == MACH_RCV_INVALID_DATA) mr = MACH_RCV_INVALID_DATA; - } - else { - if (msg_receive_error(kmsg, msg_addr, option, seqno, space) + } else { + if (msg_receive_error(kmsg, option, rcv_addr, rcv_size, seqno, space, &size) == MACH_RCV_INVALID_DATA) mr = MACH_RCV_INVALID_DATA; } - goto out; + } else { + /* capture ksmg QoS values to the thread continuation state */ + self->ith_qos = kmsg->ikm_qos; + self->ith_qos_override = kmsg->ikm_qos_override; + mr = ipc_kmsg_put(kmsg, option, rcv_addr, rcv_size, trailer_size, &size); } - mr = ipc_kmsg_put(msg_addr, - kmsg, - kmsg->ikm_header->msgh_size + - trailer->msgh_trailer_size); - out: + + if (sizep) + *sizep = size; return mr; } +#ifndef _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG +#define _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG 0x02000000 /* pthread event manager bit */ +#endif +#ifndef _PTHREAD_PRIORITY_OVERCOMMIT_FLAG +#define _PTHREAD_PRIORITY_OVERCOMMIT_FLAG 0x80000000 /* request overcommit threads */ +#endif +#ifndef _PTHREAD_PRIORITY_QOS_CLASS_MASK +#define _PTHREAD_PRIORITY_QOS_CLASS_MASK 0x003fff00 /* QoS class mask */ +#endif + +/* JMM - this needs to invoke a pthread function to compute this */ +mach_msg_priority_t +mach_msg_priority_combine(mach_msg_priority_t msg_qos, + mach_msg_priority_t recv_qos) +{ + mach_msg_priority_t overcommit; + mach_msg_priority_t no_oc_qos; + mach_msg_priority_t res; + + assert(msg_qos < _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG); + overcommit = recv_qos & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG; + no_oc_qos = recv_qos & ~overcommit; + res = (no_oc_qos > msg_qos) ? no_oc_qos : msg_qos; + res |= overcommit; + + return res; +} +/* + * Routine: mach_msg_receive [Kernel Internal] + * Purpose: + * Routine for kernel-task threads to actively receive a message. + * + * Unlike being dispatched to by ipc_kobject_server() or the + * reply part of mach_msg_rpc_from_kernel(), this routine + * looks up the receive port name in the kernel's port + * namespace and copies out received port rights to that namespace + * as well. Out-of-line memory is copied out the kernel's + * address space (rather than just providing the vm_map_copy_t). + * Conditions: + * Nothing locked. + * Returns: + * MACH_MSG_SUCCESS Received a message. + * See for list of MACH_RCV_XXX errors. + */ mach_msg_return_t mach_msg_receive( mach_msg_header_t *msg, @@ -405,7 +468,7 @@ mach_msg_receive( mach_port_name_t rcv_name, mach_msg_timeout_t rcv_timeout, void (*continuation)(mach_msg_return_t), - mach_msg_size_t slist_size) + __unused mach_msg_size_t slist_size) { thread_t self = current_thread(); ipc_space_t space = current_space(); @@ -421,23 +484,29 @@ mach_msg_receive( self->ith_msg_addr = CAST_DOWN(mach_vm_address_t, msg); self->ith_object = object; - self->ith_msize = rcv_size; + self->ith_rsize = rcv_size; + self->ith_msize = 0; self->ith_option = option; - self->ith_scatter_list_size = slist_size; self->ith_continuation = continuation; + self->ith_knote = ITH_KNOTE_NULL; ipc_mqueue_receive(mqueue, option, rcv_size, rcv_timeout, THREAD_ABORTSAFE); if ((option & MACH_RCV_TIMEOUT) && rcv_timeout == 0) thread_poll_yield(self); - return mach_msg_receive_results(); + return mach_msg_receive_results(NULL); } void mach_msg_receive_continue(void) { + mach_msg_return_t mr; thread_t self = current_thread(); - (*self->ith_continuation)(mach_msg_receive_results()); + if (self->ith_state == MACH_PEEK_READY) + mr = MACH_PEEK_READY; + else + mr = mach_msg_receive_results(NULL); + (*self->ith_continuation)(mr); } @@ -461,34 +530,49 @@ mach_msg_overwrite_trap( mach_msg_size_t rcv_size = args->rcv_size; mach_port_name_t rcv_name = args->rcv_name; mach_msg_timeout_t msg_timeout = args->timeout; - __unused mach_port_name_t notify = args->notify; + mach_msg_priority_t override = args->override; mach_vm_address_t rcv_msg_addr = args->rcv_msg; - mach_msg_size_t scatter_list_size = 0; /* NOT INITIALIZED - but not used in pactice */ __unused mach_port_seqno_t temp_seqno = 0; mach_msg_return_t mr = MACH_MSG_SUCCESS; vm_map_t map = current_map(); - + + /* Only accept options allowed by the user */ + option &= MACH_MSG_OPTION_USER; + if (option & MACH_SEND_MSG) { ipc_space_t space = current_space(); ipc_kmsg_t kmsg; + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); + mr = ipc_kmsg_get(msg_addr, send_size, &kmsg); - if (mr != MACH_MSG_SUCCESS) + if (mr != MACH_MSG_SUCCESS) { + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; + } + + KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE, + (uintptr_t)msg_addr, + VM_KERNEL_ADDRPERM((uintptr_t)kmsg), + 0, 0, + 0); + + mr = ipc_kmsg_copyin(kmsg, space, map, override, &option); - mr = ipc_kmsg_copyin(kmsg, space, map, option & MACH_SEND_NOTIFY); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } - mr = ipc_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, msg_timeout); + mr = ipc_kmsg_send(kmsg, option, msg_timeout); if (mr != MACH_MSG_SUCCESS) { mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); - (void) ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size); + (void) ipc_kmsg_put(kmsg, option, msg_addr, send_size, 0, NULL); + KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } @@ -506,34 +590,115 @@ mach_msg_overwrite_trap( } /* hold ref for object */ - /* - * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list - * and receive buffer - * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the - * alternate receive buffer (separate send and receive buffers). - */ - if (option & MACH_RCV_OVERWRITE) - self->ith_msg_addr = rcv_msg_addr; - else if (rcv_msg_addr != (mach_vm_address_t)0) + if ((option & MACH_RCV_SYNC_WAIT) && !(option & MACH_SEND_SYNC_OVERRIDE)) { + ipc_port_t special_reply_port; + __IGNORE_WCASTALIGN(special_reply_port = (ipc_port_t) object); + /* link the special reply port to the destination */ + mr = mach_msg_rcv_link_special_reply_port(special_reply_port, + (mach_port_name_t)override); + if (mr != MACH_MSG_SUCCESS) { + io_release(object); + return mr; + } + } + + if (rcv_msg_addr != (mach_vm_address_t)0) self->ith_msg_addr = rcv_msg_addr; else self->ith_msg_addr = msg_addr; self->ith_object = object; - self->ith_msize = rcv_size; + self->ith_rsize = rcv_size; + self->ith_msize = 0; self->ith_option = option; - self->ith_scatter_list_size = scatter_list_size; self->ith_receiver_name = MACH_PORT_NULL; self->ith_continuation = thread_syscall_return; + self->ith_knote = ITH_KNOTE_NULL; ipc_mqueue_receive(mqueue, option, rcv_size, msg_timeout, THREAD_ABORTSAFE); if ((option & MACH_RCV_TIMEOUT) && msg_timeout == 0) thread_poll_yield(self); - return mach_msg_receive_results(); + return mach_msg_receive_results(NULL); } return MACH_MSG_SUCCESS; } +/* + * Routine: mach_msg_rcv_link_special_reply_port + * Purpose: + * Link the special reply port(rcv right) to the + * other end of the sync ipc channel. + * Conditions: + * Nothing locked. + * Returns: + * None. + */ +static mach_msg_return_t +mach_msg_rcv_link_special_reply_port( + ipc_port_t special_reply_port, + mach_port_name_t dest_name_port) +{ + ipc_port_t dest_port = IP_NULL; + kern_return_t kr; + int qos; + + if (current_thread()->ith_special_reply_port != special_reply_port) { + return MACH_RCV_INVALID_NOTIFY; + } + + /* Copyin the destination port */ + if (!MACH_PORT_VALID(dest_name_port)) { + return MACH_RCV_INVALID_NOTIFY; + } + + kr = ipc_object_copyin(current_space(), + dest_name_port, MACH_MSG_TYPE_COPY_SEND, + (ipc_object_t *) &dest_port); + + /* + * The receive right of dest port might have gone away, + * do not fail the receive in that case. + */ + if (kr == KERN_SUCCESS && IP_VALID(dest_port)) { + + /* Get the effective qos of the thread */ + qos = proc_get_effective_thread_policy(current_thread(), TASK_POLICY_QOS); + + ipc_port_link_special_reply_port_with_qos(special_reply_port, + dest_port, qos); + + /* release the send right */ + ipc_port_release_send(dest_port); + } + return MACH_MSG_SUCCESS; +} + +/* + * Routine: mach_msg_rcv_unlink_special_reply_port + * Purpose: + * Unlink the special reply port to the other end + * of the sync ipc channel. + * Condition: + * Nothing locked. + * Returns: + * None. + */ +static void +mach_msg_rcv_unlink_special_reply_port(void) +{ + thread_t self = current_thread(); + ipc_port_t special_reply_port = self->ith_special_reply_port; + mach_msg_option_t option = self->ith_option; + + if ((special_reply_port == IP_NULL) || + !(option & MACH_RCV_SYNC_WAIT)) { + return; + } + + ipc_port_unlink_special_reply_port(special_reply_port, + IPC_PORT_UNLINK_SR_ALLOW_SYNC_QOS_LINKAGE); +} + /* * Routine: mach_msg_trap [mach trap] * Purpose: @@ -564,6 +729,8 @@ mach_msg_trap( * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error. * Conditions: * Nothing locked. + * size - maximum buffer size on input, + * actual copied-out size on output * Returns: * MACH_MSG_SUCCESS minimal header/trailer copied * MACH_RCV_INVALID_DATA copyout to user buffer failed @@ -572,13 +739,16 @@ mach_msg_trap( mach_msg_return_t msg_receive_error( ipc_kmsg_t kmsg, - mach_vm_address_t msg_addr, mach_msg_option_t option, + mach_vm_address_t rcv_addr, + mach_msg_size_t rcv_size, mach_port_seqno_t seqno, - ipc_space_t space) + ipc_space_t space, + mach_msg_size_t *sizep) { - mach_msg_max_trailer_t *trailer; mach_vm_address_t context; + mach_msg_trailer_size_t trailer_size; + mach_msg_max_trailer_t *trailer; context = kmsg->ikm_header->msgh_remote_port->ip_context; @@ -598,17 +768,17 @@ msg_receive_error( bcopy( (char *)&trailer_template, (char *)trailer, sizeof(trailer_template)); - if (option & MACH_RCV_TRAILER_MASK) { - trailer->msgh_context = context; - trailer->msgh_seqno = seqno; - trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); - } + + trailer_size = ipc_kmsg_add_trailer(kmsg, space, + option, current_thread(), seqno, + TRUE, context); /* - * Copy the message to user space + * Copy the message to user space and return the size + * (note that ipc_kmsg_put may also adjust the actual + * size copied out to user-space). */ - if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size + - trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA) + if (ipc_kmsg_put(kmsg, option, rcv_addr, rcv_size, trailer_size, sizep) == MACH_RCV_INVALID_DATA) return(MACH_RCV_INVALID_DATA); else return(MACH_MSG_SUCCESS);