/*
- * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2006 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@
*/
/*
- * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998 Apple Inc. All rights reserved.
*
* HISTORY
*
*/
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2005 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.
+ */
-#include <IOKit/IODeviceTreeSupport.h>
-#include <IOKit/IOService.h>
-#include <libkern/c++/OSContainers.h>
-#include <IOKit/IOCatalogue.h>
-#include <libkern/c++/OSUnserialize.h>
extern "C" {
#include <machine/machine_routines.h>
-#include <mach/kmod.h>
-#include <mach-o/mach_header.h>
+#include <libkern/kernel_mach_header.h>
#include <kern/host.h>
+#include <security/mac_data.h>
};
-#include <IOKit/IOLib.h>
-
-#include <IOKit/assert.h>
-
-
-extern "C" {
-int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
-extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
-extern void OSRuntimeUnloadCPPForSegment(
- struct segment_command * segment);
-};
-
-
-/*****
- * At startup these function pointers are set to use the libsa in-kernel
- * linker for recording and loading kmods. Once the root filesystem
- * is available, the kmod_load_function pointer gets switched to point
- * at the kmod_load_extension() function built into the kernel, and the
- * others are set to zero. Those two functions must *always* be checked
- * before being invoked.
- */
-extern "C" {
-kern_return_t (*kmod_load_function)(char *extension_name) =
- &kmod_load_extension;
-bool (*record_startup_extensions_function)(void) = 0;
-bool (*add_from_mkext_function)(OSData * mkext) = 0;
-void (*remove_startup_extension_function)(const char * name) = 0;
-};
-
-
-/*****
- * A few parts of IOCatalogue require knowledge of
- * whether the in-kernel linker is present. This
- * variable is set by libsa's bootstrap code.
- */
-int kernelLinkerPresent = 0;
+#include <libkern/c++/OSContainers.h>
+#include <libkern/c++/OSUnserialize.h>
+#include <libkern/c++/OSKext.h>
+#include <libkern/OSKextLibPrivate.h>
+#include <IOKit/IODeviceTreeSupport.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOCatalogue.h>
-#define super OSObject
-#define kModuleKey "CFBundleIdentifier"
+#include <IOKit/IOLib.h>
+#include <IOKit/assert.h>
-OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
+#if PRAGMA_MARK
+#pragma mark Internal Declarations
+#endif
+/*********************************************************************
+*********************************************************************/
#define CATALOGTEST 0
-IOCatalogue * gIOCatalogue;
-const OSSymbol * gIOClassKey;
-const OSSymbol * gIOProbeScoreKey;
+IOCatalogue * gIOCatalogue;
+const OSSymbol * gIOClassKey;
+const OSSymbol * gIOProbeScoreKey;
+const OSSymbol * gIOModuleIdentifierKey;
+IOLock * gIOCatalogLock;
-static void UniqueProperties( OSDictionary * dict )
+#if PRAGMA_MARK
+#pragma mark Utility functions
+#endif
+/*********************************************************************
+*********************************************************************/
+static void
+UniqueProperties(OSDictionary * dict)
{
- OSString * data;
+ OSString * data;
- data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
- if( data) {
+ data = OSDynamicCast(OSString, dict->getObject(gIOClassKey));
+ if (data) {
const OSSymbol *classSymbol = OSSymbol::withString(data);
dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
classSymbol->release();
}
- data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
- if( data) {
+ data = OSDynamicCast(OSString, dict->getObject(gIOMatchCategoryKey));
+ if (data) {
const OSSymbol *classSymbol = OSSymbol::withString(data);
- dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
+ dict->setObject(gIOMatchCategoryKey, (OSSymbol *) classSymbol);
classSymbol->release();
}
+ return;
}
-void IOCatalogue::initialize( void )
+/*********************************************************************
+* Add a new personality to the set if it has a unique IOResourceMatchKey value.
+* XXX -- svail: This should be optimized.
+* esb - There doesn't seem like any reason to do this - it causes problems
+* esb - when there are more than one loadable driver matching on the same provider class
+*********************************************************************/
+static void
+AddNewImports(OSOrderedSet * set, OSDictionary * dict)
+{
+ set->setObject(dict);
+}
+
+#if PRAGMA_MARK
+#pragma mark IOCatalogue class implementation
+#endif
+/*********************************************************************
+*********************************************************************/
+
+#define super OSObject
+OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
+
+/*********************************************************************
+*********************************************************************/
+void IOCatalogue::initialize(void)
{
OSArray * array;
OSString * errorString;
array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
if (!array && errorString) {
- IOLog("KernelConfigTables syntax error: %s\n",
- errorString->getCStringNoCopy());
- errorString->release();
+ IOLog("KernelConfigTables syntax error: %s\n",
+ errorString->getCStringNoCopy());
+ errorString->release();
}
- gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
- gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
- assert( array && gIOClassKey && gIOProbeScoreKey);
+ gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
+ gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
+ gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
+
+ assert( array && gIOClassKey && gIOProbeScoreKey
+ && gIOModuleIdentifierKey);
gIOCatalogue = new IOCatalogue;
assert(gIOCatalogue);
array->release();
}
-// Initialize the IOCatalog object.
+/*********************************************************************
+* Initialize the IOCatalog object.
+*********************************************************************/
bool IOCatalogue::init(OSArray * initArray)
{
- IORegistryEntry * entry;
OSDictionary * dict;
if ( !super::init() )
array->retain();
kernelTables = OSCollectionIterator::withCollection( array );
- lock = IOLockAlloc();
- kld_lock = IOLockAlloc();
+ gIOCatalogLock = IOLockAlloc();
+
+ lock = gIOCatalogLock;
+#if __ppc__ || __i386__
+ kld_lock = NULL;
+#endif /* __ppc__ || __i386__ */
kernelTables->reset();
while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
thread_call_func_delayed( ping, this, deadline );
#endif
- entry = IORegistryEntry::getRegistryRoot();
- if ( entry )
- entry->setProperty(kIOCatalogueKey, this);
-
return true;
}
-// Release all resources used by IOCatalogue and deallocate.
-// This will probably never be called.
+/*********************************************************************
+* Release all resources used by IOCatalogue and deallocate.
+* This will probably never be called.
+*********************************************************************/
void IOCatalogue::free( void )
{
if ( array )
super::free();
}
+/*********************************************************************
+*********************************************************************/
#if CATALOGTEST
static int hackLimit;
-
enum { kDriversPerIter = 4 };
-void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
+void
+IOCatalogue::ping(thread_call_param_t arg, thread_call_param_t)
{
IOCatalogue * self = (IOCatalogue *) arg;
OSOrderedSet * set;
set = OSOrderedSet::withCapacity( 1 );
- IOTakeLock( &self->lock );
+ IOLockLock( &self->lock );
for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
table = (OSDictionary *) self->array->getObject(
if( table) {
set->setLastObject( table );
- OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey );
+ OSSymbol * sym = (OSSymbol *) table->getObject(gIOClassKey);
kprintf("enabling %s\n", sym->getCStringNoCopy());
} else {
hackLimit += newLimit;
self->generation++;
- IOUnlock( &self->lock );
+ IOLockUnlock( &self->lock );
if( kDriversPerIter == newLimit) {
AbsoluteTime deadline;
- clock_interval_to_deadline( 500, kMillisecondScale );
- thread_call_func_delayed( ping, this, deadline );
+ clock_interval_to_deadline(500, kMillisecondScale);
+ thread_call_func_delayed(ping, this, deadline);
}
}
#endif
-OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
- SInt32 * generationCount )
+/*********************************************************************
+*********************************************************************/
+OSOrderedSet *
+IOCatalogue::findDrivers(
+ IOService * service,
+ SInt32 * generationCount)
{
OSDictionary * nextTable;
OSOrderedSet * set;
if( !set )
return( 0 );
- IOTakeLock( lock );
+ IOLockLock(lock);
kernelTables->reset();
#if CATALOGTEST
*generationCount = getGenerationCount();
- IOUnlock( lock );
+ IOLockUnlock(lock);
return( set );
}
-// Is personality already in the catalog?
-OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
- SInt32 * generationCount)
+/*********************************************************************
+* Is personality already in the catalog?
+*********************************************************************/
+OSOrderedSet *
+IOCatalogue::findDrivers(
+ OSDictionary * matching,
+ SInt32 * generationCount)
{
OSDictionary * dict;
OSOrderedSet * set;
set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
(void *)gIOProbeScoreKey );
- IOTakeLock( lock );
+ IOLockLock(lock);
kernelTables->reset();
while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
set->setObject(dict);
}
*generationCount = getGenerationCount();
- IOUnlock( lock );
+ IOLockUnlock(lock);
return set;
}
-// Add a new personality to the set if it has a unique IOResourceMatchKey value.
-// XXX -- svail: This should be optimized.
-// esb - There doesn't seem like any reason to do this - it causes problems
-// esb - when there are more than one loadable driver matching on the same provider class
-static void AddNewImports( OSOrderedSet * set, OSDictionary * dict )
-{
- set->setObject(dict);
-}
-
-// Add driver config tables to catalog and start matching process.
-bool IOCatalogue::addDrivers(OSArray * drivers,
- bool doNubMatching = true )
+/*********************************************************************
+* Add driver config tables to catalog and start matching process.
+*
+* Important that existing personalities are kept (not replaced)
+* if duplicates found. Personalities can come from OSKext objects
+* or from userland kext library. We want to minimize distinct
+* copies between OSKext & IOCatalogue.
+*
+* xxx - userlib used to refuse to send personalities with IOKitDebug
+* xxx - during safe boot. That would be better implemented here.
+*********************************************************************/
+bool IOCatalogue::addDrivers(
+ OSArray * drivers,
+ bool doNubMatching)
{
- OSCollectionIterator * iter;
- OSDictionary * dict;
- OSOrderedSet * set;
- OSArray * persons;
- bool ret;
+ bool result = false;
+ OSCollectionIterator * iter = NULL; // must release
+ OSOrderedSet * set = NULL; // must release
+ OSDictionary * dict = NULL; // do not release
+ OSArray * persons = NULL; // do not release
- ret = true;
persons = OSDynamicCast(OSArray, drivers);
- if ( !persons )
- return false;
-
- iter = OSCollectionIterator::withCollection( persons );
- if (!iter )
- return false;
+ if (!persons) {
+ goto finish;
+ }
set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
- (void *)gIOProbeScoreKey );
- if ( !set ) {
- iter->release();
- return false;
+ (void *)gIOProbeScoreKey );
+ if (!set) {
+ goto finish;
+ }
+
+ iter = OSCollectionIterator::withCollection(persons);
+ if (!iter) {
+ goto finish;
}
- IOTakeLock( lock );
+ result = true;
+
+ IOLockLock(lock);
while ( (dict = (OSDictionary *) iter->getNextObject()) ) {
- UInt count;
-
- UniqueProperties( dict );
+
+ // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
+ SInt count;
+
+ UniqueProperties(dict);
+
// Add driver personality to catalogue.
count = array->getCount();
- while ( count-- ) {
- OSDictionary * driver;
-
+ while (count--) {
+ OSDictionary * driver;
+
// Be sure not to double up on personalities.
driver = (OSDictionary *)array->getObject(count);
-
+
/* 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);
+ if (dict->isEqualTo(driver)) {
break;
}
}
+ if (count >= 0) {
+ // its a dup
+ continue;
+ }
- ret = array->setObject( dict );
- if ( !ret )
+ result = array->setObject(dict);
+ if (!result) {
break;
-
- AddNewImports( set, dict );
+ }
+
+ AddNewImports(set, dict);
}
// Start device matching.
- if ( doNubMatching && (set->getCount() > 0) ) {
- IOService::catalogNewDrivers( set );
+ if (doNubMatching && (set->getCount() > 0)) {
+ IOService::catalogNewDrivers(set);
generation++;
}
- IOUnlock( lock );
+ IOLockUnlock(lock);
- set->release();
- iter->release();
-
- return ret;
+finish:
+ if (set) set->release();
+ if (iter) iter->release();
+
+ return result;
}
-// Remove drivers from the catalog which match the
-// properties in the matching dictionary.
-bool IOCatalogue::removeDrivers( OSDictionary * matching,
- bool doNubMatching = true)
+/*********************************************************************
+* Remove drivers from the catalog which match the
+* properties in the matching dictionary.
+*********************************************************************/
+bool
+IOCatalogue::removeDrivers(
+ OSDictionary * matching,
+ bool doNubMatching)
{
OSCollectionIterator * tables;
OSDictionary * dict;
UniqueProperties( matching );
- IOTakeLock( lock );
+ IOLockLock(lock);
kernelTables->reset();
arrayCopy->merge(array);
array->flushCollection();
IOService::catalogNewDrivers(set);
generation++;
}
- IOUnlock( lock );
+ IOLockUnlock(lock);
set->release();
tables->release();
}
// Return the generation count.
-SInt32 IOCatalogue::getGenerationCount( void ) const
+SInt32 IOCatalogue::getGenerationCount(void) const
{
return( generation );
}
-bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
+bool IOCatalogue::isModuleLoaded(OSString * moduleName) const
{
return isModuleLoaded(moduleName->getCStringNoCopy());
}
-bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
+bool IOCatalogue::isModuleLoaded(const char * moduleName) const
{
- kmod_info_t * k_info;
-
- if ( !moduleName )
- return false;
-
- // Is the module already loaded?
- 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);
-
- /* If the extension couldn't be loaded this time,
- * make it unavailable so that no more requests are
- * made in vain. This also enables other matching
- * extensions to have a chance.
- */
- 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);
- }
-
- IOLockUnlock(kld_lock);
+ OSReturn ret;
+ ret = OSKext::loadKextWithIdentifier(moduleName);
+ if (kOSKextReturnDeferred == ret) {
+ // a request has been queued but the module isn't necessarily
+ // loaded yet, so stall.
return false;
}
-
- if (k_info) {
- kfree(k_info, sizeof(kmod_info_t));
- }
-
- /* Lock wasn't taken if we get here. */
+ // module is present or never will be
return true;
}
// Check to see if module has been loaded already.
-bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
+bool IOCatalogue::isModuleLoaded(OSDictionary * driver) const
{
OSString * moduleName = NULL;
+ OSString * publisherName = NULL;
if ( !driver )
return false;
- moduleName = OSDynamicCast(OSString, driver->getObject(kModuleKey));
+ /* The personalities of codeless kexts often contain the bundle ID of the
+ * kext they reference, and not the bundle ID of the codeless kext itself.
+ * The prelinked kernel needs to know the bundle ID of the codeless kext
+ * so it can include these personalities, so OSKext stores that bundle ID
+ * in the IOPersonalityPublisher key, and we record it as requested here.
+ */
+ publisherName = OSDynamicCast(OSString,
+ driver->getObject(kIOPersonalityPublisherKey));
+ OSKext::recordIdentifierRequest(publisherName);
+
+ moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
if ( moduleName )
return isModuleLoaded(moduleName);
return true;
}
-// This function is called after a module has been loaded.
-void IOCatalogue::moduleHasLoaded( OSString * moduleName )
+/* This function is called after a module has been loaded.
+ * Is invoked from user client call, ultimately from IOKitLib's
+ * IOCatalogueModuleLoaded(). Sent from kextd.
+ */
+void IOCatalogue::moduleHasLoaded(OSString * moduleName)
{
- OSDictionary * dict;
+ OSDictionary * dict;
dict = OSDictionary::withCapacity(2);
- dict->setObject(kModuleKey, moduleName);
+ dict->setObject(gIOModuleIdentifierKey, moduleName);
startMatching(dict);
dict->release();
+
+ (void) OSKext::setDeferredLoadSucceeded();
+ (void) OSKext::considerRebuildOfPrelinkedKernel();
}
-void IOCatalogue::moduleHasLoaded( const char * moduleName )
+void IOCatalogue::moduleHasLoaded(const char * moduleName)
{
- OSString * name;
+ OSString * name;
name = OSString::withCString(moduleName);
moduleHasLoaded(name);
name->release();
}
-IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
+// xxx - return is really OSReturn/kern_return_t
+IOReturn IOCatalogue::unloadModule(OSString * moduleName) const
{
- kmod_info_t * k_info = 0;
- kern_return_t ret;
- const char * name;
-
- ret = kIOReturnBadArgument;
- if ( moduleName ) {
- name = moduleName->getCStringNoCopy();
- 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) ) {
-
- 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;
+ return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
}
-static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
+static IOReturn _terminateDrivers(OSDictionary * matching)
{
- OSCollectionIterator * tables;
OSDictionary * dict;
OSIterator * iter;
- OSArray * arrayCopy;
IOService * service;
IOReturn ret;
} while( !service && !iter->isValid());
iter->release();
+ return ret;
+}
+
+static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
+{
+ OSCollectionIterator * tables;
+ OSDictionary * dict;
+ OSArray * arrayCopy;
+ IOReturn ret = kIOReturnSuccess;
+
// remove configs from catalog.
- if ( ret != kIOReturnSuccess )
- return ret;
arrayCopy = OSArray::withCapacity(100);
if ( !arrayCopy )
return ret;
}
-IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
+bool IOCatalogue::removePersonalities(OSArray * personalitiesToRemove)
+{
+ bool result = true;
+ OSArray * arrayCopy = NULL; // do not release
+ OSCollectionIterator * iterator = NULL; // must release
+ OSDictionary * personality = NULL; // do not release
+ OSDictionary * checkPersonality = NULL; // do not release
+ unsigned int count, i;
+
+ // remove configs from catalog.
+
+ arrayCopy = OSArray::withArray(array);
+ if (!arrayCopy) {
+ result = false;
+ goto finish;
+ }
+
+ iterator = OSCollectionIterator::withCollection(arrayCopy);
+ arrayCopy->release();
+ if (!iterator) {
+ result = false;
+ goto finish;
+ }
+
+ array->flushCollection();
+
+ count = personalitiesToRemove->getCount();
+
+ /* Go through the old catalog's list of personalities and add back any that
+ * are *not* found in 'personalitiesToRemove'.
+ */
+ while ((personality = (OSDictionary *)iterator->getNextObject())) {
+ bool found = false;
+
+ for (i = 0; i < count; i++) {
+ checkPersonality = OSDynamicCast(OSDictionary,
+ personalitiesToRemove->getObject(i));
+
+ /* Do isEqualTo() with the single-arg version to make an exact
+ * comparison (unlike _removeDrivers() above).
+ */
+ if (personality->isEqualTo(checkPersonality)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ array->setObject(personality);
+ }
+ }
+
+finish:
+
+ OSSafeRelease(iterator);
+ return result;
+}
+
+IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching)
{
IOReturn ret;
- ret = kIOReturnSuccess;
- IOTakeLock( lock );
- ret = _terminateDrivers(array, matching);
+ ret = _terminateDrivers(matching);
+ IOLockLock(lock);
+ if (kIOReturnSuccess == ret)
+ ret = _removeDrivers(array, matching);
kernelTables->reset();
- IOUnlock( lock );
+ IOLockUnlock(lock);
return ret;
}
IOReturn IOCatalogue::terminateDriversForModule(
- OSString * moduleName,
- bool unload )
+ OSString * moduleName,
+ bool unload)
{
IOReturn ret;
OSDictionary * dict;
+ bool isLoaded = false;
+
+ /* Check first if the kext currently has any linkage dependents;
+ * in such a case the unload would fail so let's not terminate any
+ * IOServices (since doing so typically results in a panic when there
+ * are loaded dependencies). Note that we aren't locking the kext here
+ * so it might lose or gain dependents by the time we call unloadModule();
+ * I think that's ok, our unload can fail if a kext comes in on top of
+ * this one even after we've torn down IOService objects. Conversely,
+ * if we fail the unload here and then lose a library, the autounload
+ * thread will get us in short order.
+ */
+ if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
+
+ isLoaded = true;
+ if (!OSKext::canUnloadKextWithIdentifier(moduleName,
+ /* checkClasses */ false)) {
+ ret = kOSKextReturnInUse;
+ goto finish;
+ }
+ }
dict = OSDictionary::withCapacity(1);
- if ( !dict )
- return kIOReturnNoMemory;
-
- dict->setObject(kModuleKey, moduleName);
+ if (!dict) {
+ ret = kIOReturnNoMemory;
+ goto finish;
+ }
- IOTakeLock( lock );
+ dict->setObject(gIOModuleIdentifierKey, moduleName);
- ret = _terminateDrivers(array, dict);
+ ret = _terminateDrivers(dict);
+
+ /* No goto between IOLock calls!
+ */
+ IOLockLock(lock);
+ if (kIOReturnSuccess == ret) {
+ ret = _removeDrivers(array, dict);
+ }
kernelTables->reset();
// Unload the module itself.
- if ( unload && ret == kIOReturnSuccess ) {
- // Do kmod stop first.
+ if (unload && isLoaded && ret == kIOReturnSuccess) {
ret = unloadModule(moduleName);
}
- IOUnlock( lock );
+ IOLockUnlock(lock);
dict->release();
+finish:
return ret;
}
IOReturn IOCatalogue::terminateDriversForModule(
- const char * moduleName,
- bool unload )
+ const char * moduleName,
+ bool unload)
{
OSString * name;
IOReturn ret;
if ( !set )
return false;
- IOTakeLock( lock );
+ IOLockLock(lock);
kernelTables->reset();
while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
generation++;
}
- IOUnlock( lock );
+ IOLockUnlock(lock);
set->release();
void IOCatalogue::reset(void)
{
- OSArray * tables;
- OSDictionary * entry;
- unsigned int count;
-
IOLog("Resetting IOCatalogue.\n");
-
- IOTakeLock( lock );
- tables = OSArray::withArray(array);
- array->flushCollection();
-
- count = tables->getCount();
- while ( count-- ) {
- entry = (OSDictionary *)tables->getObject(count);
- if ( entry && !entry->getObject(kModuleKey) ) {
- array->setObject(entry);
- }
- }
-
- kernelTables->reset();
- IOUnlock( lock );
-
- tables->release();
}
bool IOCatalogue::serialize(OSSerialize * s) const
{
- bool ret;
-
if ( !s )
return false;
- IOTakeLock( lock );
- ret = array->serialize(s);
- IOUnlock( lock );
-
- return ret;
+ return super::serialize(s);
}
+bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
+{
+ kern_return_t kr = kIOReturnSuccess;
-bool IOCatalogue::recordStartupExtensions(void) {
- bool result = false;
+ switch ( kind )
+ {
+ case kIOCatalogGetContents:
+ if (!array->serialize(s))
+ kr = kIOReturnNoMemory;
+ break;
- 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);
+ case kIOCatalogGetModuleDemandList:
+ kr = KERN_NOT_SUPPORTED;
+ break;
- return result;
-}
+ case kIOCatalogGetCacheMissList:
+ kr = KERN_NOT_SUPPORTED;
+ break;
+ case kIOCatalogGetROMMkextList:
+ kr = KERN_NOT_SUPPORTED;
+ break;
-/*********************************************************************
-*********************************************************************/
-bool IOCatalogue::addExtensionsFromArchive(OSData * mkext) {
- bool result = false;
-
- 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;
+ default:
+ kr = kIOReturnBadArgument;
+ break;
}
- IOLockUnlock(kld_lock);
- return result;
+ return kr;
}
+#if PRAGMA_MARK
+#pragma mark Obsolete Kext Loading Stuff
+#endif
/*********************************************************************
-* This function clears out all references to the in-kernel linker,
-* frees the list of startup extensions in extensionDict, and
-* deallocates the kernel's __KLD segment to reclaim that memory.
-*********************************************************************/
-kern_return_t IOCatalogue::removeKernelLinker(void) {
- kern_return_t result = KERN_SUCCESS;
- extern struct mach_header _mh_execute_header;
- struct segment_command * segment;
- char * dt_segment_name;
- void * segment_paddress;
- int segment_size;
-
- /* This must be the very first thing done by this function.
- */
- IOLockLock(kld_lock);
-
-
- /* If the kernel linker isn't here, that's automatically
- * a success.
- */
- if (!kernelLinkerPresent) {
- result = KERN_SUCCESS;
- goto finish;
- }
-
- IOLog("Jettisoning kernel linker.\n");
-
- kernelLinkerPresent = 0;
-
- /* Set the kmod_load_extension function as the means for loading
- * a kernel extension.
- */
- kmod_load_function = &kmod_load_extension;
-
- record_startup_extensions_function = 0;
- add_from_mkext_function = 0;
- remove_startup_extension_function = 0;
-
-
- /* Invoke destructors for the __KLD and __LINKEDIT segments.
- * Do this for all segments before actually freeing their
- * memory so that any cross-dependencies (not that there
- * should be any) are handled.
- */
- segment = getsegbynamefromheader(
- &_mh_execute_header, "__KLD");
- if (!segment) {
- IOLog("error removing kernel linker: can't find __KLD segment\n");
- result = KERN_FAILURE;
- goto finish;
- }
- OSRuntimeUnloadCPPForSegment(segment);
-
- segment = getsegbynamefromheader(
- &_mh_execute_header, "__LINKEDIT");
- if (!segment) {
- IOLog("error removing kernel linker: can't find __LINKEDIT segment\n");
- result = KERN_FAILURE;
- goto finish;
- }
- OSRuntimeUnloadCPPForSegment(segment);
+**********************************************************************
+*** BINARY COMPATIBILITY SECTION ***
+**********************************************************************
+**********************************************************************
+* These functions are no longer used are necessary for C++ binary
+* compatibility on ppc/i386.
+**********************************************************************/
+#if __ppc__ || __i386__
+bool IOCatalogue::recordStartupExtensions(void)
+{ return false; }
- /* Free the memory that was set up by bootx.
- */
- dt_segment_name = "Kernel-__KLD";
- if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
- IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
- (int)segment_size);
- }
+bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
+{ return KERN_NOT_SUPPORTED; }
- dt_segment_name = "Kernel-__LINKEDIT";
- if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
- IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
- (int)segment_size);
- }
+kern_return_t IOCatalogue::removeKernelLinker(void)
+{ return KERN_NOT_SUPPORTED; }
-
-finish:
-
- /* This must be the very last thing done before returning.
- */
- IOLockUnlock(kld_lock);
-
- return result;
-}
+#endif /* __ppc__ || __i386__ */