/*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
+/*
+ * NOTICE: This file was modified by McAfee Research in 2004 to introduce
+ * support for mandatory and extensible security protections. This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ * Copyright (c) 2005 SPARTA, Inc.
+ */
/*
*/
/*
#include <ipc/ipc_hash.h>
#include <ipc/ipc_table.h>
+#include <security/mac_mach_internal.h>
+
#include <string.h>
#ifdef ppc
ipc_kmsg_t kmsg;
#if !defined(__LP64__)
- mach_msg_size_t size = msg_and_trailer_size - MAX_TRAILER_SIZE;
-
/*
* LP64support -
* Pad the allocation in case we need to expand the
* forward as we process them than it is to push all the
* data backwards.
*/
- max_expanded_size =
- (size > sizeof(mach_msg_base_t)) ?
- (msg_and_trailer_size + DESC_SIZE_ADJUSTMENT *
- ((size - sizeof(mach_msg_base_t)) /
- (sizeof(mach_msg_ool_descriptor_t))))
- :
- (msg_and_trailer_size);
-#else
- max_expanded_size = msg_and_trailer_size;
+
+ mach_msg_size_t size = msg_and_trailer_size - MAX_TRAILER_SIZE;
+ if (size > sizeof(mach_msg_base_t)) {
+ mach_msg_size_t max_desc = ((size - sizeof(mach_msg_base_t)) /
+ sizeof(mach_msg_ool_descriptor_t)) *
+ DESC_SIZE_ADJUSTMENT;
+ if (msg_and_trailer_size >= MACH_MSG_SIZE_MAX - max_desc)
+ return IKM_NULL;
+ max_expanded_size = msg_and_trailer_size + max_desc;
+ } else
#endif
+ max_expanded_size = msg_and_trailer_size;
- /* round up for ikm_cache */
- if (max_expanded_size < IKM_SAVED_MSG_SIZE)
- max_expanded_size = IKM_SAVED_MSG_SIZE;
+ if (max_expanded_size > ikm_less_overhead(MACH_MSG_SIZE_MAX))
+ return IKM_NULL;
+ else if (max_expanded_size < IKM_SAVED_MSG_SIZE)
+ max_expanded_size = IKM_SAVED_MSG_SIZE; /* round up for ikm_cache */
if (max_expanded_size == IKM_SAVED_MSG_SIZE) {
struct ikm_cache *cache;
max_expanded_size -
msg_and_trailer_size);
}
+
return(kmsg);
}
mach_msg_size_t size = kmsg->ikm_size;
ipc_port_t port;
+#if CONFIG_MACF_MACH
+ if (kmsg->ikm_sender != NULL) {
+ task_deallocate(kmsg->ikm_sender);
+ kmsg->ikm_sender = NULL;
+ }
+#endif
+
/*
* Check to see if the message is bound to the port. If so,
* mark it not in use. If the port isn't already dead, then
prev->ikm_next = next;
}
/* XXX Temporary debug logic */
- assert(kmsg->ikm_next = IKM_BOGUS);
- assert(kmsg->ikm_prev = IKM_BOGUS);
+ assert((kmsg->ikm_next = IKM_BOGUS) == IKM_BOGUS);
+ assert((kmsg->ikm_prev = IKM_BOGUS) == IKM_BOGUS);
}
/*
ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count,
(mach_msg_descriptor_t *)(body + 1));
}
+
+#if CONFIG_MACF_MACH
+ if (kmsg->ikm_sender != NULL) {
+ task_deallocate(kmsg->ikm_sender);
+ kmsg->ikm_sender = NULL;
+ }
+#endif
}
/*
if ((size < sizeof(mach_msg_header_t)) || (size & 3))
return MACH_SEND_MSG_TOO_SMALL;
+ if (size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE)
+ return MACH_SEND_TOO_LARGE;
+
msg_and_trailer_size = size + MAX_TRAILER_SIZE;
kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
(unsigned int)kmsg->ikm_header->msgh_remote_port,
(unsigned int)kmsg->ikm_header->msgh_local_port, 0);
#endif
+
+#if CONFIG_MACF_MACH
+ /* XXX - why do we zero sender labels here instead of in mach_msg()? */
+ task_t cur = current_task();
+ if (cur) {
+ task_reference(cur);
+ kmsg->ikm_sender = cur;
+ } else
+ trailer->msgh_labels.sender = 0;
+#else
+ trailer->msgh_labels.sender = 0;
+#endif
+
*kmsgp = kmsg;
return MACH_MSG_SUCCESS;
}
trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
+ trailer->msgh_labels.sender = 0;
+
+#if CONFIG_MACF_MACH
+ kmsg->ikm_sender = NULL;
+#endif
*kmsgp = kmsg;
return MACH_MSG_SUCCESS;
}
port = (ipc_port_t) kmsg->ikm_header->msgh_remote_port;
assert(IP_VALID(port));
+ if ((option & ~(MACH_SEND_TIMEOUT|MACH_SEND_ALWAYS)) != 0)
+ printf("ipc_kmsg_send: bad option 0x%x\n", option);
+
ip_lock(port);
if (port->ip_receiver == ipc_space_kernel) {
ipc_object_t dest_port, reply_port;
ipc_port_t dest_soright, reply_soright;
ipc_port_t notify_port;
+ ipc_entry_t entry;
if ((mbits != msg->msgh_bits) ||
(!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ||
if (!MACH_PORT_VALID(dest_name))
goto invalid_dest;
- if (notify != MACH_PORT_NULL) {
- ipc_entry_t entry;
+#if CONFIG_MACF_MACH
+ /*
+ * We do the port send check here instead of in ipc_kmsg_send()
+ * because copying the header involves copying the port rights too
+ * and we need to do the send check before anything is actually copied.
+ */
+ entry = ipc_entry_lookup(space, dest_name);
+ if (entry != IE_NULL) {
+ int error = 0;
+ ipc_port_t port = (ipc_port_t) entry->ie_object;
+ if (port == IP_NULL)
+ goto invalid_dest;
+ ip_lock(port);
+ if (ip_active(port)) {
+ task_t self = current_task();
+ tasklabel_lock(self);
+ error = mac_port_check_send(&self->maclabel,
+ &port->ip_label);
+ tasklabel_unlock(self);
+ }
+ ip_unlock(port);
+ if (error != 0)
+ goto invalid_dest;
+ }
+#endif
+ if (notify != MACH_PORT_NULL) {
if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
is_write_unlock(space);
return MACH_SEND_INVALID_NOTIFY;
notify_port = IP_NULL;
if (dest_name == reply_name) {
- ipc_entry_t entry;
mach_port_name_t name = dest_name;
/*
}
}
} else if (!MACH_PORT_VALID(reply_name)) {
- ipc_entry_t entry;
-
/*
* No reply port! This is an easy case
* to make atomic. Just copyin the destination.
user_desc_sizes = (dsc_count <= DESC_COUNT_SMALL) ?
&desc_size_space : kalloc(dsc_count * sizeof(vm_size_t));
if (user_desc_sizes == NULL) {
- ipc_kmsg_clean_partial(kmsg,0,0,0,0);
+ ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
return KERN_RESOURCE_SHORTAGE;
}
}
* physical copies and possible contraction of the descriptors from
* processes with pointers larger than the kernel's.
*/
- daddr = 0;
+ daddr = NULL;
for (i = 0; i < dsc_count; i++) {
daddr = naddr;
if (naddr > (mach_msg_descriptor_t *)
((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size)) {
- ipc_kmsg_clean_partial(kmsg,0,0,0,0);
+ ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
mr = MACH_SEND_MSG_TOO_SMALL;
goto out;
}
/*
* Invalid copy option
*/
- ipc_kmsg_clean_partial(kmsg,0,0,0,0);
+ ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
mr = MACH_SEND_INVALID_TYPE;
goto out;
}
/*
* Per message kernel memory limit exceeded
*/
- ipc_kmsg_clean_partial(kmsg,0,0,0,0);
+ ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
mr = MACH_MSG_VM_KERNEL;
goto out;
}
if (space_needed) {
if (vm_allocate(ipc_kernel_copy_map, &paddr, space_needed, VM_FLAGS_ANYWHERE) !=
KERN_SUCCESS) {
- ipc_kmsg_clean_partial(kmsg,0,0,0,0);
+ ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
mr = MACH_MSG_VM_KERNEL;
goto out;
}
dsc->type = dsc_type;
if (length == 0) {
- dsc->address = 0;
+ dsc->address = NULL;
} else if ((length >= MSG_OOL_SIZE_SMALL) &&
(copy_options == MACH_MSG_PHYSICAL_COPY) && !dealloc) {
dsc->copy = copy_option;
dsc->type = daddr->type.type;
dsc->count = count;
+ dsc->address = NULL; /* for now */
+
+ result_disp = ipc_object_copyin_type(user_disp);
+ dsc->disposition = result_disp;
/* calculate length of data in bytes, rounding up */
length = count * sizeof(mach_port_name_t);
if (length == 0) {
complex = TRUE;
- dsc->address = (void *) 0;
break;
}
(void) mach_vm_deallocate(map, addr, (mach_vm_size_t)length);
}
+ objects = (ipc_object_t *) data;
dsc->address = data;
- result_disp = ipc_object_copyin_type(user_disp);
- dsc->disposition = result_disp;
-
- objects = (ipc_object_t *) data;
-
for ( j = 0; j < count; j++) {
mach_port_name_t port = (mach_port_name_t) objects[j];
ipc_object_t object;
ipc_object_destroy(object, result_disp);
}
kfree(data, length);
+ dsc->address = NULL;
mr = MACH_SEND_INVALID_RIGHT;
break;
}
ipc_port_request_index_t request;
if (!space->is_active) {
+ printf("ipc_kmsg_copyout_header: dead space\n");
is_write_unlock(space);
return (MACH_RCV_HEADER_ERROR|
MACH_MSG_IPC_SPACE);
notify_port = ipc_port_lookup_notify(space,
notify);
if (notify_port == IP_NULL) {
+ printf("ipc_kmsg_copyout_header: no notify port\n");
is_write_unlock(space);
return MACH_RCV_INVALID_NOTIFY;
}
if (kr != KERN_SUCCESS) {
/* space is unlocked */
- if (kr == KERN_RESOURCE_SHORTAGE)
+ if (kr == KERN_RESOURCE_SHORTAGE) {
+ printf("ipc_kmsg_copyout_header: can't grow kernel ipc space\n");
return (MACH_RCV_HEADER_ERROR|
MACH_MSG_IPC_KERNEL);
- else
+ } else {
+ printf("ipc_kmsg_copyout_header: can't grow user ipc space\n");
return (MACH_RCV_HEADER_ERROR|
MACH_MSG_IPC_SPACE);
+ }
}
/* space is locked again; start over */
kr = ipc_port_dngrow(reply, ITS_SIZE_NONE);
/* port is unlocked */
- if (kr != KERN_SUCCESS)
+ if (kr != KERN_SUCCESS) {
+ printf("ipc_kmsg_copyout_header: can't grow kernel ipc space2\n");
return (MACH_RCV_HEADER_ERROR|
MACH_MSG_IPC_KERNEL);
+ }
is_write_lock(space);
continue;
is_read_lock(space);
if (!space->is_active) {
+ printf("ipc_kmsg_copyout_header: dead space2\n");
is_read_unlock(space);
return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
}
/* must check notify even though it won't be used */
if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
+ printf("ipc_kmsg_copyout_header: ipc_entry_lookup failed\n");
is_read_unlock(space);
return MACH_RCV_INVALID_NOTIFY;
}
if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
+ printf("ipc_kmsg_copyout_header: MACH_PORT_TYPE_RECEIVE not set!\n");
is_read_unlock(space);
return MACH_RCV_INVALID_NOTIFY;
}
mach_msg_return_t mr;
mr = ipc_kmsg_copyout_header(kmsg->ikm_header, space, notify);
- if (mr != MACH_MSG_SUCCESS)
+ if (mr != MACH_MSG_SUCCESS) {
+ printf("ipc_kmsg_copyout: ipc_kmsg_copyout_header failed: %d\n", mr);
return mr;
+ }
if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
mr = ipc_kmsg_copyout_body(kmsg, space, map, slist);
}
if (msgh->msgh_local_port) {
- printf("%slocal=0x%x(", needs_comma ? "," : "",
+ printf("%slocal=%p(", needs_comma ? "," : "",
msgh->msgh_local_port);
ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
printf(")\n");