#include <kern/ipc_mig.h>
#include <kern/task.h>
#include <kern/thread.h>
-#include <kern/lock.h>
#include <kern/sched_prim.h>
#include <kern/exception.h>
#include <kern/misc_protos.h>
#include <ipc/ipc_pset.h>
#include <ipc/ipc_space.h>
#include <ipc/ipc_entry.h>
+#include <ipc/ipc_importance.h>
#include <machine/machine_routines.h>
#include <security/mac_mach_internal.h>
#include <sys/kdebug.h>
-
#ifndef offsetof
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif /* offsetof */
};
/*
- * 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:
* MACH_SEND_INVALID_REPLY Can't copyin reply port.
* MACH_SEND_TIMED_OUT Timeout expired without delivery.
* MACH_SEND_INTERRUPTED Delivery interrupted.
- * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
- * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
- * MACH_SEND_NOTIFY_IN_PROGRESS
- * This space has already forced a message to this port.
*/
mach_msg_return_t
mach_msg_option_t option,
mach_msg_size_t send_size,
mach_msg_timeout_t send_timeout,
- mach_port_name_t notify)
+ __unused mach_port_name_t notify)
{
ipc_space_t space = current_space();
vm_map_t map = current_map();
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;
-
- if (option & MACH_SEND_CANCEL) {
- if (notify == MACH_PORT_NULL)
- mr = MACH_SEND_INVALID_NOTIFY;
- else
- mr = ipc_kmsg_copyin(kmsg, space, map, notify);
- } else
- mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
+
+ mr = ipc_kmsg_copyin(kmsg, space, map, &option);
+
if (mr != MACH_MSG_SUCCESS) {
ipc_kmsg_free(kmsg);
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);
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
+ * Routine: mach_msg_receive_results
* Purpose:
* Receive a message.
* Conditions:
{
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_msg_option_t option = self->ith_option;
ipc_kmsg_t kmsg = self->ith_kmsg;
mach_port_seqno_t seqno = self->ith_seqno;
+ mach_msg_trailer_size_t trailer_size;
- mach_msg_max_trailer_t *trailer;
-
- ipc_object_release(object);
+ io_release(object);
if (mr != MACH_MSG_SUCCESS) {
* 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,
+ msg_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,
- msg_addr + offsetof(mach_msg_header_t, msgh_size),
+ msg_addr + offsetof(mach_msg_user_header_t, msgh_size),
sizeof(mach_msg_size_t)))
- mr = MACH_RCV_INVALID_DATA;
- goto out;
+ mr = MACH_RCV_INVALID_DATA;
+ } else {
+
+ /* discard importance in message */
+ ipc_importance_clean(kmsg);
+
+ if (msg_receive_error(kmsg, msg_addr, option, seqno, space)
+ == MACH_RCV_INVALID_DATA)
+ mr = MACH_RCV_INVALID_DATA;
}
-
- if (msg_receive_error(kmsg, msg_addr, option, seqno, space)
- == MACH_RCV_INVALID_DATA)
- mr = MACH_RCV_INVALID_DATA;
}
- goto out;
+ return mr;
}
- 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 IMPORTANCE_INHERITANCE
- /*
- * 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
- }
- }
+ /* adopt/transform any importance attributes carried in the message */
+ ipc_importance_receive(kmsg, option);
- /*
- * 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;
+#endif /* IMPORTANCE_INHERITANCE */
- slist = ipc_kmsg_get_scatter(msg_addr, slist_size, kmsg);
- mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, slist);
- ipc_kmsg_free_scatter(slist, slist_size);
- } else {
- mr = ipc_kmsg_copyout(kmsg, space, map,
- MACH_PORT_NULL, MACH_MSG_BODY_NULL);
- }
+ 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 ((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)
+ trailer_size) == MACH_RCV_INVALID_DATA)
mr = MACH_RCV_INVALID_DATA;
}
else {
== MACH_RCV_INVALID_DATA)
mr = MACH_RCV_INVALID_DATA;
}
- goto out;
+ } else {
+ mr = ipc_kmsg_put(msg_addr,
+ kmsg,
+ kmsg->ikm_header->msgh_size +
+ trailer_size);
}
- mr = ipc_kmsg_put(msg_addr,
- kmsg,
- kmsg->ikm_header->msgh_size +
- trailer->msgh_trailer_size);
- out:
+
return mr;
}
+/*
+ * 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 <mach/message.h> for list of MACH_RCV_XXX errors.
+ */
mach_msg_return_t
mach_msg_receive(
mach_msg_header_t *msg,
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();
self->ith_object = object;
self->ith_msize = rcv_size;
self->ith_option = option;
- self->ith_scatter_list_size = slist_size;
self->ith_continuation = continuation;
ipc_mqueue_receive(mqueue, option, rcv_size, rcv_timeout, THREAD_ABORTSAFE);
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;
- mach_port_name_t notify = args->notify;
+ __unused mach_port_name_t notify = args->notify;
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;
if (mr != MACH_MSG_SUCCESS)
return mr;
- if (option & MACH_SEND_CANCEL) {
- if (notify == MACH_PORT_NULL)
- mr = MACH_SEND_INVALID_NOTIFY;
- else
- mr = ipc_kmsg_copyin(kmsg, space, map, notify);
- } else
- mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
+ mr = ipc_kmsg_copyin(kmsg, space, map, &option);
+
if (mr != MACH_MSG_SUCCESS) {
ipc_kmsg_free(kmsg);
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);
}
/* 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 (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_option = option;
- self->ith_scatter_list_size = scatter_list_size;
self->ith_receiver_name = MACH_PORT_NULL;
self->ith_continuation = thread_syscall_return;
mach_port_seqno_t seqno,
ipc_space_t space)
{
- 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;
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
*/
if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size +
- trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
+ trailer_size) == MACH_RCV_INVALID_DATA)
return(MACH_RCV_INVALID_DATA);
else
return(MACH_MSG_SUCCESS);