xref: /xnu-11215/iokit/Kernel/IOCatalogue.cpp (revision 5c2921b0)
1 /*
2  * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * Copyright (c) 1998 Apple Inc.  All rights reserved.
30  *
31  * HISTORY
32  *
33  */
34 /*
35  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
36  * support for mandatory and extensible security protections.  This notice
37  * is included in support of clause 2.2 (b) of the Apple Public License,
38  * Version 2.0.
39  */
40 
41 #define IOKIT_ENABLE_SHARED_PTR
42 
43 extern "C" {
44 #include <libkern/kernel_mach_header.h>
45 #include <kern/host.h>
46 #include <security/mac_data.h>
47 };
48 
49 #include <machine/machine_routines.h>
50 #include <libkern/c++/OSContainers.h>
51 #include <libkern/c++/OSUnserialize.h>
52 #include <libkern/c++/OSKext.h>
53 #include <libkern/c++/OSSharedPtr.h>
54 #include <libkern/OSKextLibPrivate.h>
55 #include <libkern/OSDebug.h>
56 
57 #include <IOKit/IODeviceTreeSupport.h>
58 #include <IOKit/IOService.h>
59 #include <IOKit/IOCatalogue.h>
60 
61 #include <IOKit/IOLib.h>
62 #include <IOKit/assert.h>
63 #include <IOKit/IOKitKeysPrivate.h>
64 
65 #if PRAGMA_MARK
66 #pragma mark Internal Declarations
67 #endif
68 /*********************************************************************
69 *********************************************************************/
70 
71 OSSharedPtr<IOCatalogue> gIOCatalogue;
72 OSSharedPtr<const OSSymbol> gIOClassKey;
73 OSSharedPtr<const OSSymbol> gIOProbeScoreKey;
74 OSSharedPtr<const OSSymbol> gIOModuleIdentifierKey;
75 OSSharedPtr<const OSSymbol> gIOModuleIdentifierKernelKey;
76 OSSharedPtr<const OSSymbol> gIOHIDInterfaceClassName;
77 IORWLock       * gIOCatalogLock;
78 
79 #if PRAGMA_MARK
80 #pragma mark Utility functions
81 #endif
82 
83 #if PRAGMA_MARK
84 #pragma mark IOCatalogue class implementation
85 #endif
86 /*********************************************************************
87 *********************************************************************/
88 
89 #define super OSObject
90 OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
91 
92 static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
93     OSDictionary *theModuleDict);
94 
95 
96 /*********************************************************************
97 *********************************************************************/
98 void
initialize(void)99 IOCatalogue::initialize(void)
100 {
101 	OSSharedPtr<OSArray> array;
102 	OSSharedPtr<OSString> errorString;
103 	bool                   rc;
104 
105 	extern const char * gIOKernelConfigTables;
106 
107 	array = OSDynamicPtrCast<OSArray>(OSUnserialize(gIOKernelConfigTables, errorString));
108 	if (!array && errorString) {
109 		IOLog("KernelConfigTables syntax error: %s\n",
110 		    errorString->getCStringNoCopy());
111 	}
112 
113 	gIOClassKey                  = OSSymbol::withCStringNoCopy( kIOClassKey );
114 	gIOProbeScoreKey             = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
115 	gIOModuleIdentifierKey       = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
116 	gIOModuleIdentifierKernelKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKernelKey );
117 	gIOHIDInterfaceClassName     = OSSymbol::withCStringNoCopy( "IOHIDInterface" );
118 
119 
120 	assert( array && gIOClassKey && gIOProbeScoreKey
121 	    && gIOModuleIdentifierKey);
122 
123 	gIOCatalogue = OSMakeShared<IOCatalogue>();
124 	assert(gIOCatalogue);
125 	rc = gIOCatalogue->init(array.get());
126 	assert(rc);
127 }
128 
129 /*********************************************************************
130 * Initialize the IOCatalog object.
131 *********************************************************************/
132 OSArray *
arrayForPersonality(OSDictionary * dict)133 IOCatalogue::arrayForPersonality(OSDictionary * dict)
134 {
135 	const OSSymbol * sym;
136 
137 	sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
138 	if (!sym) {
139 		return NULL;
140 	}
141 
142 	return (OSArray *) personalities->getObject(sym);
143 }
144 
145 void
addPersonality(OSDictionary * dict)146 IOCatalogue::addPersonality(OSDictionary * dict)
147 {
148 	const OSSymbol * sym;
149 	OSArray * arr;
150 
151 	sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
152 	if (!sym) {
153 		return;
154 	}
155 	arr = (OSArray *) personalities->getObject(sym);
156 	if (arr) {
157 		arr->setObject(dict);
158 	} else {
159 		OSSharedPtr<OSArray> sharedArr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
160 		personalities->setObject(sym, sharedArr.get());
161 	}
162 }
163 
164 /*********************************************************************
165 * Initialize the IOCatalog object.
166 *********************************************************************/
167 bool
init(OSArray * initArray)168 IOCatalogue::init(OSArray * initArray)
169 {
170 	OSDictionary         * dict;
171 	OSObject * obj;
172 
173 	if (!super::init()) {
174 		return false;
175 	}
176 
177 	generation = 1;
178 
179 	personalities = OSDictionary::withCapacity(32);
180 	personalities->setOptions(OSCollection::kSort, OSCollection::kSort);
181 	for (unsigned int idx = 0; (obj = initArray->getObject(idx)); idx++) {
182 		dict = OSDynamicCast(OSDictionary, obj);
183 		if (!dict) {
184 			continue;
185 		}
186 		OSKext::uniquePersonalityProperties(dict);
187 		if (NULL == dict->getObject( gIOClassKey.get())) {
188 			IOLog("Missing or bad \"%s\" key\n",
189 			    gIOClassKey->getCStringNoCopy());
190 			continue;
191 		}
192 		dict->setObject("KernelConfigTable", kOSBooleanTrue);
193 		addPersonality(dict);
194 	}
195 
196 	gIOCatalogLock = IORWLockAlloc();
197 	lock = gIOCatalogLock;
198 
199 	return true;
200 }
201 
202 /*********************************************************************
203 * Release all resources used by IOCatalogue and deallocate.
204 * This will probably never be called.
205 *********************************************************************/
206 void
free(void)207 IOCatalogue::free( void )
208 {
209 	panic("");
210 }
211 
212 /*********************************************************************
213 *********************************************************************/
214 OSPtr<OSOrderedSet>
findDrivers(IOService * service,SInt32 * generationCount)215 IOCatalogue::findDrivers(
216 	IOService * service,
217 	SInt32 * generationCount)
218 {
219 	OSDictionary         * nextTable;
220 	OSSharedPtr<OSOrderedSet> set;
221 	OSArray              * array;
222 	const OSMetaClass    * meta;
223 	unsigned int           idx;
224 
225 	set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
226 	    (void *)(gIOProbeScoreKey.get()));
227 	if (!set) {
228 		return NULL;
229 	}
230 
231 	IORWLockRead(lock);
232 
233 	meta = service->getMetaClass();
234 	while (meta) {
235 		array = (OSArray *) personalities->getObject(meta->getClassNameSymbol());
236 		if (array) {
237 			for (idx = 0; (nextTable = (OSDictionary *) array->getObject(idx)); idx++) {
238 				set->setObject(nextTable);
239 			}
240 		}
241 		if (meta == &IOService::gMetaClass) {
242 			break;
243 		}
244 		meta = meta->getSuperClass();
245 	}
246 
247 	*generationCount = getGenerationCount();
248 
249 	IORWLockUnlock(lock);
250 
251 	return set;
252 }
253 
254 /*********************************************************************
255 * Is personality already in the catalog?
256 *********************************************************************/
257 OSPtr<OSOrderedSet>
findDrivers(OSDictionary * matching,SInt32 * generationCount)258 IOCatalogue::findDrivers(
259 	OSDictionary * matching,
260 	SInt32 * generationCount)
261 {
262 	OSSharedPtr<OSCollectionIterator> iter;
263 	OSDictionary         * dict;
264 	OSSharedPtr<OSOrderedSet> set;
265 	OSArray              * array;
266 	const OSSymbol       * key;
267 	unsigned int           idx;
268 
269 	OSKext::uniquePersonalityProperties(matching);
270 
271 	set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
272 	    (void *)(gIOProbeScoreKey.get()));
273 	if (!set) {
274 		return NULL;
275 	}
276 	iter = OSCollectionIterator::withCollection(personalities.get());
277 	if (!iter) {
278 		return nullptr;
279 	}
280 
281 	IORWLockRead(lock);
282 	while ((key = (const OSSymbol *) iter->getNextObject())) {
283 		array = (OSArray *) personalities->getObject(key);
284 		if (array) {
285 			for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
286 				/* This comparison must be done with only the keys in the
287 				 * "matching" dict to enable general searches.
288 				 */
289 				if (dict->isEqualTo(matching, matching)) {
290 					set->setObject(dict);
291 				}
292 			}
293 		}
294 	}
295 	*generationCount = getGenerationCount();
296 	IORWLockUnlock(lock);
297 
298 	return set;
299 }
300 
301 bool
exchangeDrivers(OSDictionary * matchingForRemove,OSArray * personalitiesToAdd,bool doNubMatching)302 IOCatalogue::exchangeDrivers(
303 	OSDictionary *matchingForRemove,
304 	OSArray *personalitiesToAdd,
305 	bool doNubMatching)
306 {
307 	OSSharedPtr<OSOrderedSet> set;
308 	OSSharedPtr<OSCollectionIterator> iter_new, iter_all_personalities;
309 
310 	set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
311 	    (void *)(gIOProbeScoreKey.get()));
312 	if (!set) {
313 		goto finish;
314 	}
315 
316 	iter_new = OSCollectionIterator::withCollection(personalitiesToAdd);
317 	if (!iter_new) {
318 		goto finish;
319 	}
320 
321 	IORWLockWrite(lock);
322 
323 	iter_all_personalities = OSCollectionIterator::withCollection(personalities.get());
324 	if (!iter_all_personalities) {
325 		IORWLockUnlock(lock);
326 		goto finish;
327 	}
328 
329 	/*
330 	 * Remove personalities first.
331 	 * We get a dictionary that has only some keys that could belong to a personality.
332 	 * Every personality that will match those keys will be removed.
333 	 */
334 	const OSSymbol * key;
335 	while ((key = (const OSSymbol *) iter_all_personalities->getNextObject())) {
336 		OSArray *array = (OSArray *) personalities->getObject(key);
337 		if (array) {
338 			unsigned int idx;
339 			OSDictionary *dict;
340 			for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
341 				if (dict->isEqualTo(matchingForRemove, matchingForRemove)) {
342 					set->setObject(dict);
343 					array->removeObject(idx);
344 					idx--;
345 				}
346 			}
347 		}
348 	}
349 
350 	/*
351 	 * Add new personalities.
352 	 */
353 	OSObject *object;
354 	while ((object = iter_new->getNextObject())) {
355 		OSDictionary * personality = OSDynamicCast(OSDictionary, object);
356 		if (personality) {
357 			OSKext::uniquePersonalityProperties(personality);
358 			OSArray * array = arrayForPersonality(personality);
359 			if (!array) {
360 				addPersonality(personality);
361 			} else {
362 				SInt count = array->getCount();
363 				while (count--) {
364 					OSDictionary * driver;
365 					// Be sure not to double up on personalities.
366 					driver = (OSDictionary *)array->getObject(count);
367 					/* Unlike in other functions, this comparison must be exact!
368 					 * The catalogue must be able to contain personalities that
369 					 * are proper supersets of others.
370 					 * Do not compare just the properties present in one driver
371 					 * personality or the other.
372 					 */
373 					if (personality->isEqualTo(driver)) {
374 						break;
375 					}
376 				}
377 				if (count >= 0) {
378 					// its a dup
379 					continue;
380 				}
381 				array->setObject(personality);
382 			}
383 			set->setObject(personality);
384 		}
385 	}
386 
387 	if (doNubMatching && (set->getCount() > 0)) {
388 		IOService::catalogNewDrivers(set.get());
389 		generation++;
390 	}
391 
392 	IORWLockUnlock(lock);
393 
394 finish:
395 	return true;
396 }
397 
398 /*********************************************************************
399 * Add driver config tables to catalog and start matching process.
400 *
401 * Important that existing personalities are kept (not replaced)
402 * if duplicates found. Personalities can come from OSKext objects
403 * or from userland kext library. We want to minimize distinct
404 * copies between OSKext & IOCatalogue.
405 *
406 * xxx - userlib used to refuse to send personalities with IOKitDebug
407 * xxx - during safe boot. That would be better implemented here.
408 *********************************************************************/
409 
410 bool
addDrivers(OSArray * drivers,bool doNubMatching)411 IOCatalogue::addDrivers(
412 	OSArray * drivers,
413 	bool doNubMatching)
414 {
415 	bool                   result = false;
416 	OSSharedPtr<OSOrderedSet> set;
417 	OSSharedPtr<OSCollectionIterator> iter;
418 	OSObject             * object = NULL;   // do not release
419 	OSArray              * persons = NULL;// do not release
420 
421 	persons = OSDynamicCast(OSArray, drivers);
422 	if (!persons) {
423 		goto finish;
424 	}
425 
426 	set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
427 	    (void *)(gIOProbeScoreKey.get()));
428 	if (!set) {
429 		goto finish;
430 	}
431 
432 	iter = OSCollectionIterator::withCollection(persons);
433 	if (!iter) {
434 		goto finish;
435 	}
436 
437 	/* Start with success; clear it on an error.
438 	 */
439 	result = true;
440 
441 	IORWLockWrite(lock);
442 	while ((object = iter->getNextObject())) {
443 		// xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
444 
445 		OSDictionary * personality = OSDynamicCast(OSDictionary, object);
446 
447 		SInt count;
448 
449 		if (!personality) {
450 			IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
451 			result = false;
452 			break;
453 		}
454 
455 		OSKext::uniquePersonalityProperties(personality);
456 
457 		// Add driver personality to catalogue.
458 
459 		OSArray * array = arrayForPersonality(personality);
460 		if (!array) {
461 			addPersonality(personality);
462 		} else {
463 			count = array->getCount();
464 			while (count--) {
465 				OSDictionary * driver;
466 
467 				// Be sure not to double up on personalities.
468 				driver = (OSDictionary *)array->getObject(count);
469 
470 				/* Unlike in other functions, this comparison must be exact!
471 				 * The catalogue must be able to contain personalities that
472 				 * are proper supersets of others.
473 				 * Do not compare just the properties present in one driver
474 				 * personality or the other.
475 				 */
476 				if (personality->isEqualTo(driver)) {
477 					break;
478 				}
479 			}
480 			if (count >= 0) {
481 				// its a dup
482 				continue;
483 			}
484 			result = array->setObject(personality);
485 			if (!result) {
486 				break;
487 			}
488 		}
489 
490 		set->setObject(personality);
491 	}
492 	// Start device matching.
493 	if (result && doNubMatching && (set->getCount() > 0)) {
494 		IOService::catalogNewDrivers(set.get());
495 		generation++;
496 	}
497 	IORWLockUnlock(lock);
498 
499 finish:
500 
501 	return result;
502 }
503 
504 bool
505 IOCatalogue::removeDrivers(bool doNubMatching, bool (^shouldRemove)(OSDictionary *personality))
506 {
507 	OSSharedPtr<OSOrderedSet> set;
508 	OSSharedPtr<OSCollectionIterator> iter;
509 	OSDictionary         * dict;
510 	OSArray              * array;
511 	const OSSymbol       * key;
512 	unsigned int           idx;
513 
514 	set = OSOrderedSet::withCapacity(10,
515 	    IOServiceOrdering,
516 	    (void *)(gIOProbeScoreKey.get()));
517 	if (!set) {
518 		return false;
519 	}
520 	iter = OSCollectionIterator::withCollection(personalities.get());
521 	if (!iter) {
522 		return false;
523 	}
524 
525 	IORWLockWrite(lock);
526 	while ((key = (const OSSymbol *) iter->getNextObject())) {
527 		array = (OSArray *) personalities->getObject(key);
528 		if (array) {
529 			for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
530 				if (shouldRemove(dict)) {
531 					set->setObject(dict);
532 					array->removeObject(idx);
533 					idx--;
534 				}
535 			}
536 		}
537 		// Start device matching.
538 		if (doNubMatching && (set->getCount() > 0)) {
539 			IOService::catalogNewDrivers(set.get());
540 			generation++;
541 		}
542 	}
543 	IORWLockUnlock(lock);
544 
545 	return true;
546 }
547 
548 /*********************************************************************
549 * Remove drivers from the catalog which match the
550 * properties in the matching dictionary.
551 *********************************************************************/
552 bool
removeDrivers(OSDictionary * matching,bool doNubMatching)553 IOCatalogue::removeDrivers(
554 	OSDictionary * matching,
555 	bool doNubMatching)
556 {
557 	if (!matching) {
558 		return false;
559 	}
560 	return removeDrivers(doNubMatching, ^(OSDictionary *dict) {
561 		/* This comparison must be done with only the keys in the
562 		 * "matching" dict to enable general searches.
563 		 */
564 		return dict->isEqualTo(matching, matching);
565 	});
566 }
567 
568 // Return the generation count.
569 SInt32
getGenerationCount(void) const570 IOCatalogue::getGenerationCount(void) const
571 {
572 	return generation;
573 }
574 /*********************************************************************
575 *********************************************************************/
576 /* static */
577 
578 bool
personalityIsBoot(OSDictionary * match)579 IOCatalogue::personalityIsBoot(OSDictionary * match)
580 {
581 	OSString * moduleName;
582 	OSSharedPtr<OSKext> theKext;
583 
584 	moduleName = OSDynamicCast(OSString, match->getObject(gIOModuleIdentifierKey.get()));
585 	if (!moduleName) {
586 		return true;
587 	}
588 	theKext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
589 	if (!theKext) {
590 		return true;
591 	}
592 	switch (theKext->kc_type) {
593 	case KCKindPrimary:
594 		return true;
595 	case KCKindUnknown:
596 		return true;
597 	case KCKindNone:
598 		return false;
599 	case KCKindAuxiliary:
600 		return false;
601 	case KCKindPageable:
602 		return false;
603 	default:
604 		assert(false);
605 		return false;
606 	}
607 }
608 
609 // Check to see if kernel module has been loaded already, and request its load.
610 bool
isModuleLoaded(OSDictionary * driver,OSObject ** kextRef) const611 IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
612 {
613 	OSString * moduleName = NULL;
614 	OSString * publisherName = NULL;
615 	OSReturn   ret;
616 
617 	if (kextRef) {
618 		*kextRef = NULL;
619 	}
620 	if (!driver) {
621 		return false;
622 	}
623 
624 	/* The personalities of codeless kexts often contain the bundle ID of the
625 	 * kext they reference, and not the bundle ID of the codeless kext itself.
626 	 * The prelinked kernel needs to know the bundle ID of the codeless kext
627 	 * so it can include these personalities, so OSKext stores that bundle ID
628 	 * in the IOPersonalityPublisher key, and we record it as requested here.
629 	 */
630 	publisherName = OSDynamicCast(OSString,
631 	    driver->getObject(kIOPersonalityPublisherKey));
632 	OSKext::recordIdentifierRequest(publisherName);
633 
634 	moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey.get()));
635 	if (moduleName) {
636 		ret = OSKext::loadKextWithIdentifier(moduleName, kextRef);
637 		if (kOSKextReturnDeferred == ret) {
638 			// a request has been queued but the module isn't necessarily
639 			// loaded yet, so stall.
640 			return false;
641 		}
642 		OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey.get()));
643 		if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) {
644 			OSSharedPtr<OSObject> dextRef;
645 			ret = OSKext::loadKextWithIdentifier(moduleDextName, dextRef);
646 		}
647 		// module is present or never will be
648 		return true;
649 	}
650 
651 	/* If a personality doesn't hold the "CFBundleIdentifier" or "CFBundleIdentifierKernel" key
652 	 * it is assumed to be an "in-kernel" driver.
653 	 */
654 	return true;
655 }
656 
657 bool
isModuleLoaded(OSDictionary * driver,OSSharedPtr<OSObject> & kextRef) const658 IOCatalogue::isModuleLoaded(OSDictionary * driver, OSSharedPtr<OSObject>& kextRef) const
659 {
660 	OSObject* kextRefRaw = NULL;
661 	bool result = isModuleLoaded(driver, &kextRefRaw);
662 	kextRef.reset(kextRefRaw, OSNoRetain);
663 	return result;
664 }
665 
666 /* This function is called after a module has been loaded.
667  * Is invoked from user client call, ultimately from IOKitLib's
668  * IOCatalogueModuleLoaded(). Sent from kextd.
669  */
670 void
moduleHasLoaded(const OSSymbol * moduleName)671 IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName)
672 {
673 	startMatching(moduleName);
674 
675 	(void) OSKext::setDeferredLoadSucceeded();
676 	(void) OSKext::considerRebuildOfPrelinkedKernel();
677 }
678 
679 void
moduleHasLoaded(const char * moduleName)680 IOCatalogue::moduleHasLoaded(const char * moduleName)
681 {
682 	OSSharedPtr<const OSSymbol> name;
683 
684 	name = OSSymbol::withCString(moduleName);
685 	moduleHasLoaded(name.get());
686 }
687 
688 // xxx - return is really OSReturn/kern_return_t
689 IOReturn
unloadModule(OSString * moduleName) const690 IOCatalogue::unloadModule(OSString * moduleName) const
691 {
692 	return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
693 }
694 
695 IOReturn
terminateDrivers(OSDictionary * matching,io_name_t className,bool asynchronous)696 IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className, bool asynchronous)
697 {
698 	OSDictionary         * dict;
699 	OSSharedPtr<OSIterator> iter;
700 	IOService            * service;
701 	IOReturn               ret;
702 
703 	ret = kIOReturnSuccess;
704 	dict = NULL;
705 	iter = IORegistryIterator::iterateOver(gIOServicePlane,
706 	    kIORegistryIterateRecursively);
707 	if (!iter) {
708 		return kIOReturnNoMemory;
709 	}
710 
711 	if (matching) {
712 		OSKext::uniquePersonalityProperties( matching, false );
713 	}
714 
715 	// terminate instances.
716 	do {
717 		iter->reset();
718 		while ((service = (IOService *)iter->getNextObject())) {
719 			if (className && !service->metaCast(className)) {
720 				continue;
721 			}
722 			if (matching) {
723 				/* Terminate only for personalities that match the matching dictionary.
724 				 * This comparison must be done with only the keys in the
725 				 * "matching" dict to enable general matching.
726 				 */
727 				dict = service->getPropertyTable();
728 				if (!dict) {
729 					continue;
730 				}
731 				if (!dict->isEqualTo(matching, matching)) {
732 					continue;
733 				}
734 			}
735 
736 			OSKext     * kext;
737 			OSSharedPtr<OSString> dextBundleID;
738 			const char * bundleIDStr;
739 			OSObject   * prop;
740 			bool         okToTerminate;
741 			bool         isDext = service->hasUserServer();
742 			for (okToTerminate = true;;) {
743 				if (isDext) {
744 					dextBundleID = OSDynamicPtrCast<OSString>(service->copyProperty(gIOModuleIdentifierKey.get()));
745 					if (!dextBundleID) {
746 						break;
747 					}
748 					bundleIDStr = dextBundleID->getCStringNoCopy();
749 				} else {
750 					kext = service->getMetaClass()->getKext();
751 					if (!kext) {
752 						break;
753 					}
754 					bundleIDStr = kext->getIdentifierCString();
755 					prop = kext->getPropertyForHostArch(kOSBundleAllowUserTerminateKey);
756 					if (prop) {
757 						okToTerminate = (kOSBooleanTrue == prop);
758 						break;
759 					}
760 				}
761 				if (!bundleIDStr) {
762 					break;
763 				}
764 				if (!strcmp(kOSKextKernelIdentifier, bundleIDStr)) {
765 					okToTerminate = false;
766 					break;
767 				}
768 				if (!strncmp("com.apple.", bundleIDStr, strlen("com.apple."))) {
769 					okToTerminate = false;
770 					break;
771 				}
772 				break;
773 			}
774 			if (!okToTerminate) {
775 #if DEVELOPMENT || DEBUG
776 				okToTerminate = true;
777 #endif /* DEVELOPMENT || DEBUG */
778 				IOLog("%sallowing kextunload terminate for bundleID %s\n",
779 				    okToTerminate ? "" : "dis", bundleIDStr ? bundleIDStr : "?");
780 				if (!okToTerminate) {
781 					ret = kIOReturnUnsupported;
782 					break;
783 				}
784 			}
785 			IOOptionBits terminateOptions = kIOServiceRequired;
786 			if (!asynchronous) {
787 				terminateOptions |= kIOServiceSynchronous;
788 			}
789 			if (isDext) {
790 				terminateOptions |= kIOServiceTerminateNeedWillTerminate;
791 			}
792 			if (!service->terminate(terminateOptions)) {
793 				ret = kIOReturnUnsupported;
794 				break;
795 			}
796 		}
797 	} while (!service && !iter->isValid());
798 
799 	return ret;
800 }
801 
802 IOReturn
_removeDrivers(OSDictionary * matching)803 IOCatalogue::_removeDrivers(OSDictionary * matching)
804 {
805 	IOReturn               ret = kIOReturnSuccess;
806 	OSSharedPtr<OSCollectionIterator> iter;
807 	OSDictionary         * dict;
808 	OSArray              * array;
809 	const OSSymbol       * key;
810 	unsigned int           idx;
811 
812 	// remove configs from catalog.
813 
814 	iter = OSCollectionIterator::withCollection(personalities.get());
815 	if (!iter) {
816 		return kIOReturnNoMemory;
817 	}
818 
819 	while ((key = (const OSSymbol *) iter->getNextObject())) {
820 		array = (OSArray *) personalities->getObject(key);
821 		if (array) {
822 			for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
823 				/* Remove from the catalogue's array any personalities
824 				 * that match the matching dictionary.
825 				 * This comparison must be done with only the keys in the
826 				 * "matching" dict to enable general matching.
827 				 */
828 				if (dict->isEqualTo(matching, matching)) {
829 					array->removeObject(idx);
830 					idx--;
831 				}
832 			}
833 		}
834 	}
835 
836 	return ret;
837 }
838 
839 IOReturn
terminateDrivers(OSDictionary * matching)840 IOCatalogue::terminateDrivers(OSDictionary * matching)
841 {
842 	IOReturn ret;
843 
844 	if (!matching) {
845 		return kIOReturnBadArgument;
846 	}
847 	ret = terminateDrivers(matching, NULL, false);
848 	IORWLockWrite(lock);
849 	if (kIOReturnSuccess == ret) {
850 		ret = _removeDrivers(matching);
851 	}
852 	IORWLockUnlock(lock);
853 
854 	return ret;
855 }
856 
857 IOReturn
terminateDriversForUserspaceReboot()858 IOCatalogue::terminateDriversForUserspaceReboot()
859 {
860 	IOReturn                ret = kIOReturnSuccess;
861 
862 #if !NO_KEXTD
863 	OSSharedPtr<OSIterator> iter;
864 	IOService             * service;
865 	bool                    isDeferredMatch;
866 	bool                    isDext;
867 	bool                    preserveDuringUserspaceReboot;
868 	IOOptionBits            terminateOptions;
869 
870 	iter = IORegistryIterator::iterateOver(gIOServicePlane,
871 	    kIORegistryIterateRecursively);
872 	if (!iter) {
873 		return kIOReturnNoMemory;
874 	}
875 
876 	do {
877 		iter->reset();
878 		while ((service = (IOService *)iter->getNextObject())) {
879 			isDeferredMatch = service->propertyHasValue(gIOMatchDeferKey, kOSBooleanTrue);
880 			isDext = service->hasUserServer();
881 			if (isDeferredMatch || isDext) {
882 				OSSharedPtr<OSObject> prop = service->copyProperty(gIOUserServerPreserveUserspaceRebootKey, gIOServicePlane, kIORegistryIterateRecursively | kIORegistryIterateParents);
883 				preserveDuringUserspaceReboot = prop == kOSBooleanTrue;
884 				if (preserveDuringUserspaceReboot) {
885 					IOLog("preserving service %s-0x%llx during userspace reboot\n", service->getName(), service->getRegistryEntryID());
886 					continue;
887 				}
888 
889 				if (isDext) {
890 					OSSharedPtr<OSString> name = OSDynamicPtrCast<OSString>(service->copyProperty(gIOUserServerNameKey));
891 					const char *userServerName = NULL;
892 					if (name) {
893 						userServerName = name->getCStringNoCopy();
894 					}
895 					IOLog("terminating service %s-0x%llx [dext %s]\n", service->getName(), service->getRegistryEntryID(), userServerName ? userServerName : "(null)");
896 				} else {
897 					OSKext *kext = service->getMetaClass()->getKext();
898 					const char *bundleID = NULL;
899 					if (kext) {
900 						bundleID = kext->getIdentifierCString();
901 					}
902 					IOLog("terminating service %s-0x%llx [kext %s]\n", service->getName(), service->getRegistryEntryID(), bundleID ? bundleID : "(null)");
903 				}
904 				terminateOptions = kIOServiceRequired | kIOServiceSynchronous;
905 				if (isDext) {
906 					terminateOptions |= kIOServiceTerminateNeedWillTerminate;
907 				}
908 				if (!service->terminate(terminateOptions)) {
909 					IOLog("failed to terminate service %s-0x%llx\n", service->getName(), service->getRegistryEntryID());
910 					ret = kIOReturnUnsupported;
911 					break;
912 				}
913 			}
914 		}
915 	} while (!service && !iter->isValid());
916 #endif
917 
918 	return ret;
919 }
920 
921 IOReturn
resetAfterUserspaceReboot(void)922 IOCatalogue::resetAfterUserspaceReboot(void)
923 {
924 	OSSharedPtr<OSIterator> iter;
925 	IOService             * service;
926 
927 	iter = IORegistryIterator::iterateOver(gIOServicePlane,
928 	    kIORegistryIterateRecursively);
929 	if (!iter) {
930 		return kIOReturnNoMemory;
931 	}
932 
933 	do {
934 		iter->reset();
935 		while ((service = (IOService *)iter->getNextObject())) {
936 			service->resetRematchProperties();
937 		}
938 	} while (!service && !iter->isValid());
939 
940 	/* Remove all dext personalities */
941 	removeDrivers(false, ^(OSDictionary *dict) {
942 		return dict->getObject(gIOUserServerNameKey) != NULL;
943 	});
944 
945 	return kIOReturnSuccess;
946 }
947 
948 IOReturn
terminateDriversForModule(OSString * moduleName,bool unload,bool asynchronous)949 IOCatalogue::terminateDriversForModule(
950 	OSString * moduleName,
951 	bool unload,
952 	bool asynchronous)
953 {
954 	IOReturn ret;
955 	OSSharedPtr<OSDictionary> dict;
956 	OSSharedPtr<OSKext> kext;
957 	bool isLoaded = false;
958 	bool isDext = false;
959 
960 	/* Check first if the kext currently has any linkage dependents;
961 	 * in such a case the unload would fail so let's not terminate any
962 	 * IOServices (since doing so typically results in a panic when there
963 	 * are loaded dependencies). Note that we aren't locking the kext here
964 	 * so it might lose or gain dependents by the time we call unloadModule();
965 	 * I think that's ok, our unload can fail if a kext comes in on top of
966 	 * this one even after we've torn down IOService objects. Conversely,
967 	 * if we fail the unload here and then lose a library, the autounload
968 	 * thread will get us in short order.
969 	 */
970 	if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
971 		isLoaded = true;
972 
973 		if (!OSKext::canUnloadKextWithIdentifier(moduleName,
974 		    /* checkClasses */ false)) {
975 			ret = kOSKextReturnInUse;
976 			goto finish;
977 		}
978 	}
979 	kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
980 	if (kext) {
981 		isDext = kext->isDriverKit();
982 	}
983 
984 	dict = OSDictionary::withCapacity(1);
985 	if (!dict) {
986 		ret = kIOReturnNoMemory;
987 		goto finish;
988 	}
989 
990 	dict->setObject(gIOModuleIdentifierKey.get(), moduleName);
991 
992 	ret = terminateDrivers(dict.get(), NULL, asynchronous);
993 
994 	if (isDext) {
995 		/* Force rematching after removing personalities. Dexts are never considered to be "loaded" (from OSKext),
996 		 * so we can't call unloadModule() to remove personalities and start rematching. */
997 		removeDrivers(dict.get(), true);
998 	} else {
999 		/* No goto between IOLock calls!
1000 		 */
1001 		IORWLockWrite(lock);
1002 		if (kIOReturnSuccess == ret) {
1003 			ret = _removeDrivers(dict.get());
1004 		}
1005 
1006 		// Unload the module itself.
1007 		if (unload && isLoaded && ret == kIOReturnSuccess) {
1008 			ret = unloadModule(moduleName);
1009 		}
1010 		IORWLockUnlock(lock);
1011 	}
1012 
1013 finish:
1014 	return ret;
1015 }
1016 
1017 IOReturn
terminateDriversForModule(const char * moduleName,bool unload,bool asynchronous)1018 IOCatalogue::terminateDriversForModule(
1019 	const char * moduleName,
1020 	bool unload,
1021 	bool asynchronous)
1022 {
1023 	OSSharedPtr<OSString> name;
1024 	IOReturn ret;
1025 
1026 	name = OSString::withCString(moduleName);
1027 	if (!name) {
1028 		return kIOReturnNoMemory;
1029 	}
1030 
1031 	ret = terminateDriversForModule(name.get(), unload, asynchronous);
1032 
1033 	return ret;
1034 }
1035 
1036 #if defined(__i386__) || defined(__x86_64__)
1037 bool
startMatching(OSDictionary * matching)1038 IOCatalogue::startMatching( OSDictionary * matching )
1039 {
1040 	OSSharedPtr<OSOrderedSet> set;
1041 
1042 	if (!matching) {
1043 		return false;
1044 	}
1045 
1046 	set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
1047 	    (void *)(gIOProbeScoreKey.get()));
1048 	if (!set) {
1049 		return false;
1050 	}
1051 
1052 	IORWLockRead(lock);
1053 
1054 	personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
1055 		OSArray      * array;
1056 		OSDictionary * dict;
1057 		unsigned int   idx;
1058 
1059 		array = (OSArray *) value;
1060 		for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
1061 		        /* This comparison must be done with only the keys in the
1062 		         * "matching" dict to enable general matching.
1063 		         */
1064 		        if (dict->isEqualTo(matching, matching)) {
1065 		                set->setObject(dict);
1066 			}
1067 		}
1068 		return false;
1069 	});
1070 
1071 	// Start device matching.
1072 	if (set->getCount() > 0) {
1073 		IOService::catalogNewDrivers(set.get());
1074 		generation++;
1075 	}
1076 
1077 	IORWLockUnlock(lock);
1078 
1079 	return true;
1080 }
1081 #endif /* defined(__i386__) || defined(__x86_64__) */
1082 
1083 bool
startMatching(const OSSymbol * moduleName)1084 IOCatalogue::startMatching( const OSSymbol * moduleName )
1085 {
1086 	OSSharedPtr<OSOrderedSet> set;
1087 	OSSharedPtr<OSKext>       kext;
1088 	OSSharedPtr<OSArray>      servicesToTerminate;
1089 
1090 	if (!moduleName) {
1091 		return false;
1092 	}
1093 
1094 	set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
1095 	    (void *)(gIOProbeScoreKey.get()));
1096 	if (!set) {
1097 		return false;
1098 	}
1099 
1100 	/*
1101 	 * Be sure to call into OSKext outside of
1102 	 * IORWLock, otherwise it can trigger a lock
1103 	 * inversion.
1104 	 */
1105 	kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
1106 
1107 	IORWLockRead(lock);
1108 
1109 	if (kext && kext->isDriverKit()) {
1110 		/* We're here because kernelmanagerd called IOCatalogueModuleLoaded after launching a dext.
1111 		 * Determine what providers the dext would match against. If there's something already attached
1112 		 * to the provider, terminate it.
1113 		 *
1114 		 * This is only safe to do for HID dexts.
1115 		 */
1116 		OSSharedPtr<OSArray> dextPersonalities = kext->copyPersonalitiesArray();
1117 
1118 		if (!dextPersonalities) {
1119 			return false;
1120 		}
1121 
1122 		servicesToTerminate = OSArray::withCapacity(1);
1123 		if (!servicesToTerminate) {
1124 			return false;
1125 		}
1126 
1127 		dextPersonalities->iterateObjects(^bool (OSObject * obj) {
1128 			OSDictionary * personality = OSDynamicCast(OSDictionary, obj);
1129 			OSSharedPtr<OSIterator> iter;
1130 			IOService * provider;
1131 			OSSharedPtr<IOService> service;
1132 			const OSSymbol * category;
1133 
1134 			if (personality) {
1135 			        category = OSDynamicCast(OSSymbol, personality->getObject(gIOMatchCategoryKey));
1136 			        if (!category) {
1137 			                category = gIODefaultMatchCategoryKey;
1138 				}
1139 			        iter = IOService::getMatchingServices(personality);
1140 
1141 			        while (iter && (provider = OSDynamicCast(IOService, iter->getNextObject()))) {
1142 			                if (provider->metaCast(gIOHIDInterfaceClassName.get()) != NULL) {
1143 			                        service.reset(provider->copyClientWithCategory(category), OSNoRetain);
1144 			                        if (service) {
1145 			                                servicesToTerminate->setObject(service);
1146 						}
1147 					}
1148 				}
1149 			}
1150 
1151 			return false;
1152 		});
1153 	}
1154 
1155 	personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
1156 		OSArray      * array;
1157 		OSDictionary * dict;
1158 		OSObject     * moduleIdentifierKernel;
1159 		OSObject     * moduleIdentifier;
1160 		unsigned int   idx;
1161 
1162 		array = (OSArray *) value;
1163 		for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
1164 		        moduleIdentifierKernel = dict->getObject(gIOModuleIdentifierKernelKey.get());
1165 		        moduleIdentifier = dict->getObject(gIOModuleIdentifierKey.get());
1166 		        if ((moduleIdentifierKernel && moduleName->isEqualTo(moduleIdentifierKernel)) ||
1167 		        (moduleIdentifier && moduleName->isEqualTo(moduleIdentifier))) {
1168 		                set->setObject(dict);
1169 			}
1170 		}
1171 		return false;
1172 	});
1173 
1174 	if (servicesToTerminate) {
1175 		servicesToTerminate->iterateObjects(^bool (OSObject * obj) {
1176 			IOService * service = OSDynamicCast(IOService, obj);
1177 			if (service) {
1178 			        IOOptionBits terminateOptions = kIOServiceRequired;
1179 			        if (service->hasUserServer()) {
1180 			                terminateOptions |= kIOServiceTerminateNeedWillTerminate;
1181 				}
1182 			        if (!service->terminate(terminateOptions)) {
1183 			                IOLog("%s: failed to terminate service %s-0x%qx with options %08llx for new dext %s\n", __FUNCTION__, service->getName(), service->getRegistryEntryID(), (long long)terminateOptions, moduleName->getCStringNoCopy());
1184 				}
1185 			}
1186 			return false;
1187 		});
1188 	}
1189 
1190 	// Start device matching.
1191 	if (set->getCount() > 0) {
1192 		IOService::catalogNewDrivers(set.get());
1193 		generation++;
1194 	}
1195 
1196 	IORWLockUnlock(lock);
1197 
1198 	return true;
1199 }
1200 
1201 void
reset(void)1202 IOCatalogue::reset(void)
1203 {
1204 	IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
1205 	    /* doMatching */ false);
1206 	return;
1207 }
1208 
1209 bool
resetAndAddDrivers(OSArray * drivers,bool doNubMatching)1210 IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
1211 {
1212 	bool                   result              = false;
1213 	OSArray              * newPersonalities    = NULL;// do not release
1214 	const OSSymbol       * key;
1215 	OSArray              * array;
1216 	OSDictionary         * thisNewPersonality   = NULL;// do not release
1217 	OSDictionary         * thisOldPersonality   = NULL;// do not release
1218 	OSSharedPtr<OSDictionary> myKexts;
1219 	OSSharedPtr<OSCollectionIterator> iter;
1220 	OSSharedPtr<OSOrderedSet> matchSet;
1221 	signed int             idx, newIdx;
1222 
1223 	if (drivers) {
1224 		newPersonalities = OSDynamicCast(OSArray, drivers);
1225 		if (!newPersonalities) {
1226 			goto finish;
1227 		}
1228 	}
1229 	matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
1230 	    (void *)(gIOProbeScoreKey.get()));
1231 	if (!matchSet) {
1232 		goto finish;
1233 	}
1234 	iter = OSCollectionIterator::withCollection(personalities.get());
1235 	if (!iter) {
1236 		goto finish;
1237 	}
1238 
1239 	/* need copy of loaded kexts so we can check if for loaded modules without
1240 	 * taking the OSKext lock.  There is a potential of deadlocking if we get
1241 	 * an OSKext via the normal path.  See 14672140.
1242 	 */
1243 	myKexts = OSKext::copyKexts();
1244 
1245 	result = true;
1246 
1247 	IOLog("Resetting IOCatalogue.\n");
1248 
1249 	/* No goto finish from here to unlock.
1250 	 */
1251 	IORWLockWrite(lock);
1252 
1253 	while ((key = (const OSSymbol *) iter->getNextObject())) {
1254 		array = (OSArray *) personalities->getObject(key);
1255 		if (!array) {
1256 			continue;
1257 		}
1258 
1259 		for (idx = 0;
1260 		    (thisOldPersonality = (OSDictionary *) array->getObject(idx));
1261 		    idx++) {
1262 			if (thisOldPersonality->getObject("KernelConfigTable")) {
1263 				continue;
1264 			}
1265 			thisNewPersonality = NULL;
1266 
1267 			if (newPersonalities) {
1268 				for (newIdx = 0;
1269 				    (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
1270 				    newIdx++) {
1271 					/* Unlike in other functions, this comparison must be exact!
1272 					 * The catalogue must be able to contain personalities that
1273 					 * are proper supersets of others.
1274 					 * Do not compare just the properties present in one driver
1275 					 * personality or the other.
1276 					 */
1277 					if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
1278 						/* skip thisNewPersonality if it is not an OSDictionary */
1279 						continue;
1280 					}
1281 					if (thisNewPersonality->isEqualTo(thisOldPersonality)) {
1282 						break;
1283 					}
1284 				}
1285 			}
1286 			if (thisNewPersonality) {
1287 				// dup, ignore
1288 				newPersonalities->removeObject(newIdx);
1289 			} else {
1290 				// not in new set - remove
1291 				// only remove dictionary if this module in not loaded - 9953845
1292 				if (isModuleLoadedNoOSKextLock(myKexts.get(), thisOldPersonality) == false) {
1293 					if (matchSet) {
1294 						matchSet->setObject(thisOldPersonality);
1295 					}
1296 					array->removeObject(idx);
1297 					idx--;
1298 				}
1299 			}
1300 		} // for...
1301 	} // while...
1302 
1303 	// add new
1304 	if (newPersonalities) {
1305 		for (newIdx = 0;
1306 		    (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
1307 		    newIdx++) {
1308 			if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
1309 				/* skip thisNewPersonality if it is not an OSDictionary */
1310 				continue;
1311 			}
1312 
1313 			OSKext::uniquePersonalityProperties(thisNewPersonality);
1314 			addPersonality(thisNewPersonality);
1315 			matchSet->setObject(thisNewPersonality);
1316 		}
1317 	}
1318 
1319 	/* Finally, start device matching on all new & removed personalities.
1320 	 */
1321 	if (result && doNubMatching && (matchSet->getCount() > 0)) {
1322 		IOService::catalogNewDrivers(matchSet.get());
1323 		generation++;
1324 	}
1325 
1326 	IORWLockUnlock(lock);
1327 
1328 finish:
1329 
1330 	return result;
1331 }
1332 
1333 bool
serialize(OSSerialize * s) const1334 IOCatalogue::serialize(OSSerialize * s) const
1335 {
1336 	if (!s) {
1337 		return false;
1338 	}
1339 
1340 	return super::serialize(s);
1341 }
1342 
1343 bool
serializeData(IOOptionBits kind,OSSerialize * s) const1344 IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
1345 {
1346 	kern_return_t kr = kIOReturnSuccess;
1347 
1348 	switch (kind) {
1349 	case kIOCatalogGetContents:
1350 		kr = KERN_NOT_SUPPORTED;
1351 		break;
1352 
1353 	case kIOCatalogGetModuleDemandList:
1354 		kr = KERN_NOT_SUPPORTED;
1355 		break;
1356 
1357 	case kIOCatalogGetCacheMissList:
1358 		kr = KERN_NOT_SUPPORTED;
1359 		break;
1360 
1361 	case kIOCatalogGetROMMkextList:
1362 		kr = KERN_NOT_SUPPORTED;
1363 		break;
1364 
1365 	default:
1366 		kr = kIOReturnBadArgument;
1367 		break;
1368 	}
1369 
1370 	return kr;
1371 }
1372 
1373 /* isModuleLoadedNoOSKextLock - used to check to see if a kext is loaded
1374  * without taking the OSKext lock.  We use this to avoid the problem
1375  * where taking the IOCatalog lock then the OSKext lock will dealock when
1376  * a kext load or unload is happening at the same time as IOCatalog changing.
1377  *
1378  * theKexts - is a dictionary of current kexts (from OSKext::copyKexts) with
1379  *      key set to the kext bundle ID and value set to an OSKext object
1380  * theModuleDict - is an IOKit personality dictionary for a given module (kext)
1381  */
1382 static bool
isModuleLoadedNoOSKextLock(OSDictionary * theKexts,OSDictionary * theModuleDict)1383 isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
1384     OSDictionary *theModuleDict)
1385 {
1386 	bool                    myResult = false;
1387 	const OSString *        myBundleID = NULL;// do not release
1388 	OSKext *                myKext = NULL;  // do not release
1389 
1390 	if (theKexts == NULL || theModuleDict == NULL) {
1391 		return myResult;
1392 	}
1393 
1394 	// gIOModuleIdentifierKey is "CFBundleIdentifier"
1395 	myBundleID = OSDynamicCast(OSString,
1396 	    theModuleDict->getObject(gIOModuleIdentifierKey.get()));
1397 	if (myBundleID == NULL) {
1398 		return myResult;
1399 	}
1400 
1401 	myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
1402 	if (myKext) {
1403 		myResult = myKext->isLoaded();
1404 	}
1405 
1406 	return myResult;
1407 }
1408 
1409 
1410 #if PRAGMA_MARK
1411 #pragma mark Obsolete Kext Loading Stuff
1412 #endif
1413 /*********************************************************************
1414  **********************************************************************
1415  ***                  BINARY COMPATIBILITY SECTION                  ***
1416  **********************************************************************
1417  **********************************************************************
1418  * These functions are no longer used are necessary for C++ binary
1419  * compatibility on i386.
1420  **********************************************************************/
1421