X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/ff6e181ae92fc6f1e89841290f461d1f2f9badd9..fe8ab488e9161c46dd9885d58fc52996dc0249ff:/osfmk/ipc/ipc_object.c diff --git a/osfmk/ipc/ipc_object.c b/osfmk/ipc/ipc_object.c index 4c6d260ca..49b7e4690 100644 --- a/osfmk/ipc/ipc_object.c +++ b/osfmk/ipc/ipc_object.c @@ -1,14 +1,19 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * 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. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * 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. + * + * 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 @@ -18,7 +23,7 @@ * 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@ @@ -48,6 +53,13 @@ * 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. + */ /* */ /* @@ -68,8 +80,10 @@ #include #include +#include #include +#include #include #include #include @@ -77,8 +91,11 @@ #include #include #include +#include #include +#include + zone_t ipc_object_zones[IOT_NUMBER]; /* @@ -91,10 +108,7 @@ void ipc_object_reference( ipc_object_t object) { - io_lock(object); - assert(object->io_references > 0); io_reference(object); - io_unlock(object); } /* @@ -107,10 +121,7 @@ void ipc_object_release( ipc_object_t object) { - io_lock(object); - assert(object->io_references > 0); io_release(object); - io_check_unlock(object); } /* @@ -246,7 +257,7 @@ ipc_object_alloc_dead( 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; } @@ -284,7 +295,7 @@ ipc_object_alloc_dead_name( 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; } @@ -295,6 +306,7 @@ ipc_object_alloc_dead_name( * 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. @@ -336,7 +348,7 @@ ipc_object_alloc( } 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); @@ -346,9 +358,9 @@ ipc_object_alloc( 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); @@ -418,6 +430,7 @@ ipc_object_alloc_name( entry->ie_bits |= type | urefs; entry->ie_object = object; + ipc_entry_modified(space, name, entry); io_lock(object); is_write_unlock(space); @@ -442,7 +455,6 @@ ipc_object_copyin_type( 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: @@ -454,6 +466,10 @@ ipc_object_copyin_type( 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; } @@ -483,7 +499,17 @@ ipc_object_copyin( { 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; + +#if IMPORTANCE_INHERITANCE + int assertcnt = 0; +#endif + + queue_init(links); /* * Could first try a read lock when doing @@ -496,13 +522,33 @@ ipc_object_copyin( 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); @@ -580,13 +626,14 @@ ipc_object_copyin_from_kernel( 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; } @@ -601,11 +648,11 @@ ipc_object_copyin_from_kernel( 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; } @@ -658,6 +705,42 @@ ipc_object_destroy( } } +/* + * 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: @@ -693,7 +776,7 @@ ipc_object_copyout( is_write_lock(space); for (;;) { - if (!space->is_active) { + if (!is_active(space)) { is_write_unlock(space); return KERN_INVALID_TASK; } @@ -706,7 +789,7 @@ ipc_object_copyout( 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 */ @@ -737,6 +820,7 @@ ipc_object_copyout( kr = ipc_right_copyout(space, name, entry, msgt_name, overflow, object); + /* object is unlocked */ is_write_unlock(space); @@ -777,6 +861,11 @@ ipc_object_copyout_name( ipc_entry_t entry; kern_return_t kr; +#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); @@ -821,10 +910,47 @@ ipc_object_copyout_name( /* 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; } @@ -973,7 +1099,6 @@ ipc_object_rename( return kr; } -#if MACH_ASSERT /* * Check whether the object is a port if so, free it. But * keep track of that fact. @@ -987,82 +1112,8 @@ io_free( if (otype == IOT_PORT) { port = (ipc_port_t) object; -#if MACH_ASSERT - ipc_port_track_dealloc(port); -#endif /* MACH_ASSERT */ + ipc_port_finalize(port); } + io_lock_destroy(object); zfree(ipc_object_zones[otype], object); } -#endif /* MACH_ASSERT */ - -#include -#if MACH_KDB - -#include -#include - -#define printf kdbprintf - -/* - * Routine: ipc_object_print - * Purpose: - * Pretty-print an object for kdb. - */ - -const 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]); -} - -#endif /* MACH_KDB */