/*
- * Copyright (c) 2000 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-2006 SPARTA, Inc.
+ */
/*
*/
/*
#include <mach_rt.h>
+#include <mach/mach_types.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/port.h>
#include <mach/message.h>
+
+#include <kern/kern_types.h>
#include <kern/misc_protos.h>
+#include <kern/ipc_kobject.h>
+
+#include <ipc/ipc_types.h>
+#include <ipc/ipc_importance.h>
#include <ipc/port.h>
#include <ipc/ipc_space.h>
#include <ipc/ipc_entry.h>
#include <ipc/ipc_hash.h>
#include <ipc/ipc_right.h>
#include <ipc/ipc_notify.h>
+#include <ipc/ipc_port.h>
#include <ipc/ipc_pset.h>
+#include <security/mac_mach_internal.h>
+
zone_t ipc_object_zones[IOT_NUMBER];
/*
ipc_object_reference(
ipc_object_t object)
{
- io_lock(object);
- assert(object->io_references > 0);
io_reference(object);
- io_unlock(object);
}
/*
ipc_object_release(
ipc_object_t object)
{
- io_lock(object);
- assert(object->io_references > 0);
io_release(object);
- io_check_unlock(object);
}
/*
ipc_entry_t entry;
kern_return_t kr;
- int i;
-
-
kr = ipc_entry_alloc(space, namep, &entry);
if (kr != KERN_SUCCESS)
return kr;
assert(entry->ie_object == IO_NULL);
entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
-
+ ipc_entry_modified(space, *namep, entry);
is_write_unlock(space);
return KERN_SUCCESS;
}
ipc_entry_t entry;
kern_return_t kr;
- int i;
-
-
kr = ipc_entry_alloc_name(space, name, &entry);
if (kr != KERN_SUCCESS)
return kr;
assert(entry->ie_object == IO_NULL);
entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
-
+ ipc_entry_modified(space, name, entry);
is_write_unlock(space);
return KERN_SUCCESS;
}
* Allocate an object.
* Conditions:
* Nothing locked. If successful, the object is returned locked.
+ * The space is write locked on successful return.
* The caller doesn't get a reference for the object.
* Returns:
* KERN_SUCCESS The object is allocated.
}
io_lock_init(object);
- *namep = (mach_port_name_t)object;
+ *namep = CAST_MACH_PORT_TO_NAME(object);
kr = ipc_entry_alloc(space, namep, &entry);
if (kr != KERN_SUCCESS) {
io_free(otype, object);
entry->ie_bits |= type | urefs;
entry->ie_object = object;
+ ipc_entry_modified(space, *namep, entry);
io_lock(object);
- is_write_unlock(space);
object->io_references = 1; /* for entry, not caller */
object->io_bits = io_makebits(TRUE, otype, 0);
entry->ie_bits |= type | urefs;
entry->ie_object = object;
+ ipc_entry_modified(space, name, entry);
io_lock(object);
is_write_unlock(space);
switch (msgt_name) {
case MACH_MSG_TYPE_MOVE_RECEIVE:
- case MACH_MSG_TYPE_COPY_RECEIVE:
return MACH_MSG_TYPE_PORT_RECEIVE;
case MACH_MSG_TYPE_MOVE_SEND_ONCE:
case MACH_MSG_TYPE_COPY_SEND:
return MACH_MSG_TYPE_PORT_SEND;
+ case MACH_MSG_TYPE_DISPOSE_RECEIVE:
+ case MACH_MSG_TYPE_DISPOSE_SEND:
+ case MACH_MSG_TYPE_DISPOSE_SEND_ONCE:
+ /* fall thru */
default:
return MACH_MSG_TYPE_PORT_NONE;
}
{
ipc_entry_t entry;
ipc_port_t soright;
+ ipc_port_t release_port;
kern_return_t kr;
+ queue_head_t links_data;
+ queue_t links = &links_data;
+ wait_queue_link_t wql;
- int i;
+#if IMPORTANCE_INHERITANCE
+ int assertcnt = 0;
+#endif
+
+ queue_init(links);
/*
* Could first try a read lock when doing
return kr;
/* space is write-locked and active */
+ release_port = IP_NULL;
kr = ipc_right_copyin(space, name, entry,
msgt_name, TRUE,
- objectp, &soright);
+ objectp, &soright,
+ &release_port,
+#if IMPORTANCE_INHERITANCE
+ &assertcnt,
+#endif /* IMPORTANCE_INHERITANCE */
+ links);
if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
ipc_entry_dealloc(space, name, entry);
is_write_unlock(space);
+ while(!queue_empty(links)) {
+ wql = (wait_queue_link_t) dequeue(links);
+ wait_queue_link_free(wql);
+ }
+
+#if IMPORTANCE_INHERITANCE
+ if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
+ ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt);
+ }
+#endif /* IMPORTANCE_INHERITANCE */
+
+ if (release_port != IP_NULL)
+ ip_release(release_port);
+
if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
ipc_notify_port_deleted(soright, name);
* Copyin a naked capability from the kernel.
*
* MACH_MSG_TYPE_MOVE_RECEIVE
- * The receiver must be ipc_space_kernel.
+ * The receiver must be ipc_space_kernel
+ * or the receive right must already be in limbo.
* Consumes the naked receive right.
* MACH_MSG_TYPE_COPY_SEND
* A naked send right must be supplied.
ip_lock(port);
assert(ip_active(port));
- assert(port->ip_receiver_name != MACH_PORT_NULL);
- assert(port->ip_receiver == ipc_space_kernel);
+ if (port->ip_destination != IP_NULL) {
+ assert(port->ip_receiver == ipc_space_kernel);
- /* relevant part of ipc_port_clear_receiver */
- ipc_port_set_mscount(port, 0);
+ /* relevant part of ipc_port_clear_receiver */
+ ipc_port_set_mscount(port, 0);
- port->ip_receiver_name = MACH_PORT_NULL;
- port->ip_destination = IP_NULL;
+ port->ip_receiver_name = MACH_PORT_NULL;
+ port->ip_destination = IP_NULL;
+ }
ip_unlock(port);
break;
}
ipc_port_t port = (ipc_port_t) object;
ip_lock(port);
- assert(ip_active(port));
- assert(port->ip_receiver_name != MACH_PORT_NULL);
- assert(port->ip_receiver == ipc_space_kernel);
+ if (ip_active(port)) {
+ assert(port->ip_receiver_name != MACH_PORT_NULL);
+ assert(port->ip_receiver == ipc_space_kernel);
+ port->ip_mscount++;
+ }
- ip_reference(port);
- port->ip_mscount++;
port->ip_srights++;
+ ip_reference(port);
ip_unlock(port);
break;
}
- case MACH_MSG_TYPE_MOVE_SEND:
+ case MACH_MSG_TYPE_MOVE_SEND: {
/* move naked send right into the message */
+ assert(((ipc_port_t)object)->ip_srights);
break;
+ }
case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
ipc_port_t port = (ipc_port_t) object;
ip_lock(port);
- assert(ip_active(port));
- assert(port->ip_receiver_name != MACH_PORT_NULL);
-
- ip_reference(port);
+ if (ip_active(port)) {
+ assert(port->ip_receiver_name != MACH_PORT_NULL);
+ }
port->ip_sorights++;
+ ip_reference(port);
ip_unlock(port);
break;
}
- case MACH_MSG_TYPE_MOVE_SEND_ONCE:
+ case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
/* move naked send-once right into the message */
+ assert(((ipc_port_t)object)->ip_sorights);
break;
+ }
default:
panic("ipc_object_copyin_from_kernel: strange rights");
}
}
+/*
+ * Routine: ipc_object_destroy_dest
+ * Purpose:
+ * Destroys a naked capability for the destination of
+ * of a message. Consumes a ref for the object.
+ *
+ * Conditions:
+ * Nothing locked.
+ */
+
+void
+ipc_object_destroy_dest(
+ ipc_object_t object,
+ mach_msg_type_name_t msgt_name)
+{
+ assert(IO_VALID(object));
+ assert(io_otype(object) == IOT_PORT);
+
+ switch (msgt_name) {
+ case MACH_MSG_TYPE_PORT_SEND:
+ ipc_port_release_send((ipc_port_t) object);
+ break;
+
+ case MACH_MSG_TYPE_PORT_SEND_ONCE:
+ if (io_active(object) &&
+ !ip_full_kernel((ipc_port_t) object))
+ ipc_notify_send_once((ipc_port_t) object);
+ else
+ ipc_port_release_sonce((ipc_port_t) object);
+ break;
+
+ default:
+ panic("ipc_object_destroy_dest: strange rights");
+ }
+}
+
/*
* Routine: ipc_object_copyout
* Purpose:
is_write_lock(space);
for (;;) {
- if (!space->is_active) {
+ if (!is_active(space)) {
is_write_unlock(space);
return KERN_INVALID_TASK;
}
break;
}
- name = (mach_port_name_t)object;
+ name = CAST_MACH_PORT_TO_NAME(object);
kr = ipc_entry_get(space, &name, &entry);
if (kr != KERN_SUCCESS) {
/* unlocks/locks space, so must start again */
kr = ipc_right_copyout(space, name, entry,
msgt_name, overflow, object);
+
/* object is unlocked */
is_write_unlock(space);
ipc_entry_t entry;
kern_return_t kr;
- int i;
+#if IMPORTANCE_INHERITANCE
+ int assertcnt = 0;
+ ipc_importance_task_t task_imp = IIT_NULL;
+#endif /* IMPORTANCE_INHERITANCE */
assert(IO_VALID(object));
assert(io_otype(object) == IOT_PORT);
/* space is write-locked and active, object is locked and active */
+#if IMPORTANCE_INHERITANCE
+ /*
+ * We are slamming a receive right into the space, without
+ * first having been enqueued on a port destined there. So,
+ * we have to arrange to boost the task appropriately if this
+ * port has assertions (and the task wants them).
+ */
+ if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) {
+ ipc_port_t port = (ipc_port_t)object;
+
+ if (space->is_task != TASK_NULL) {
+ task_imp = space->is_task->task_imp_base;
+ if (ipc_importance_task_is_any_receiver_type(task_imp)) {
+ assertcnt = port->ip_impcount;
+ ipc_importance_task_reference(task_imp);
+ }
+ }
+
+ /* take port out of limbo */
+ assert(port->ip_tempowner != 0);
+ port->ip_tempowner = 0;
+ }
+
+#endif /* IMPORTANCE_INHERITANCE */
+
kr = ipc_right_copyout(space, name, entry,
msgt_name, overflow, object);
+
/* object is unlocked */
is_write_unlock(space);
+
+#if IMPORTANCE_INHERITANCE
+ /*
+ * Add the assertions to the task that we captured before
+ */
+ if (task_imp != IIT_NULL) {
+ ipc_importance_task_hold_internal_assertion(task_imp, assertcnt);
+ ipc_importance_task_release(task_imp);
+ }
+#endif /* IMPORTANCE_INHERITANCE */
+
return kr;
}
default:
panic("ipc_object_copyout_dest: strange rights");
+ name = MACH_PORT_DEAD;
}
*namep = name;
ipc_entry_t oentry, nentry;
kern_return_t kr;
- int i;
-
kr = ipc_entry_alloc_name(space, nname, &nentry);
if (kr != KERN_SUCCESS)
return kr;
return kr;
}
-#if MACH_ASSERT
/*
* Check whether the object is a port if so, free it. But
* keep track of that fact.
if (otype == IOT_PORT) {
port = (ipc_port_t) object;
-#if MACH_ASSERT
- ipc_port_track_dealloc(port);
-#endif /* MACH_ASSERT */
+ ipc_port_finalize(port);
}
- zfree(ipc_object_zones[otype], (vm_offset_t) object);
-}
-#endif /* MACH_ASSERT */
-
-#include <mach_kdb.h>
-#if MACH_KDB
-
-#include <ddb/db_output.h>
-
-#define printf kdbprintf
-
-/*
- * Routine: ipc_object_print
- * Purpose:
- * Pretty-print an object for kdb.
- */
-
-char *ikot_print_array[IKOT_MAX_TYPE] = {
- "(NONE) ",
- "(THREAD) ",
- "(TASK) ",
- "(HOST) ",
- "(HOST_PRIV) ",
- "(PROCESSOR) ",
- "(PSET) ",
- "(PSET_NAME) ",
- "(TIMER) ",
- "(PAGER_REQUEST) ",
- "(DEVICE) ", /* 10 */
- "(XMM_OBJECT) ",
- "(XMM_PAGER) ",
- "(XMM_KERNEL) ",
- "(XMM_REPLY) ",
- "(NOTDEF 15) ",
- "(NOTDEF 16) ",
- "(HOST_SECURITY) ",
- "(LEDGER) ",
- "(MASTER_DEVICE) ",
- "(ACTIVATION) ", /* 20 */
- "(SUBSYSTEM) ",
- "(IO_DONE_QUEUE) ",
- "(SEMAPHORE) ",
- "(LOCK_SET) ",
- "(CLOCK) ",
- "(CLOCK_CTRL) ", /* 26 */
- "(IOKIT_SPARE) ", /* 27 */
- "(NAMED_MEM_ENTRY) ", /* 28 */
- "(IOKIT_CONNECT) ",
- "(IOKIT_OBJECT) ", /* 30 */
- "(UPL) ",
- /* << new entries here */
- "(UNKNOWN) " /* magic catchall */
-};
-/* Please keep in sync with kern/ipc_kobject.h */
-
-void
-ipc_object_print(
- ipc_object_t object)
-{
- int kotype;
-
- iprintf("%s", io_active(object) ? "active" : "dead");
- printf(", refs=%d", object->io_references);
- printf(", otype=%d", io_otype(object));
- kotype = io_kotype(object);
- if (kotype >= 0 && kotype < IKOT_MAX_TYPE)
- printf(", kotype=%d %s\n", io_kotype(object),
- ikot_print_array[kotype]);
- else
- printf(", kotype=0x%x %s\n", io_kotype(object),
- ikot_print_array[IKOT_UNKNOWN]);
+ io_lock_destroy(object);
+ zfree(ipc_object_zones[otype], object);
}
-
-#endif /* MACH_KDB */