X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..d9a64523371fa019c4575bb400cbbc3a50ac9903:/osfmk/ipc/ipc_object.c diff --git a/osfmk/ipc/ipc_object.c b/osfmk/ipc/ipc_object.c index a20d572b8..6b40e4761 100644 --- a/osfmk/ipc/ipc_object.c +++ b/osfmk/ipc/ipc_object.c @@ -1,23 +1,29 @@ /* - * 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@ @@ -47,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. + */ /* */ /* @@ -57,13 +70,18 @@ * Functions to manipulate IPC objects. */ -#include - +#include #include #include #include #include + +#include #include +#include + +#include +#include #include #include #include @@ -71,8 +89,11 @@ #include #include #include +#include #include +#include + zone_t ipc_object_zones[IOT_NUMBER]; /* @@ -85,10 +106,7 @@ void ipc_object_reference( ipc_object_t object) { - io_lock(object); - assert(object->io_references > 0); io_reference(object); - io_unlock(object); } /* @@ -101,10 +119,7 @@ void ipc_object_release( ipc_object_t object) { - io_lock(object); - assert(object->io_references > 0); io_release(object); - io_check_unlock(object); } /* @@ -117,10 +132,9 @@ ipc_object_release( * Returns: * KERN_SUCCESS Object returned locked. * KERN_INVALID_TASK The space is dead. - * KERN_INVALID_NAME The name doesn't denote a right. - * KERN_INVALID_RIGHT Name doesn't denote the correct right. + * KERN_INVALID_NAME The name doesn't denote a right + * KERN_INVALID_RIGHT Name doesn't denote the correct right */ - kern_return_t ipc_object_translate( ipc_space_t space, @@ -188,11 +202,13 @@ ipc_object_translate_two( if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) { is_read_unlock(space); + mach_port_guard_exception(name1, 0, 0, kGUARD_EXC_INVALID_RIGHT); return KERN_INVALID_RIGHT; } if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) { is_read_unlock(space); + mach_port_guard_exception(name2, 0, 0, kGUARD_EXC_INVALID_RIGHT); return KERN_INVALID_RIGHT; } @@ -231,9 +247,6 @@ ipc_object_alloc_dead( ipc_entry_t entry; kern_return_t kr; - int i; - - kr = ipc_entry_alloc(space, namep, &entry); if (kr != KERN_SUCCESS) return kr; @@ -243,7 +256,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; } @@ -269,9 +282,6 @@ ipc_object_alloc_dead_name( ipc_entry_t entry; kern_return_t kr; - int i; - - kr = ipc_entry_alloc_name(space, name, &entry); if (kr != KERN_SUCCESS) return kr; @@ -284,7 +294,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 +305,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 +347,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 +357,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 +429,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 +454,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 +465,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,9 +498,9 @@ ipc_object_copyin( { ipc_entry_t entry; ipc_port_t soright; + ipc_port_t release_port; kern_return_t kr; - - int i; + int assertcnt = 0; /* * Could first try a read lock when doing @@ -498,13 +513,25 @@ 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, + &assertcnt); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); +#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); @@ -517,7 +544,8 @@ ipc_object_copyin( * 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. @@ -550,15 +578,18 @@ ipc_object_copyin_from_kernel( ipc_port_t port = (ipc_port_t) object; ip_lock(port); + imq_lock(&port->ip_messages); 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; + } + imq_unlock(&port->ip_messages); ip_unlock(port); break; } @@ -580,37 +611,43 @@ 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_receiver->is_node_id != HOST_LOCAL_NODE)); + 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"); @@ -654,6 +691,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: @@ -679,6 +752,7 @@ ipc_object_copyout( boolean_t overflow, mach_port_name_t *namep) { + struct knote *kn = current_thread()->ith_knote; mach_port_name_t name; ipc_entry_t entry; kern_return_t kr; @@ -686,10 +760,15 @@ ipc_object_copyout( assert(IO_VALID(object)); assert(io_otype(object) == IOT_PORT); + if (ITH_KNOTE_VALID(kn, msgt_name)) { + filt_machport_turnstile_prepare_lazily(kn, + msgt_name, (ipc_port_t)object); + } + is_write_lock(space); for (;;) { - if (!space->is_active) { + if (!is_active(space)) { is_write_unlock(space); return KERN_INVALID_TASK; } @@ -702,7 +781,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 */ @@ -733,6 +812,7 @@ ipc_object_copyout( kr = ipc_right_copyout(space, name, entry, msgt_name, overflow, object); + /* object is unlocked */ is_write_unlock(space); @@ -772,12 +852,21 @@ ipc_object_copyout_name( ipc_entry_t oentry; ipc_entry_t entry; kern_return_t kr; + struct knote *kn = current_thread()->ith_knote; - 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); + if (ITH_KNOTE_VALID(kn, msgt_name)) { + filt_machport_turnstile_prepare_lazily(kn, + msgt_name, (ipc_port_t)object); + } + kr = ipc_entry_alloc_name(space, name, &entry); if (kr != KERN_SUCCESS) return kr; @@ -819,10 +908,49 @@ 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); + } else { + task_imp = IIT_NULL; + } + } + + /* 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; } @@ -917,6 +1045,7 @@ ipc_object_copyout_dest( default: panic("ipc_object_copyout_dest: strange rights"); + name = MACH_PORT_DEAD; } *namep = name; @@ -945,8 +1074,6 @@ ipc_object_rename( 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; @@ -972,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. @@ -986,81 +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); } - zfree(ipc_object_zones[otype], (vm_offset_t) object); + io_lock_destroy(object); + zfree(ipc_object_zones[otype], object); } -#endif /* MACH_ASSERT */ - -#include -#if MACH_KDB - -#include - -#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]); -} - -#endif /* MACH_KDB */