X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..d7e50217d7adf6e52786a38bcaa4cd698cb9a79e:/iokit/Kernel/IOCatalogue.cpp diff --git a/iokit/Kernel/IOCatalogue.cpp b/iokit/Kernel/IOCatalogue.cpp index 3fa1d62ee..4c8e3b1b5 100644 --- a/iokit/Kernel/IOCatalogue.cpp +++ b/iokit/Kernel/IOCatalogue.cpp @@ -3,19 +3,22 @@ * * @APPLE_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. + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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. + * + * 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@ */ @@ -35,6 +38,7 @@ extern "C" { #include #include #include +#include }; #include @@ -149,6 +153,7 @@ bool IOCatalogue::init(OSArray * initArray) kernelTables = OSCollectionIterator::withCollection( array ); lock = IOLockAlloc(); + kld_lock = IOLockAlloc(); kernelTables->reset(); while( (dict = (OSDictionary *) kernelTables->getNextObject())) { @@ -282,6 +287,10 @@ OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, IOTakeLock( lock ); kernelTables->reset(); while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) { + + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ if ( dict->isEqualTo(matching, matching) ) set->setObject(dict); } @@ -339,7 +348,14 @@ bool IOCatalogue::addDrivers(OSArray * drivers, // Be sure not to double up on personalities. driver = (OSDictionary *)array->getObject(count); - if ( dict->isEqualTo(driver, driver) ) { + + /* Unlike in other functions, this comparison must be exact! + * The catalogue must be able to contain personalities that + * are proper supersets of others. + * Do not compare just the properties present in one driver + * pesonality or the other. + */ + if ( dict->isEqualTo(driver) ) { array->removeObject(count); break; } @@ -358,11 +374,6 @@ bool IOCatalogue::addDrivers(OSArray * drivers, } IOUnlock( lock ); - if ( doNubMatching ) { - (IOService::getServiceRoot())->waitQuiet(); - kmod_send_generic( kIOCatalogMatchIdle, 0, 0 ); - } - set->release(); iter->release(); @@ -409,6 +420,10 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching, array->flushCollection(); tables->reset(); while ( (dict = (OSDictionary *)tables->getNextObject()) ) { + + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ if ( dict->isEqualTo(matching, matching) ) { AddNewImports( set, dict ); continue; @@ -448,13 +463,21 @@ bool IOCatalogue::isModuleLoaded( const char * moduleName ) const return false; // Is the module already loaded? - k_info = kmod_lookupbyname((char *)moduleName); + k_info = kmod_lookupbyname_locked((char *)moduleName); if ( !k_info ) { kern_return_t ret; + /* To make sure this operation completes even if a bad extension needs + * to be removed, take the kld lock for this whole block, spanning the + * kmod_load_function() and remove_startup_extension_function() calls. + */ + IOLockLock(kld_lock); + // If the module hasn't been loaded, then load it. if (kmod_load_function != 0) { + ret = kmod_load_function((char *)moduleName); + if ( ret != kIOReturnSuccess ) { IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName); @@ -466,25 +489,34 @@ bool IOCatalogue::isModuleLoaded( const char * moduleName ) const if (kernelLinkerPresent && remove_startup_extension_function) { (*remove_startup_extension_function)(moduleName); } + IOLockUnlock(kld_lock); return false; } else if (kernelLinkerPresent) { // If kern linker is here, the driver is actually loaded, // so return true. + IOLockUnlock(kld_lock); return true; } else { // kern linker isn't here, a request has been queued // but the module isn't necessarily loaded yet, so stall. + IOLockUnlock(kld_lock); return false; } } else { - IOLog("IOCatalogue: %s cannot be loaded " - "(kmod load function not set).\n", - moduleName); + IOLog("IOCatalogue: %s cannot be loaded " + "(kmod load function not set).\n", + moduleName); } + IOLockUnlock(kld_lock); return false; } + if (k_info) { + kfree(k_info, sizeof(kmod_info_t)); + } + + /* Lock wasn't taken if we get here. */ return true; } @@ -528,22 +560,29 @@ void IOCatalogue::moduleHasLoaded( const char * moduleName ) IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const { - kmod_info_t * k_info; + kmod_info_t * k_info = 0; kern_return_t ret; const char * name; ret = kIOReturnBadArgument; if ( moduleName ) { name = moduleName->getCStringNoCopy(); - k_info = kmod_lookupbyname((char *)name); + k_info = kmod_lookupbyname_locked((char *)name); if ( k_info && (k_info->reference_count < 1) ) { if ( k_info->stop && - !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) + !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) { + + kfree(k_info, sizeof(kmod_info_t)); return ret; + } ret = kmod_destroy(host_priv_self(), k_info->id); } } + + if (k_info) { + kfree(k_info, sizeof(kmod_info_t)); + } return ret; } @@ -551,7 +590,6 @@ IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) { OSCollectionIterator * tables; - OSCollectionIterator * props; OSDictionary * dict; OSIterator * iter; OSArray * arrayCopy; @@ -570,12 +608,6 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) UniqueProperties( matching ); - props = OSCollectionIterator::withCollection(matching); - if ( !props ) { - iter->release(); - return kIOReturnNoMemory; - } - // terminate instances. do { iter->reset(); @@ -584,6 +616,10 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) if ( !dict ) continue; + /* Terminate only for personalities that match the matching dictionary. + * This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ if ( !dict->isEqualTo(matching, matching) ) continue; @@ -612,6 +648,12 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) array->flushCollection(); tables->reset(); while ( (dict = (OSDictionary *)tables->getNextObject()) ) { + + /* Remove from the catalogue's array any personalities + * that match the matching dictionary. + * This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ if ( dict->isEqualTo(matching, matching) ) continue; @@ -648,7 +690,7 @@ IOReturn IOCatalogue::terminateDriversForModule( return kIOReturnNoMemory; dict->setObject(kModuleKey, moduleName); - + IOTakeLock( lock ); ret = _terminateDrivers(array, dict); @@ -680,7 +722,7 @@ IOReturn IOCatalogue::terminateDriversForModule( ret = terminateDriversForModule(name, unload); name->release(); - + return ret; } @@ -701,6 +743,10 @@ bool IOCatalogue::startMatching( OSDictionary * matching ) kernelTables->reset(); while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) { + + /* This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ if ( dict->isEqualTo(matching, matching) ) AddNewImports(set, dict); } @@ -761,13 +807,15 @@ bool IOCatalogue::serialize(OSSerialize * s) const bool IOCatalogue::recordStartupExtensions(void) { bool result = false; - if (record_startup_extensions_function) { + IOLockLock(kld_lock); + if (kernelLinkerPresent && record_startup_extensions_function) { result = (*record_startup_extensions_function)(); } else { IOLog("Can't record startup extensions; " "kernel linker is not present.\n"); result = false; } + IOLockUnlock(kld_lock); return result; } @@ -778,13 +826,15 @@ bool IOCatalogue::recordStartupExtensions(void) { bool IOCatalogue::addExtensionsFromArchive(OSData * mkext) { bool result = false; - if (add_from_mkext_function) { + IOLockLock(kld_lock); + if (kernelLinkerPresent && add_from_mkext_function) { result = (*add_from_mkext_function)(mkext); } else { IOLog("Can't add startup extensions from archive; " "kernel linker is not present.\n"); result = false; } + IOLockUnlock(kld_lock); return result; } @@ -805,7 +855,7 @@ kern_return_t IOCatalogue::removeKernelLinker(void) { /* This must be the very first thing done by this function. */ - IOTakeLock(lock); + IOLockLock(kld_lock); /* If the kernel linker isn't here, that's automatically @@ -838,6 +888,7 @@ kern_return_t IOCatalogue::removeKernelLinker(void) { segment = getsegbynamefromheader( &_mh_execute_header, "__KLD"); if (!segment) { + IOLog("error removing kernel linker: can't find __KLD segment\n"); result = KERN_FAILURE; goto finish; } @@ -846,6 +897,7 @@ kern_return_t IOCatalogue::removeKernelLinker(void) { segment = getsegbynamefromheader( &_mh_execute_header, "__LINKEDIT"); if (!segment) { + IOLog("error removing kernel linker: can't find __LINKEDIT segment\n"); result = KERN_FAILURE; goto finish; } @@ -871,7 +923,7 @@ finish: /* This must be the very last thing done before returning. */ - IOUnlock(lock); + IOLockUnlock(kld_lock); return result; }