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
43extern "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
71OSSharedPtr<IOCatalogue> gIOCatalogue;
72OSSharedPtr<const OSSymbol> gIOClassKey;
73OSSharedPtr<const OSSymbol> gIOProbeScoreKey;
74OSSharedPtr<const OSSymbol> gIOModuleIdentifierKey;
75OSSharedPtr<const OSSymbol> gIOModuleIdentifierKernelKey;
76OSSharedPtr<const OSSymbol> gIOHIDInterfaceClassName;
77IORWLock * 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
90OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
91
92static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
93 OSDictionary *theModuleDict);
94
95
96/*********************************************************************
97*********************************************************************/
98void
99IOCatalogue::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>(source: OSUnserialize(buffer: gIOKernelConfigTables, errorString));
108 if (!array && errorString) {
109 IOLog(format: "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( cString: "IOHIDInterface" );
118
119
120 assert( array && gIOClassKey && gIOProbeScoreKey
121 && gIOModuleIdentifierKey);
122
123 gIOCatalogue = OSMakeShared<IOCatalogue>();
124 assert(gIOCatalogue);
125 rc = gIOCatalogue->init(initArray: array.get());
126 assert(rc);
127}
128
129/*********************************************************************
130* Initialize the IOCatalog object.
131*********************************************************************/
132OSArray *
133IOCatalogue::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(aKey: sym);
143}
144
145void
146IOCatalogue::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(aKey: sym);
156 if (arr) {
157 arr->setObject(dict);
158 } else {
159 OSSharedPtr<OSArray> sharedArr = OSArray::withObjects(objects: (const OSObject **)&dict, count: 1, capacity: 2);
160 personalities->setObject(aKey: sym, anObject: sharedArr.get());
161 }
162}
163
164/*********************************************************************
165* Initialize the IOCatalog object.
166*********************************************************************/
167bool
168IOCatalogue::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(capacity: 32);
180 personalities->setOptions(options: OSCollection::kSort, mask: OSCollection::kSort);
181 for (unsigned int idx = 0; (obj = initArray->getObject(index: idx)); idx++) {
182 dict = OSDynamicCast(OSDictionary, obj);
183 if (!dict) {
184 continue;
185 }
186 OSKext::uniquePersonalityProperties(personalityDict: dict);
187 if (NULL == dict->getObject( aKey: gIOClassKey.get())) {
188 IOLog(format: "Missing or bad \"%s\" key\n",
189 gIOClassKey->getCStringNoCopy());
190 continue;
191 }
192 dict->setObject(aKey: "KernelConfigTable", anObject: 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*********************************************************************/
206void
207IOCatalogue::free( void )
208{
209 panic("");
210}
211
212/*********************************************************************
213*********************************************************************/
214OSPtr<OSOrderedSet>
215IOCatalogue::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( capacity: 1, orderFunc: IOServiceOrdering,
226 orderingContext: (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(aKey: meta->getClassNameSymbol());
236 if (array) {
237 for (idx = 0; (nextTable = (OSDictionary *) array->getObject(index: 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*********************************************************************/
257OSPtr<OSOrderedSet>
258IOCatalogue::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(personalityDict: matching);
270
271 set = OSOrderedSet::withCapacity( capacity: 1, orderFunc: IOServiceOrdering,
272 orderingContext: (void *)(gIOProbeScoreKey.get()));
273 if (!set) {
274 return NULL;
275 }
276 iter = OSCollectionIterator::withCollection(inColl: 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(aKey: key);
284 if (array) {
285 for (idx = 0; (dict = (OSDictionary *) array->getObject(index: 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(aDictionary: matching, keys: matching)) {
290 set->setObject(dict);
291 }
292 }
293 }
294 }
295 *generationCount = getGenerationCount();
296 IORWLockUnlock(lock);
297
298 return set;
299}
300
301bool
302IOCatalogue::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(capacity: 10, orderFunc: IOServiceOrdering,
311 orderingContext: (void *)(gIOProbeScoreKey.get()));
312 if (!set) {
313 goto finish;
314 }
315
316 iter_new = OSCollectionIterator::withCollection(inColl: personalitiesToAdd);
317 if (!iter_new) {
318 goto finish;
319 }
320
321 IORWLockWrite(lock);
322
323 iter_all_personalities = OSCollectionIterator::withCollection(inColl: 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(aKey: key);
337 if (array) {
338 unsigned int idx;
339 OSDictionary *dict;
340 for (idx = 0; (dict = (OSDictionary *) array->getObject(index: idx)); idx++) {
341 if (dict->isEqualTo(aDictionary: matchingForRemove, keys: matchingForRemove)) {
342 set->setObject(dict);
343 array->removeObject(index: 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(personalityDict: personality);
358 OSArray * array = arrayForPersonality(dict: personality);
359 if (!array) {
360 addPersonality(dict: 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(index: 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(aDictionary: 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(newTables: set.get());
389 generation++;
390 }
391
392 IORWLockUnlock(lock);
393
394finish:
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
410bool
411IOCatalogue::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( capacity: 10, orderFunc: IOServiceOrdering,
427 orderingContext: (void *)(gIOProbeScoreKey.get()));
428 if (!set) {
429 goto finish;
430 }
431
432 iter = OSCollectionIterator::withCollection(inColl: 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(format: "IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
451 result = false;
452 break;
453 }
454
455 OSKext::uniquePersonalityProperties(personalityDict: personality);
456
457 // Add driver personality to catalogue.
458
459 OSArray * array = arrayForPersonality(dict: personality);
460 if (!array) {
461 addPersonality(dict: 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(index: 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(aDictionary: 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(newTables: set.get());
495 generation++;
496 }
497 IORWLockUnlock(lock);
498
499finish:
500
501 return result;
502}
503
504bool
505IOCatalogue::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(capacity: 10,
515 orderFunc: IOServiceOrdering,
516 orderingContext: (void *)(gIOProbeScoreKey.get()));
517 if (!set) {
518 return false;
519 }
520 iter = OSCollectionIterator::withCollection(inColl: 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(aKey: key);
528 if (array) {
529 for (idx = 0; (dict = (OSDictionary *) array->getObject(index: idx)); idx++) {
530 if (shouldRemove(dict)) {
531 set->setObject(dict);
532 array->removeObject(index: idx);
533 idx--;
534 }
535 }
536 }
537 // Start device matching.
538 if (doNubMatching && (set->getCount() > 0)) {
539 IOService::catalogNewDrivers(newTables: 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*********************************************************************/
552bool
553IOCatalogue::removeDrivers(
554 OSDictionary * matching,
555 bool doNubMatching)
556{
557 if (!matching) {
558 return false;
559 }
560 return removeDrivers(doNubMatching, shouldRemove: ^(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(aDictionary: matching, keys: matching);
565 });
566}
567
568// Return the generation count.
569SInt32
570IOCatalogue::getGenerationCount(void) const
571{
572 return generation;
573}
574/*********************************************************************
575*********************************************************************/
576/* static */
577
578bool
579IOCatalogue::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(kextIdentifier: 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.
610bool
611IOCatalogue::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(kextIdentifier: publisherName);
633
634 moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey.get()));
635 if (moduleName) {
636 ret = OSKext::loadKextWithIdentifier(kextIdentifier: 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(aString: moduleDextName))) {
644 OSSharedPtr<OSObject> dextRef;
645 ret = OSKext::loadKextWithIdentifier(kextIdentifier: moduleDextName, kextRef&: 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
657bool
658IOCatalogue::isModuleLoaded(OSDictionary * driver, OSSharedPtr<OSObject>& kextRef) const
659{
660 OSObject* kextRefRaw = NULL;
661 bool result = isModuleLoaded(driver, kextRef: &kextRefRaw);
662 kextRef.reset(p: 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 */
670void
671IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName)
672{
673 startMatching(identifier: moduleName);
674
675 (void) OSKext::setDeferredLoadSucceeded();
676 (void) OSKext::considerRebuildOfPrelinkedKernel();
677}
678
679void
680IOCatalogue::moduleHasLoaded(const char * moduleName)
681{
682 OSSharedPtr<const OSSymbol> name;
683
684 name = OSSymbol::withCString(cString: moduleName);
685 moduleHasLoaded(moduleName: name.get());
686}
687
688// xxx - return is really OSReturn/kern_return_t
689IOReturn
690IOCatalogue::unloadModule(OSString * moduleName) const
691{
692 return OSKext::removeKextWithIdentifier(kextIdentifier: moduleName->getCStringNoCopy());
693}
694
695IOReturn
696IOCatalogue::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(plane: gIOServicePlane,
706 options: kIORegistryIterateRecursively);
707 if (!iter) {
708 return kIOReturnNoMemory;
709 }
710
711 if (matching) {
712 OSKext::uniquePersonalityProperties( personalityDict: matching, defaultAddKernelBundleIdentifier: false );
713 }
714
715 // terminate instances.
716 do {
717 iter->reset();
718 while ((service = (IOService *)iter->getNextObject())) {
719 if (className && !service->metaCast(toMeta: 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(aDictionary: matching, keys: 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>(source: service->copyProperty(aKey: 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, s2: bundleIDStr)) {
765 okToTerminate = false;
766 break;
767 }
768 if (!strncmp(s1: "com.apple.", s2: bundleIDStr, n: strlen(s: "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(format: "%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(options: terminateOptions)) {
793 ret = kIOReturnUnsupported;
794 break;
795 }
796 }
797 } while (!service && !iter->isValid());
798
799 return ret;
800}
801
802IOReturn
803IOCatalogue::_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(inColl: personalities.get());
815 if (!iter) {
816 return kIOReturnNoMemory;
817 }
818
819 while ((key = (const OSSymbol *) iter->getNextObject())) {
820 array = (OSArray *) personalities->getObject(aKey: key);
821 if (array) {
822 for (idx = 0; (dict = (OSDictionary *) array->getObject(index: 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(aDictionary: matching, keys: matching)) {
829 array->removeObject(index: idx);
830 idx--;
831 }
832 }
833 }
834 }
835
836 return ret;
837}
838
839IOReturn
840IOCatalogue::terminateDrivers(OSDictionary * matching)
841{
842 IOReturn ret;
843
844 if (!matching) {
845 return kIOReturnBadArgument;
846 }
847 ret = terminateDrivers(matching, NULL, asynchronous: false);
848 IORWLockWrite(lock);
849 if (kIOReturnSuccess == ret) {
850 ret = _removeDrivers(matching);
851 }
852 IORWLockUnlock(lock);
853
854 return ret;
855}
856
857IOReturn
858IOCatalogue::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(plane: gIOServicePlane,
871 options: kIORegistryIterateRecursively);
872 if (!iter) {
873 return kIOReturnNoMemory;
874 }
875
876 do {
877 iter->reset();
878 while ((service = (IOService *)iter->getNextObject())) {
879 isDeferredMatch = service->propertyHasValue(aKey: gIOMatchDeferKey, value: kOSBooleanTrue);
880 isDext = service->hasUserServer();
881 if (isDeferredMatch || isDext) {
882 OSSharedPtr<OSObject> prop = service->copyProperty(aKey: gIOUserServerPreserveUserspaceRebootKey, plane: gIOServicePlane, options: kIORegistryIterateRecursively | kIORegistryIterateParents);
883 preserveDuringUserspaceReboot = prop == kOSBooleanTrue;
884 if (preserveDuringUserspaceReboot) {
885 IOLog(format: "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>(source: service->copyProperty(aKey: gIOUserServerNameKey));
891 const char *userServerName = NULL;
892 if (name) {
893 userServerName = name->getCStringNoCopy();
894 }
895 IOLog(format: "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(format: "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(options: terminateOptions)) {
909 IOLog(format: "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
921IOReturn
922IOCatalogue::resetAfterUserspaceReboot(void)
923{
924 OSSharedPtr<OSIterator> iter;
925 IOService * service;
926
927 iter = IORegistryIterator::iterateOver(plane: gIOServicePlane,
928 options: 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(doNubMatching: false, shouldRemove: ^(OSDictionary *dict) {
942 return dict->getObject(aKey: gIOUserServerNameKey) != NULL;
943 });
944
945 return kIOReturnSuccess;
946}
947
948IOReturn
949IOCatalogue::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(kextIdentifier: moduleName->getCStringNoCopy())) {
971 isLoaded = true;
972
973 if (!OSKext::canUnloadKextWithIdentifier(kextIdentifier: moduleName,
974 /* checkClasses */ checkClassesFlag: false)) {
975 ret = kOSKextReturnInUse;
976 goto finish;
977 }
978 }
979 kext = OSKext::lookupKextWithIdentifier(kextIdentifier: moduleName->getCStringNoCopy());
980 if (kext) {
981 isDext = kext->isDriverKit();
982 }
983
984 dict = OSDictionary::withCapacity(capacity: 1);
985 if (!dict) {
986 ret = kIOReturnNoMemory;
987 goto finish;
988 }
989
990 dict->setObject(aKey: gIOModuleIdentifierKey.get(), anObject: moduleName);
991
992 ret = terminateDrivers(matching: 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(matching: dict.get(), doNubMatching: true);
998 } else {
999 /* No goto between IOLock calls!
1000 */
1001 IORWLockWrite(lock);
1002 if (kIOReturnSuccess == ret) {
1003 ret = _removeDrivers(matching: 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
1013finish:
1014 return ret;
1015}
1016
1017IOReturn
1018IOCatalogue::terminateDriversForModule(
1019 const char * moduleName,
1020 bool unload,
1021 bool asynchronous)
1022{
1023 OSSharedPtr<OSString> name;
1024 IOReturn ret;
1025
1026 name = OSString::withCString(cString: moduleName);
1027 if (!name) {
1028 return kIOReturnNoMemory;
1029 }
1030
1031 ret = terminateDriversForModule(moduleName: name.get(), unload, asynchronous);
1032
1033 return ret;
1034}
1035
1036#if defined(__i386__) || defined(__x86_64__)
1037bool
1038IOCatalogue::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
1083bool
1084IOCatalogue::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(capacity: 10, orderFunc: IOServiceOrdering,
1095 orderingContext: (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(kextIdentifier: 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(capacity: 1);
1123 if (!servicesToTerminate) {
1124 return false;
1125 }
1126
1127 dextPersonalities->iterateObjects(block: ^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(matching: personality);
1140
1141 while (iter && (provider = OSDynamicCast(IOService, iter->getNextObject()))) {
1142 if (provider->metaCast(toMeta: gIOHIDInterfaceClassName.get()) != NULL) {
1143 service.reset(p: 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(block: ^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(index: idx)); idx++) {
1164 moduleIdentifierKernel = dict->getObject(aKey: gIOModuleIdentifierKernelKey.get());
1165 moduleIdentifier = dict->getObject(aKey: gIOModuleIdentifierKey.get());
1166 if ((moduleIdentifierKernel && moduleName->isEqualTo(anObject: moduleIdentifierKernel)) ||
1167 (moduleIdentifier && moduleName->isEqualTo(anObject: moduleIdentifier))) {
1168 set->setObject(dict);
1169 }
1170 }
1171 return false;
1172 });
1173
1174 if (servicesToTerminate) {
1175 servicesToTerminate->iterateObjects(block: ^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(options: terminateOptions)) {
1183 IOLog(format: "%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(newTables: set.get());
1193 generation++;
1194 }
1195
1196 IORWLockUnlock(lock);
1197
1198 return true;
1199}
1200
1201void
1202IOCatalogue::reset(void)
1203{
1204 IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
1205 /* doMatching */ doNubMatching: false);
1206 return;
1207}
1208
1209bool
1210IOCatalogue::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(capacity: 10, orderFunc: IOServiceOrdering,
1230 orderingContext: (void *)(gIOProbeScoreKey.get()));
1231 if (!matchSet) {
1232 goto finish;
1233 }
1234 iter = OSCollectionIterator::withCollection(inColl: 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(format: "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(aKey: key);
1255 if (!array) {
1256 continue;
1257 }
1258
1259 for (idx = 0;
1260 (thisOldPersonality = (OSDictionary *) array->getObject(index: idx));
1261 idx++) {
1262 if (thisOldPersonality->getObject(aKey: "KernelConfigTable")) {
1263 continue;
1264 }
1265 thisNewPersonality = NULL;
1266
1267 if (newPersonalities) {
1268 for (newIdx = 0;
1269 (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(index: 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(aDictionary: thisOldPersonality)) {
1282 break;
1283 }
1284 }
1285 }
1286 if (thisNewPersonality) {
1287 // dup, ignore
1288 newPersonalities->removeObject(index: newIdx);
1289 } else {
1290 // not in new set - remove
1291 // only remove dictionary if this module in not loaded - 9953845
1292 if (isModuleLoadedNoOSKextLock(theKexts: myKexts.get(), theModuleDict: thisOldPersonality) == false) {
1293 if (matchSet) {
1294 matchSet->setObject(thisOldPersonality);
1295 }
1296 array->removeObject(index: 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(index: 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(personalityDict: thisNewPersonality);
1314 addPersonality(dict: 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(newTables: matchSet.get());
1323 generation++;
1324 }
1325
1326 IORWLockUnlock(lock);
1327
1328finish:
1329
1330 return result;
1331}
1332
1333bool
1334IOCatalogue::serialize(OSSerialize * s) const
1335{
1336 if (!s) {
1337 return false;
1338 }
1339
1340 return super::serialize(serializer: s);
1341}
1342
1343bool
1344IOCatalogue::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 */
1382static bool
1383isModuleLoadedNoOSKextLock(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