X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/cb3231590a3c94ab4375e2228bd5e86b0cf1ad7e..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/iokit/Kernel/IOCatalogue.cpp diff --git a/iokit/Kernel/IOCatalogue.cpp b/iokit/Kernel/IOCatalogue.cpp index 7c0201e4d..958022743 100644 --- a/iokit/Kernel/IOCatalogue.cpp +++ b/iokit/Kernel/IOCatalogue.cpp @@ -38,6 +38,8 @@ * Version 2.0. */ +#define IOKIT_ENABLE_SHARED_PTR + extern "C" { #include #include @@ -48,6 +50,7 @@ extern "C" { #include #include #include +#include #include #include @@ -57,6 +60,7 @@ extern "C" { #include #include +#include #if PRAGMA_MARK #pragma mark Internal Declarations @@ -64,11 +68,11 @@ extern "C" { /********************************************************************* *********************************************************************/ -IOCatalogue * gIOCatalogue; -const OSSymbol * gIOClassKey; -const OSSymbol * gIOProbeScoreKey; -const OSSymbol * gIOModuleIdentifierKey; -const OSSymbol * gIOModuleIdentifierKernelKey; +OSSharedPtr gIOCatalogue; +OSSharedPtr gIOClassKey; +OSSharedPtr gIOProbeScoreKey; +OSSharedPtr gIOModuleIdentifierKey; +OSSharedPtr gIOModuleIdentifierKernelKey; IORWLock * gIOCatalogLock; #if PRAGMA_MARK @@ -93,17 +97,16 @@ static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts, void IOCatalogue::initialize(void) { - OSArray * array; - OSString * errorString; + OSSharedPtr array; + OSSharedPtr errorString; bool rc; extern const char * gIOKernelConfigTables; - array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString)); + array = OSDynamicPtrCast(OSUnserialize(gIOKernelConfigTables, errorString)); if (!array && errorString) { IOLog("KernelConfigTables syntax error: %s\n", errorString->getCStringNoCopy()); - errorString->release(); } gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey ); @@ -115,11 +118,10 @@ IOCatalogue::initialize(void) assert( array && gIOClassKey && gIOProbeScoreKey && gIOModuleIdentifierKey); - gIOCatalogue = new IOCatalogue; + gIOCatalogue = OSMakeShared(); assert(gIOCatalogue); - rc = gIOCatalogue->init(array); + rc = gIOCatalogue->init(array.get()); assert(rc); - array->release(); } /********************************************************************* @@ -152,9 +154,8 @@ IOCatalogue::addPersonality(OSDictionary * dict) if (arr) { arr->setObject(dict); } else { - arr = OSArray::withObjects((const OSObject **)&dict, 1, 2); - personalities->setObject(sym, arr); - arr->release(); + OSSharedPtr sharedArr = OSArray::withObjects((const OSObject **)&dict, 1, 2); + personalities->setObject(sym, sharedArr.get()); } } @@ -181,7 +182,7 @@ IOCatalogue::init(OSArray * initArray) continue; } OSKext::uniquePersonalityProperties(dict); - if (NULL == dict->getObject( gIOClassKey )) { + if (NULL == dict->getObject( gIOClassKey.get())) { IOLog("Missing or bad \"%s\" key\n", gIOClassKey->getCStringNoCopy()); continue; @@ -208,19 +209,19 @@ IOCatalogue::free( void ) /********************************************************************* *********************************************************************/ -OSOrderedSet * +OSPtr IOCatalogue::findDrivers( IOService * service, SInt32 * generationCount) { OSDictionary * nextTable; - OSOrderedSet * set; + OSSharedPtr set; OSArray * array; const OSMetaClass * meta; unsigned int idx; set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, - (void *)gIOProbeScoreKey ); + (void *)(gIOProbeScoreKey.get())); if (!set) { return NULL; } @@ -251,14 +252,14 @@ IOCatalogue::findDrivers( /********************************************************************* * Is personality already in the catalog? *********************************************************************/ -OSOrderedSet * +OSPtr IOCatalogue::findDrivers( OSDictionary * matching, SInt32 * generationCount) { - OSCollectionIterator * iter; + OSSharedPtr iter; OSDictionary * dict; - OSOrderedSet * set; + OSSharedPtr set; OSArray * array; const OSSymbol * key; unsigned int idx; @@ -266,14 +267,13 @@ IOCatalogue::findDrivers( OSKext::uniquePersonalityProperties(matching); set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, - (void *)gIOProbeScoreKey ); + (void *)(gIOProbeScoreKey.get())); if (!set) { return NULL; } - iter = OSCollectionIterator::withCollection(personalities); + iter = OSCollectionIterator::withCollection(personalities.get()); if (!iter) { - set->release(); - return NULL; + return nullptr; } IORWLockRead(lock); @@ -293,7 +293,6 @@ IOCatalogue::findDrivers( *generationCount = getGenerationCount(); IORWLockUnlock(lock); - iter->release(); return set; } @@ -315,8 +314,8 @@ IOCatalogue::addDrivers( bool doNubMatching) { bool result = false; - OSCollectionIterator * iter = NULL; // must release - OSOrderedSet * set = NULL; // must release + OSSharedPtr set; + OSSharedPtr iter; OSObject * object = NULL; // do not release OSArray * persons = NULL;// do not release @@ -326,7 +325,7 @@ IOCatalogue::addDrivers( } set = OSOrderedSet::withCapacity( 10, IOServiceOrdering, - (void *)gIOProbeScoreKey ); + (void *)(gIOProbeScoreKey.get())); if (!set) { goto finish; } @@ -393,51 +392,34 @@ IOCatalogue::addDrivers( } // Start device matching. if (result && doNubMatching && (set->getCount() > 0)) { - IOService::catalogNewDrivers(set); + IOService::catalogNewDrivers(set.get()); generation++; } IORWLockUnlock(lock); 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) +IOCatalogue::removeDrivers(bool doNubMatching, bool (^shouldRemove)(OSDictionary *personality)) { - OSOrderedSet * set; - OSCollectionIterator * iter; + OSSharedPtr set; + OSSharedPtr iter; OSDictionary * dict; OSArray * array; const OSSymbol * key; unsigned int idx; - if (!matching) { - return false; - } - set = OSOrderedSet::withCapacity(10, IOServiceOrdering, - (void *)gIOProbeScoreKey); + (void *)(gIOProbeScoreKey.get())); if (!set) { return false; } - iter = OSCollectionIterator::withCollection(personalities); + iter = OSCollectionIterator::withCollection(personalities.get()); if (!iter) { - set->release(); return false; } @@ -446,10 +428,7 @@ IOCatalogue::removeDrivers( array = (OSArray *) personalities->getObject(key); if (array) { for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) { - /* This comparison must be done with only the keys in the - * "matching" dict to enable general searches. - */ - if (dict->isEqualTo(matching, matching)) { + if (shouldRemove(dict)) { set->setObject(dict); array->removeObject(idx); idx--; @@ -458,18 +437,35 @@ IOCatalogue::removeDrivers( } // Start device matching. if (doNubMatching && (set->getCount() > 0)) { - IOService::catalogNewDrivers(set); + IOService::catalogNewDrivers(set.get()); generation++; } } IORWLockUnlock(lock); - set->release(); - iter->release(); - return true; } +/********************************************************************* +* Remove drivers from the catalog which match the +* properties in the matching dictionary. +*********************************************************************/ +bool +IOCatalogue::removeDrivers( + OSDictionary * matching, + bool doNubMatching) +{ + if (!matching) { + return false; + } + return removeDrivers(doNubMatching, ^(OSDictionary *dict) { + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ + return dict->isEqualTo(matching, matching); + }); +} + // Return the generation count. SInt32 IOCatalogue::getGenerationCount(void) const @@ -502,7 +498,7 @@ IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const driver->getObject(kIOPersonalityPublisherKey)); OSKext::recordIdentifierRequest(publisherName); - moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey)); + moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey.get())); if (moduleName) { ret = OSKext::loadKextWithIdentifier(moduleName, kextRef); if (kOSKextReturnDeferred == ret) { @@ -510,11 +506,10 @@ IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const // loaded yet, so stall. return false; } - OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey)); + OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey.get())); if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) { - OSObject *dextRef = NULL; - ret = OSKext::loadKextWithIdentifier(moduleDextName, &dextRef); - OSSafeReleaseNULL(dextRef); + OSSharedPtr dextRef; + ret = OSKext::loadKextWithIdentifier(moduleDextName, dextRef); } // module is present or never will be return true; @@ -526,6 +521,15 @@ IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const return true; } +bool +IOCatalogue::isModuleLoaded(OSDictionary * driver, OSSharedPtr& kextRef) const +{ + OSObject* kextRefRaw = NULL; + bool result = isModuleLoaded(driver, &kextRefRaw); + kextRef.reset(kextRefRaw, OSNoRetain); + return result; +} + /* This function is called after a module has been loaded. * Is invoked from user client call, ultimately from IOKitLib's * IOCatalogueModuleLoaded(). Sent from kextd. @@ -542,11 +546,10 @@ IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName) void IOCatalogue::moduleHasLoaded(const char * moduleName) { - const OSSymbol * name; + OSSharedPtr name; name = OSSymbol::withCString(moduleName); - moduleHasLoaded(name); - name->release(); + moduleHasLoaded(name.get()); } // xxx - return is really OSReturn/kern_return_t @@ -557,17 +560,13 @@ IOCatalogue::unloadModule(OSString * moduleName) const } IOReturn -IOCatalogue::_terminateDrivers(OSDictionary * matching) +IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className) { OSDictionary * dict; - OSIterator * iter; + OSSharedPtr iter; IOService * service; IOReturn ret; - if (!matching) { - return kIOReturnBadArgument; - } - ret = kIOReturnSuccess; dict = NULL; iter = IORegistryIterator::iterateOver(gIOServicePlane, @@ -576,32 +575,90 @@ IOCatalogue::_terminateDrivers(OSDictionary * matching) return kIOReturnNoMemory; } - OSKext::uniquePersonalityProperties( matching ); + if (matching) { + OSKext::uniquePersonalityProperties( matching, false ); + } // terminate instances. do { iter->reset(); while ((service = (IOService *)iter->getNextObject())) { - dict = service->getPropertyTable(); - if (!dict) { + if (className && !service->metaCast(className)) { 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; + if (matching) { + /* 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. + */ + dict = service->getPropertyTable(); + if (!dict) { + continue; + } + if (!dict->isEqualTo(matching, matching)) { + continue; + } } - if (!service->terminate(kIOServiceRequired | kIOServiceSynchronous)) { + OSKext * kext; + OSSharedPtr dextBundleID; + const char * bundleIDStr; + OSObject * prop; + bool okToTerminate; + bool isDext = service->hasUserServer(); + for (okToTerminate = true;;) { + if (isDext) { + dextBundleID = OSDynamicPtrCast(service->copyProperty(gIOModuleIdentifierKey.get())); + if (!dextBundleID) { + break; + } + bundleIDStr = dextBundleID->getCStringNoCopy(); + } else { + kext = service->getMetaClass()->getKext(); + if (!kext) { + break; + } + bundleIDStr = kext->getIdentifierCString(); + prop = kext->getPropertyForHostArch(kOSBundleAllowUserTerminateKey); + if (prop) { + okToTerminate = (kOSBooleanTrue == prop); + break; + } + } + if (!bundleIDStr) { + break; + } + if (!strcmp(kOSKextKernelIdentifier, bundleIDStr)) { + okToTerminate = false; + break; + } + if (!strncmp("com.apple.", bundleIDStr, strlen("com.apple."))) { + okToTerminate = false; + break; + } + break; + } + if (!okToTerminate) { +#if DEVELOPMENT || DEBUG + okToTerminate = true; +#endif /* DEVELOPMENT || DEBUG */ + IOLog("%sallowing kextunload terminate for bundleID %s\n", + okToTerminate ? "" : "dis", bundleIDStr ? bundleIDStr : "?"); + if (!okToTerminate) { + ret = kIOReturnUnsupported; + break; + } + } + IOOptionBits terminateOptions = kIOServiceRequired | kIOServiceSynchronous; + if (isDext) { + terminateOptions |= kIOServiceTerminateNeedWillTerminate; + } + if (!service->terminate(terminateOptions)) { ret = kIOReturnUnsupported; break; } } } while (!service && !iter->isValid()); - iter->release(); return ret; } @@ -610,7 +667,7 @@ IOReturn IOCatalogue::_removeDrivers(OSDictionary * matching) { IOReturn ret = kIOReturnSuccess; - OSCollectionIterator * iter; + OSSharedPtr iter; OSDictionary * dict; OSArray * array; const OSSymbol * key; @@ -618,7 +675,7 @@ IOCatalogue::_removeDrivers(OSDictionary * matching) // remove configs from catalog. - iter = OSCollectionIterator::withCollection(personalities); + iter = OSCollectionIterator::withCollection(personalities.get()); if (!iter) { return kIOReturnNoMemory; } @@ -639,7 +696,6 @@ IOCatalogue::_removeDrivers(OSDictionary * matching) } } } - iter->release(); return ret; } @@ -649,7 +705,10 @@ IOCatalogue::terminateDrivers(OSDictionary * matching) { IOReturn ret; - ret = _terminateDrivers(matching); + if (!matching) { + return kIOReturnBadArgument; + } + ret = terminateDrivers(matching, NULL); IORWLockWrite(lock); if (kIOReturnSuccess == ret) { ret = _removeDrivers(matching); @@ -659,13 +718,96 @@ IOCatalogue::terminateDrivers(OSDictionary * matching) return ret; } +IOReturn +IOCatalogue::terminateDriversForUserspaceReboot() +{ + IOReturn ret = kIOReturnSuccess; + +#if !NO_KEXTD + OSSharedPtr iter; + IOService * service; + bool isDeferredMatch; + bool isDext; + IOOptionBits terminateOptions; + + iter = IORegistryIterator::iterateOver(gIOServicePlane, + kIORegistryIterateRecursively); + if (!iter) { + return kIOReturnNoMemory; + } + + do { + iter->reset(); + while ((service = (IOService *)iter->getNextObject())) { + isDeferredMatch = service->propertyHasValue(gIOMatchDeferKey, kOSBooleanTrue); + isDext = service->hasUserServer(); + if (isDeferredMatch || isDext) { + if (isDext) { + OSSharedPtr name = OSDynamicPtrCast(service->copyProperty(gIOUserServerNameKey)); + const char *userServerName = NULL; + if (name) { + userServerName = name->getCStringNoCopy(); + } + IOLog("terminating service %s-0x%llx [dext %s]\n", service->getName(), service->getRegistryEntryID(), userServerName ? userServerName : "(null)"); + } else { + OSKext *kext = service->getMetaClass()->getKext(); + const char *bundleID = NULL; + if (kext) { + bundleID = kext->getIdentifierCString(); + } + IOLog("terminating service %s-0x%llx [kext %s]\n", service->getName(), service->getRegistryEntryID(), bundleID ? bundleID : "(null)"); + } + terminateOptions = kIOServiceRequired | kIOServiceSynchronous; + if (isDext) { + terminateOptions |= kIOServiceTerminateNeedWillTerminate; + } + if (!service->terminate(terminateOptions)) { + IOLog("failed to terminate service %s-0x%llx\n", service->getName(), service->getRegistryEntryID()); + ret = kIOReturnUnsupported; + break; + } + } + } + } while (!service && !iter->isValid()); +#endif + + return ret; +} + +IOReturn +IOCatalogue::resetAfterUserspaceReboot(void) +{ + OSSharedPtr iter; + IOService * service; + + iter = IORegistryIterator::iterateOver(gIOServicePlane, + kIORegistryIterateRecursively); + if (!iter) { + return kIOReturnNoMemory; + } + + do { + iter->reset(); + while ((service = (IOService *)iter->getNextObject())) { + service->resetRematchProperties(); + } + } while (!service && !iter->isValid()); + + /* Remove all dext personalities */ + removeDrivers(false, ^(OSDictionary *dict) { + return dict->getObject(gIOUserServerNameKey) != NULL; + }); + + return kIOReturnSuccess; +} + IOReturn IOCatalogue::terminateDriversForModule( OSString * moduleName, bool unload) { IOReturn ret; - OSDictionary * dict; + OSSharedPtr dict; bool isLoaded = false; /* Check first if the kext currently has any linkage dependents; @@ -693,15 +835,15 @@ IOCatalogue::terminateDriversForModule( goto finish; } - dict->setObject(gIOModuleIdentifierKey, moduleName); + dict->setObject(gIOModuleIdentifierKey.get(), moduleName); - ret = _terminateDrivers(dict); + ret = terminateDrivers(dict.get(), NULL); /* No goto between IOLock calls! */ IORWLockWrite(lock); if (kIOReturnSuccess == ret) { - ret = _removeDrivers(dict); + ret = _removeDrivers(dict.get()); } // Unload the module itself. @@ -711,8 +853,6 @@ IOCatalogue::terminateDriversForModule( IORWLockUnlock(lock); - dict->release(); - finish: return ret; } @@ -722,7 +862,7 @@ IOCatalogue::terminateDriversForModule( const char * moduleName, bool unload) { - OSString * name; + OSSharedPtr name; IOReturn ret; name = OSString::withCString(moduleName); @@ -730,8 +870,7 @@ IOCatalogue::terminateDriversForModule( return kIOReturnNoMemory; } - ret = terminateDriversForModule(name, unload); - name->release(); + ret = terminateDriversForModule(name.get(), unload); return ret; } @@ -740,14 +879,14 @@ IOCatalogue::terminateDriversForModule( bool IOCatalogue::startMatching( OSDictionary * matching ) { - OSOrderedSet * set; + OSSharedPtr set; if (!matching) { return false; } set = OSOrderedSet::withCapacity(10, IOServiceOrdering, - (void *)gIOProbeScoreKey); + (void *)(gIOProbeScoreKey.get())); if (!set) { return false; } @@ -773,14 +912,12 @@ IOCatalogue::startMatching( OSDictionary * matching ) // Start device matching. if (set->getCount() > 0) { - IOService::catalogNewDrivers(set); + IOService::catalogNewDrivers(set.get()); generation++; } IORWLockUnlock(lock); - set->release(); - return true; } #endif /* defined(__i386__) || defined(__x86_64__) */ @@ -788,14 +925,14 @@ IOCatalogue::startMatching( OSDictionary * matching ) bool IOCatalogue::startMatching( const OSSymbol * moduleName ) { - OSOrderedSet * set; + OSSharedPtr set; if (!moduleName) { return false; } set = OSOrderedSet::withCapacity(10, IOServiceOrdering, - (void *)gIOProbeScoreKey); + (void *)(gIOProbeScoreKey.get())); if (!set) { return false; } @@ -805,13 +942,16 @@ IOCatalogue::startMatching( const OSSymbol * moduleName ) personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) { OSArray * array; OSDictionary * dict; - OSObject * obj; + OSObject * moduleIdentifierKernel; + OSObject * moduleIdentifier; unsigned int idx; array = (OSArray *) value; for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) { - obj = dict->getObject(gIOModuleIdentifierKernelKey); - if (obj && moduleName->isEqualTo(obj)) { + moduleIdentifierKernel = dict->getObject(gIOModuleIdentifierKernelKey.get()); + moduleIdentifier = dict->getObject(gIOModuleIdentifierKey.get()); + if ((moduleIdentifierKernel && moduleName->isEqualTo(moduleIdentifierKernel)) || + (moduleIdentifier && moduleName->isEqualTo(moduleIdentifier))) { set->setObject(dict); } } @@ -820,14 +960,12 @@ IOCatalogue::startMatching( const OSSymbol * moduleName ) // Start device matching. if (set->getCount() > 0) { - IOService::catalogNewDrivers(set); + IOService::catalogNewDrivers(set.get()); generation++; } IORWLockUnlock(lock); - set->release(); - return true; } @@ -844,13 +982,13 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) { bool result = false; OSArray * newPersonalities = NULL;// do not release - OSCollectionIterator * iter = NULL;// must release - OSOrderedSet * matchSet = NULL;// must release const OSSymbol * key; OSArray * array; OSDictionary * thisNewPersonality = NULL;// do not release OSDictionary * thisOldPersonality = NULL;// do not release - OSDictionary * myKexts = NULL;// must release + OSSharedPtr myKexts; + OSSharedPtr iter; + OSSharedPtr matchSet; signed int idx, newIdx; if (drivers) { @@ -860,11 +998,11 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) } } matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering, - (void *)gIOProbeScoreKey); + (void *)(gIOProbeScoreKey.get())); if (!matchSet) { goto finish; } - iter = OSCollectionIterator::withCollection(personalities); + iter = OSCollectionIterator::withCollection(personalities.get()); if (!iter) { goto finish; } @@ -922,7 +1060,7 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) } else { // not in new set - remove // only remove dictionary if this module in not loaded - 9953845 - if (isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false) { + if (isModuleLoadedNoOSKextLock(myKexts.get(), thisOldPersonality) == false) { if (matchSet) { matchSet->setObject(thisOldPersonality); } @@ -952,22 +1090,13 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) /* Finally, start device matching on all new & removed personalities. */ if (result && doNubMatching && (matchSet->getCount() > 0)) { - IOService::catalogNewDrivers(matchSet); + IOService::catalogNewDrivers(matchSet.get()); generation++; } IORWLockUnlock(lock); finish: - if (matchSet) { - matchSet->release(); - } - if (iter) { - iter->release(); - } - if (myKexts) { - myKexts->release(); - } return result; } @@ -1035,7 +1164,7 @@ isModuleLoadedNoOSKextLock(OSDictionary *theKexts, // gIOModuleIdentifierKey is "CFBundleIdentifier" myBundleID = OSDynamicCast(OSString, - theModuleDict->getObject(gIOModuleIdentifierKey)); + theModuleDict->getObject(gIOModuleIdentifierKey.get())); if (myBundleID == NULL) { return myResult; }