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 | extern "C" { |
42 | #include <machine/machine_routines.h> |
43 | #include <libkern/kernel_mach_header.h> |
44 | #include <kern/host.h> |
45 | #include <security/mac_data.h> |
46 | }; |
47 | |
48 | #include <libkern/c++/OSContainers.h> |
49 | #include <libkern/c++/OSUnserialize.h> |
50 | #include <libkern/c++/OSKext.h> |
51 | #include <libkern/OSKextLibPrivate.h> |
52 | #include <libkern/OSDebug.h> |
53 | |
54 | #include <IOKit/IODeviceTreeSupport.h> |
55 | #include <IOKit/IOService.h> |
56 | #include <IOKit/IOCatalogue.h> |
57 | |
58 | #include <IOKit/IOLib.h> |
59 | #include <IOKit/assert.h> |
60 | |
61 | #if PRAGMA_MARK |
62 | #pragma mark Internal Declarations |
63 | #endif |
64 | /********************************************************************* |
65 | *********************************************************************/ |
66 | |
67 | IOCatalogue * gIOCatalogue; |
68 | const OSSymbol * gIOClassKey; |
69 | const OSSymbol * gIOProbeScoreKey; |
70 | const OSSymbol * gIOModuleIdentifierKey; |
71 | IORWLock * gIOCatalogLock; |
72 | |
73 | #if PRAGMA_MARK |
74 | #pragma mark Utility functions |
75 | #endif |
76 | |
77 | #if PRAGMA_MARK |
78 | #pragma mark IOCatalogue class implementation |
79 | #endif |
80 | /********************************************************************* |
81 | *********************************************************************/ |
82 | |
83 | #define super OSObject |
84 | OSDefineMetaClassAndStructors(IOCatalogue, OSObject) |
85 | |
86 | static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts, |
87 | OSDictionary *theModuleDict); |
88 | |
89 | |
90 | /********************************************************************* |
91 | *********************************************************************/ |
92 | void IOCatalogue::initialize(void) |
93 | { |
94 | OSArray * array; |
95 | OSString * errorString; |
96 | bool rc; |
97 | |
98 | extern const char * gIOKernelConfigTables; |
99 | |
100 | array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString)); |
101 | if (!array && errorString) { |
102 | IOLog("KernelConfigTables syntax error: %s\n" , |
103 | errorString->getCStringNoCopy()); |
104 | errorString->release(); |
105 | } |
106 | |
107 | gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey ); |
108 | gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey ); |
109 | gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey ); |
110 | |
111 | assert( array && gIOClassKey && gIOProbeScoreKey |
112 | && gIOModuleIdentifierKey); |
113 | |
114 | gIOCatalogue = new IOCatalogue; |
115 | assert(gIOCatalogue); |
116 | rc = gIOCatalogue->init(array); |
117 | assert(rc); |
118 | array->release(); |
119 | } |
120 | |
121 | /********************************************************************* |
122 | * Initialize the IOCatalog object. |
123 | *********************************************************************/ |
124 | OSArray * IOCatalogue::arrayForPersonality(OSDictionary * dict) |
125 | { |
126 | const OSSymbol * sym; |
127 | |
128 | sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey)); |
129 | if (!sym) return (0); |
130 | |
131 | return ((OSArray *) personalities->getObject(sym)); |
132 | } |
133 | |
134 | void IOCatalogue::addPersonality(OSDictionary * dict) |
135 | { |
136 | const OSSymbol * sym; |
137 | OSArray * arr; |
138 | |
139 | sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey)); |
140 | if (!sym) return; |
141 | arr = (OSArray *) personalities->getObject(sym); |
142 | if (arr) arr->setObject(dict); |
143 | else |
144 | { |
145 | arr = OSArray::withObjects((const OSObject **)&dict, 1, 2); |
146 | personalities->setObject(sym, arr); |
147 | arr->release(); |
148 | } |
149 | } |
150 | |
151 | /********************************************************************* |
152 | * Initialize the IOCatalog object. |
153 | *********************************************************************/ |
154 | bool IOCatalogue::init(OSArray * initArray) |
155 | { |
156 | OSDictionary * dict; |
157 | OSObject * obj; |
158 | |
159 | if ( !super::init() ) |
160 | return false; |
161 | |
162 | generation = 1; |
163 | |
164 | personalities = OSDictionary::withCapacity(32); |
165 | personalities->setOptions(OSCollection::kSort, OSCollection::kSort); |
166 | for (unsigned int idx = 0; (obj = initArray->getObject(idx)); idx++) |
167 | { |
168 | dict = OSDynamicCast(OSDictionary, obj); |
169 | if (!dict) continue; |
170 | OSKext::uniquePersonalityProperties(dict); |
171 | if( 0 == dict->getObject( gIOClassKey )) |
172 | { |
173 | IOLog("Missing or bad \"%s\" key\n" , |
174 | gIOClassKey->getCStringNoCopy()); |
175 | continue; |
176 | } |
177 | dict->setObject("KernelConfigTable" , kOSBooleanTrue); |
178 | addPersonality(dict); |
179 | } |
180 | |
181 | gIOCatalogLock = IORWLockAlloc(); |
182 | lock = gIOCatalogLock; |
183 | |
184 | return true; |
185 | } |
186 | |
187 | /********************************************************************* |
188 | * Release all resources used by IOCatalogue and deallocate. |
189 | * This will probably never be called. |
190 | *********************************************************************/ |
191 | void IOCatalogue::free( void ) |
192 | { |
193 | panic("" ); |
194 | } |
195 | |
196 | /********************************************************************* |
197 | *********************************************************************/ |
198 | OSOrderedSet * |
199 | IOCatalogue::findDrivers( |
200 | IOService * service, |
201 | SInt32 * generationCount) |
202 | { |
203 | OSDictionary * nextTable; |
204 | OSOrderedSet * set; |
205 | OSArray * array; |
206 | const OSMetaClass * meta; |
207 | unsigned int idx; |
208 | |
209 | set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, |
210 | (void *)gIOProbeScoreKey ); |
211 | if( !set ) |
212 | return( 0 ); |
213 | |
214 | IORWLockRead(lock); |
215 | |
216 | meta = service->getMetaClass(); |
217 | while (meta) |
218 | { |
219 | array = (OSArray *) personalities->getObject(meta->getClassNameSymbol()); |
220 | if (array) for (idx = 0; (nextTable = (OSDictionary *) array->getObject(idx)); idx++) |
221 | { |
222 | set->setObject(nextTable); |
223 | } |
224 | if (meta == &IOService::gMetaClass) break; |
225 | meta = meta->getSuperClass(); |
226 | } |
227 | |
228 | *generationCount = getGenerationCount(); |
229 | |
230 | IORWLockUnlock(lock); |
231 | |
232 | return( set ); |
233 | } |
234 | |
235 | /********************************************************************* |
236 | * Is personality already in the catalog? |
237 | *********************************************************************/ |
238 | OSOrderedSet * |
239 | IOCatalogue::findDrivers( |
240 | OSDictionary * matching, |
241 | SInt32 * generationCount) |
242 | { |
243 | OSCollectionIterator * iter; |
244 | OSDictionary * dict; |
245 | OSOrderedSet * set; |
246 | OSArray * array; |
247 | const OSSymbol * key; |
248 | unsigned int idx; |
249 | |
250 | OSKext::uniquePersonalityProperties(matching); |
251 | |
252 | set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, |
253 | (void *)gIOProbeScoreKey ); |
254 | if (!set) return (0); |
255 | iter = OSCollectionIterator::withCollection(personalities); |
256 | if (!iter) |
257 | { |
258 | set->release(); |
259 | return (0); |
260 | } |
261 | |
262 | IORWLockRead(lock); |
263 | while ((key = (const OSSymbol *) iter->getNextObject())) |
264 | { |
265 | array = (OSArray *) personalities->getObject(key); |
266 | if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) |
267 | { |
268 | /* This comparison must be done with only the keys in the |
269 | * "matching" dict to enable general searches. |
270 | */ |
271 | if ( dict->isEqualTo(matching, matching) ) |
272 | set->setObject(dict); |
273 | } |
274 | } |
275 | *generationCount = getGenerationCount(); |
276 | IORWLockUnlock(lock); |
277 | |
278 | iter->release(); |
279 | return set; |
280 | } |
281 | |
282 | /********************************************************************* |
283 | * Add driver config tables to catalog and start matching process. |
284 | * |
285 | * Important that existing personalities are kept (not replaced) |
286 | * if duplicates found. Personalities can come from OSKext objects |
287 | * or from userland kext library. We want to minimize distinct |
288 | * copies between OSKext & IOCatalogue. |
289 | * |
290 | * xxx - userlib used to refuse to send personalities with IOKitDebug |
291 | * xxx - during safe boot. That would be better implemented here. |
292 | *********************************************************************/ |
293 | |
294 | bool IOCatalogue::addDrivers( |
295 | OSArray * drivers, |
296 | bool doNubMatching) |
297 | { |
298 | bool result = false; |
299 | OSCollectionIterator * iter = NULL; // must release |
300 | OSOrderedSet * set = NULL; // must release |
301 | OSObject * object = NULL; // do not release |
302 | OSArray * persons = NULL; // do not release |
303 | |
304 | persons = OSDynamicCast(OSArray, drivers); |
305 | if (!persons) { |
306 | goto finish; |
307 | } |
308 | |
309 | set = OSOrderedSet::withCapacity( 10, IOServiceOrdering, |
310 | (void *)gIOProbeScoreKey ); |
311 | if (!set) { |
312 | goto finish; |
313 | } |
314 | |
315 | iter = OSCollectionIterator::withCollection(persons); |
316 | if (!iter) { |
317 | goto finish; |
318 | } |
319 | |
320 | /* Start with success; clear it on an error. |
321 | */ |
322 | result = true; |
323 | |
324 | IORWLockWrite(lock); |
325 | while ( (object = iter->getNextObject()) ) { |
326 | |
327 | // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL |
328 | |
329 | OSDictionary * personality = OSDynamicCast(OSDictionary, object); |
330 | |
331 | SInt count; |
332 | |
333 | if (!personality) { |
334 | IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n" ); |
335 | result = false; |
336 | break; |
337 | } |
338 | |
339 | OSKext::uniquePersonalityProperties(personality); |
340 | |
341 | // Add driver personality to catalogue. |
342 | |
343 | OSArray * array = arrayForPersonality(personality); |
344 | if (!array) addPersonality(personality); |
345 | else |
346 | { |
347 | count = array->getCount(); |
348 | while (count--) { |
349 | OSDictionary * driver; |
350 | |
351 | // Be sure not to double up on personalities. |
352 | driver = (OSDictionary *)array->getObject(count); |
353 | |
354 | /* Unlike in other functions, this comparison must be exact! |
355 | * The catalogue must be able to contain personalities that |
356 | * are proper supersets of others. |
357 | * Do not compare just the properties present in one driver |
358 | * personality or the other. |
359 | */ |
360 | if (personality->isEqualTo(driver)) { |
361 | break; |
362 | } |
363 | } |
364 | if (count >= 0) { |
365 | // its a dup |
366 | continue; |
367 | } |
368 | result = array->setObject(personality); |
369 | if (!result) { |
370 | break; |
371 | } |
372 | } |
373 | |
374 | set->setObject(personality); |
375 | } |
376 | // Start device matching. |
377 | if (result && doNubMatching && (set->getCount() > 0)) { |
378 | IOService::catalogNewDrivers(set); |
379 | generation++; |
380 | } |
381 | IORWLockUnlock(lock); |
382 | |
383 | finish: |
384 | if (set) set->release(); |
385 | if (iter) iter->release(); |
386 | |
387 | return result; |
388 | } |
389 | |
390 | /********************************************************************* |
391 | * Remove drivers from the catalog which match the |
392 | * properties in the matching dictionary. |
393 | *********************************************************************/ |
394 | bool |
395 | IOCatalogue::removeDrivers( |
396 | OSDictionary * matching, |
397 | bool doNubMatching) |
398 | { |
399 | OSOrderedSet * set; |
400 | OSCollectionIterator * iter; |
401 | OSDictionary * dict; |
402 | OSArray * array; |
403 | const OSSymbol * key; |
404 | unsigned int idx; |
405 | |
406 | if ( !matching ) |
407 | return false; |
408 | |
409 | set = OSOrderedSet::withCapacity(10, |
410 | IOServiceOrdering, |
411 | (void *)gIOProbeScoreKey); |
412 | if ( !set ) |
413 | return false; |
414 | iter = OSCollectionIterator::withCollection(personalities); |
415 | if (!iter) |
416 | { |
417 | set->release(); |
418 | return (false); |
419 | } |
420 | |
421 | IORWLockWrite(lock); |
422 | while ((key = (const OSSymbol *) iter->getNextObject())) |
423 | { |
424 | array = (OSArray *) personalities->getObject(key); |
425 | if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) |
426 | { |
427 | /* This comparison must be done with only the keys in the |
428 | * "matching" dict to enable general searches. |
429 | */ |
430 | if ( dict->isEqualTo(matching, matching) ) { |
431 | set->setObject(dict); |
432 | array->removeObject(idx); |
433 | idx--; |
434 | } |
435 | } |
436 | // Start device matching. |
437 | if ( doNubMatching && (set->getCount() > 0) ) { |
438 | IOService::catalogNewDrivers(set); |
439 | generation++; |
440 | } |
441 | } |
442 | IORWLockUnlock(lock); |
443 | |
444 | set->release(); |
445 | iter->release(); |
446 | |
447 | return true; |
448 | } |
449 | |
450 | // Return the generation count. |
451 | SInt32 IOCatalogue::getGenerationCount(void) const |
452 | { |
453 | return( generation ); |
454 | } |
455 | |
456 | bool IOCatalogue::isModuleLoaded(OSString * moduleName) const |
457 | { |
458 | return isModuleLoaded(moduleName->getCStringNoCopy()); |
459 | } |
460 | |
461 | bool IOCatalogue::isModuleLoaded(const char * moduleName) const |
462 | { |
463 | OSReturn ret; |
464 | ret = OSKext::loadKextWithIdentifier(moduleName); |
465 | if (kOSKextReturnDeferred == ret) { |
466 | // a request has been queued but the module isn't necessarily |
467 | // loaded yet, so stall. |
468 | return false; |
469 | } |
470 | // module is present or never will be |
471 | return true; |
472 | } |
473 | |
474 | // Check to see if module has been loaded already. |
475 | bool IOCatalogue::isModuleLoaded(OSDictionary * driver) const |
476 | { |
477 | OSString * moduleName = NULL; |
478 | OSString * publisherName = NULL; |
479 | |
480 | if ( !driver ) |
481 | return false; |
482 | |
483 | /* The personalities of codeless kexts often contain the bundle ID of the |
484 | * kext they reference, and not the bundle ID of the codeless kext itself. |
485 | * The prelinked kernel needs to know the bundle ID of the codeless kext |
486 | * so it can include these personalities, so OSKext stores that bundle ID |
487 | * in the IOPersonalityPublisher key, and we record it as requested here. |
488 | */ |
489 | publisherName = OSDynamicCast(OSString, |
490 | driver->getObject(kIOPersonalityPublisherKey)); |
491 | OSKext::recordIdentifierRequest(publisherName); |
492 | |
493 | moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey)); |
494 | if ( moduleName ) |
495 | return isModuleLoaded(moduleName); |
496 | |
497 | /* If a personality doesn't hold the "CFBundleIdentifier" key |
498 | * it is assumed to be an "in-kernel" driver. |
499 | */ |
500 | return true; |
501 | } |
502 | |
503 | /* This function is called after a module has been loaded. |
504 | * Is invoked from user client call, ultimately from IOKitLib's |
505 | * IOCatalogueModuleLoaded(). Sent from kextd. |
506 | */ |
507 | void IOCatalogue::moduleHasLoaded(OSString * moduleName) |
508 | { |
509 | OSDictionary * dict; |
510 | |
511 | dict = OSDictionary::withCapacity(2); |
512 | dict->setObject(gIOModuleIdentifierKey, moduleName); |
513 | startMatching(dict); |
514 | dict->release(); |
515 | |
516 | (void) OSKext::setDeferredLoadSucceeded(); |
517 | (void) OSKext::considerRebuildOfPrelinkedKernel(); |
518 | } |
519 | |
520 | void IOCatalogue::moduleHasLoaded(const char * moduleName) |
521 | { |
522 | OSString * name; |
523 | |
524 | name = OSString::withCString(moduleName); |
525 | moduleHasLoaded(name); |
526 | name->release(); |
527 | } |
528 | |
529 | // xxx - return is really OSReturn/kern_return_t |
530 | IOReturn IOCatalogue::unloadModule(OSString * moduleName) const |
531 | { |
532 | return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy()); |
533 | } |
534 | |
535 | IOReturn IOCatalogue::_terminateDrivers(OSDictionary * matching) |
536 | { |
537 | OSDictionary * dict; |
538 | OSIterator * iter; |
539 | IOService * service; |
540 | IOReturn ret; |
541 | |
542 | if ( !matching ) |
543 | return kIOReturnBadArgument; |
544 | |
545 | ret = kIOReturnSuccess; |
546 | dict = 0; |
547 | iter = IORegistryIterator::iterateOver(gIOServicePlane, |
548 | kIORegistryIterateRecursively); |
549 | if ( !iter ) |
550 | return kIOReturnNoMemory; |
551 | |
552 | OSKext::uniquePersonalityProperties( matching ); |
553 | |
554 | // terminate instances. |
555 | do { |
556 | iter->reset(); |
557 | while( (service = (IOService *)iter->getNextObject()) ) { |
558 | dict = service->getPropertyTable(); |
559 | if ( !dict ) |
560 | continue; |
561 | |
562 | /* Terminate only for personalities that match the matching dictionary. |
563 | * This comparison must be done with only the keys in the |
564 | * "matching" dict to enable general matching. |
565 | */ |
566 | if ( !dict->isEqualTo(matching, matching) ) |
567 | continue; |
568 | |
569 | if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) { |
570 | ret = kIOReturnUnsupported; |
571 | break; |
572 | } |
573 | } |
574 | } while( !service && !iter->isValid()); |
575 | iter->release(); |
576 | |
577 | return ret; |
578 | } |
579 | |
580 | IOReturn IOCatalogue::_removeDrivers(OSDictionary * matching) |
581 | { |
582 | IOReturn ret = kIOReturnSuccess; |
583 | OSCollectionIterator * iter; |
584 | OSDictionary * dict; |
585 | OSArray * array; |
586 | const OSSymbol * key; |
587 | unsigned int idx; |
588 | |
589 | // remove configs from catalog. |
590 | |
591 | iter = OSCollectionIterator::withCollection(personalities); |
592 | if (!iter) return (kIOReturnNoMemory); |
593 | |
594 | while ((key = (const OSSymbol *) iter->getNextObject())) |
595 | { |
596 | array = (OSArray *) personalities->getObject(key); |
597 | if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) |
598 | { |
599 | |
600 | /* Remove from the catalogue's array any personalities |
601 | * that match the matching dictionary. |
602 | * This comparison must be done with only the keys in the |
603 | * "matching" dict to enable general matching. |
604 | */ |
605 | if (dict->isEqualTo(matching, matching)) |
606 | { |
607 | array->removeObject(idx); |
608 | idx--; |
609 | } |
610 | } |
611 | } |
612 | iter->release(); |
613 | |
614 | return ret; |
615 | } |
616 | |
617 | IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching) |
618 | { |
619 | IOReturn ret; |
620 | |
621 | ret = _terminateDrivers(matching); |
622 | IORWLockWrite(lock); |
623 | if (kIOReturnSuccess == ret) |
624 | ret = _removeDrivers(matching); |
625 | IORWLockUnlock(lock); |
626 | |
627 | return ret; |
628 | } |
629 | |
630 | IOReturn IOCatalogue::terminateDriversForModule( |
631 | OSString * moduleName, |
632 | bool unload) |
633 | { |
634 | IOReturn ret; |
635 | OSDictionary * dict; |
636 | bool isLoaded = false; |
637 | |
638 | /* Check first if the kext currently has any linkage dependents; |
639 | * in such a case the unload would fail so let's not terminate any |
640 | * IOServices (since doing so typically results in a panic when there |
641 | * are loaded dependencies). Note that we aren't locking the kext here |
642 | * so it might lose or gain dependents by the time we call unloadModule(); |
643 | * I think that's ok, our unload can fail if a kext comes in on top of |
644 | * this one even after we've torn down IOService objects. Conversely, |
645 | * if we fail the unload here and then lose a library, the autounload |
646 | * thread will get us in short order. |
647 | */ |
648 | if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) { |
649 | |
650 | isLoaded = true; |
651 | |
652 | if (!OSKext::canUnloadKextWithIdentifier(moduleName, |
653 | /* checkClasses */ false)) { |
654 | ret = kOSKextReturnInUse; |
655 | goto finish; |
656 | } |
657 | } |
658 | dict = OSDictionary::withCapacity(1); |
659 | if (!dict) { |
660 | ret = kIOReturnNoMemory; |
661 | goto finish; |
662 | } |
663 | |
664 | dict->setObject(gIOModuleIdentifierKey, moduleName); |
665 | |
666 | ret = _terminateDrivers(dict); |
667 | |
668 | /* No goto between IOLock calls! |
669 | */ |
670 | IORWLockWrite(lock); |
671 | if (kIOReturnSuccess == ret) { |
672 | ret = _removeDrivers(dict); |
673 | } |
674 | |
675 | // Unload the module itself. |
676 | if (unload && isLoaded && ret == kIOReturnSuccess) { |
677 | ret = unloadModule(moduleName); |
678 | } |
679 | |
680 | IORWLockUnlock(lock); |
681 | |
682 | dict->release(); |
683 | |
684 | finish: |
685 | return ret; |
686 | } |
687 | |
688 | IOReturn IOCatalogue::terminateDriversForModule( |
689 | const char * moduleName, |
690 | bool unload) |
691 | { |
692 | OSString * name; |
693 | IOReturn ret; |
694 | |
695 | name = OSString::withCString(moduleName); |
696 | if ( !name ) |
697 | return kIOReturnNoMemory; |
698 | |
699 | ret = terminateDriversForModule(name, unload); |
700 | name->release(); |
701 | |
702 | return ret; |
703 | } |
704 | |
705 | bool IOCatalogue::startMatching( OSDictionary * matching ) |
706 | { |
707 | OSCollectionIterator * iter; |
708 | OSDictionary * dict; |
709 | OSOrderedSet * set; |
710 | OSArray * array; |
711 | const OSSymbol * key; |
712 | unsigned int idx; |
713 | |
714 | if ( !matching ) |
715 | return false; |
716 | |
717 | set = OSOrderedSet::withCapacity(10, IOServiceOrdering, |
718 | (void *)gIOProbeScoreKey); |
719 | if ( !set ) |
720 | return false; |
721 | |
722 | iter = OSCollectionIterator::withCollection(personalities); |
723 | if (!iter) |
724 | { |
725 | set->release(); |
726 | return false; |
727 | } |
728 | |
729 | IORWLockRead(lock); |
730 | |
731 | while ((key = (const OSSymbol *) iter->getNextObject())) |
732 | { |
733 | array = (OSArray *) personalities->getObject(key); |
734 | if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) |
735 | { |
736 | /* This comparison must be done with only the keys in the |
737 | * "matching" dict to enable general matching. |
738 | */ |
739 | if (dict->isEqualTo(matching, matching)) { |
740 | set->setObject(dict); |
741 | } |
742 | } |
743 | } |
744 | |
745 | // Start device matching. |
746 | if ( set->getCount() > 0 ) { |
747 | IOService::catalogNewDrivers(set); |
748 | generation++; |
749 | } |
750 | |
751 | IORWLockUnlock(lock); |
752 | |
753 | set->release(); |
754 | iter->release(); |
755 | |
756 | return true; |
757 | } |
758 | |
759 | void IOCatalogue::reset(void) |
760 | { |
761 | IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL, |
762 | /* doMatching */ false); |
763 | return; |
764 | } |
765 | |
766 | bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) |
767 | { |
768 | bool result = false; |
769 | OSArray * newPersonalities = NULL; // do not release |
770 | OSCollectionIterator * iter = NULL; // must release |
771 | OSOrderedSet * matchSet = NULL; // must release |
772 | const OSSymbol * key; |
773 | OSArray * array; |
774 | OSDictionary * thisNewPersonality = NULL; // do not release |
775 | OSDictionary * thisOldPersonality = NULL; // do not release |
776 | OSDictionary * myKexts = NULL; // must release |
777 | signed int idx, newIdx; |
778 | |
779 | if (drivers) { |
780 | newPersonalities = OSDynamicCast(OSArray, drivers); |
781 | if (!newPersonalities) { |
782 | goto finish; |
783 | } |
784 | } |
785 | matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering, |
786 | (void *)gIOProbeScoreKey); |
787 | if (!matchSet) { |
788 | goto finish; |
789 | } |
790 | iter = OSCollectionIterator::withCollection(personalities); |
791 | if (!iter) { |
792 | goto finish; |
793 | } |
794 | |
795 | /* need copy of loaded kexts so we can check if for loaded modules without |
796 | * taking the OSKext lock. There is a potential of deadlocking if we get |
797 | * an OSKext via the normal path. See 14672140. |
798 | */ |
799 | myKexts = OSKext::copyKexts(); |
800 | |
801 | result = true; |
802 | |
803 | IOLog("Resetting IOCatalogue.\n" ); |
804 | |
805 | /* No goto finish from here to unlock. |
806 | */ |
807 | IORWLockWrite(lock); |
808 | |
809 | while ((key = (const OSSymbol *) iter->getNextObject())) |
810 | { |
811 | array = (OSArray *) personalities->getObject(key); |
812 | if (!array) continue; |
813 | |
814 | for (idx = 0; |
815 | (thisOldPersonality = (OSDictionary *) array->getObject(idx)); |
816 | idx++) |
817 | { |
818 | if (thisOldPersonality->getObject("KernelConfigTable" )) continue; |
819 | thisNewPersonality = NULL; |
820 | |
821 | if (newPersonalities) { |
822 | for (newIdx = 0; |
823 | (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx)); |
824 | newIdx++) |
825 | { |
826 | /* Unlike in other functions, this comparison must be exact! |
827 | * The catalogue must be able to contain personalities that |
828 | * are proper supersets of others. |
829 | * Do not compare just the properties present in one driver |
830 | * personality or the other. |
831 | */ |
832 | if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) { |
833 | /* skip thisNewPersonality if it is not an OSDictionary */ |
834 | continue; |
835 | } |
836 | if (thisNewPersonality->isEqualTo(thisOldPersonality)) |
837 | break; |
838 | } |
839 | } |
840 | if (thisNewPersonality) { |
841 | // dup, ignore |
842 | newPersonalities->removeObject(newIdx); |
843 | } |
844 | else { |
845 | // not in new set - remove |
846 | // only remove dictionary if this module in not loaded - 9953845 |
847 | if ( isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false ) { |
848 | if (matchSet) { |
849 | matchSet->setObject(thisOldPersonality); |
850 | } |
851 | array->removeObject(idx); |
852 | idx--; |
853 | } |
854 | } |
855 | } // for... |
856 | } // while... |
857 | |
858 | // add new |
859 | if (newPersonalities) { |
860 | for (newIdx = 0; |
861 | (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx)); |
862 | newIdx++) |
863 | { |
864 | if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) { |
865 | /* skip thisNewPersonality if it is not an OSDictionary */ |
866 | continue; |
867 | } |
868 | |
869 | OSKext::uniquePersonalityProperties(thisNewPersonality); |
870 | addPersonality(thisNewPersonality); |
871 | matchSet->setObject(thisNewPersonality); |
872 | } |
873 | } |
874 | |
875 | /* Finally, start device matching on all new & removed personalities. |
876 | */ |
877 | if (result && doNubMatching && (matchSet->getCount() > 0)) { |
878 | IOService::catalogNewDrivers(matchSet); |
879 | generation++; |
880 | } |
881 | |
882 | IORWLockUnlock(lock); |
883 | |
884 | finish: |
885 | if (matchSet) matchSet->release(); |
886 | if (iter) iter->release(); |
887 | if (myKexts) myKexts->release(); |
888 | |
889 | return result; |
890 | } |
891 | |
892 | bool IOCatalogue::serialize(OSSerialize * s) const |
893 | { |
894 | if ( !s ) |
895 | return false; |
896 | |
897 | return super::serialize(s); |
898 | } |
899 | |
900 | bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const |
901 | { |
902 | kern_return_t kr = kIOReturnSuccess; |
903 | |
904 | switch ( kind ) |
905 | { |
906 | case kIOCatalogGetContents: |
907 | kr = KERN_NOT_SUPPORTED; |
908 | break; |
909 | |
910 | case kIOCatalogGetModuleDemandList: |
911 | kr = KERN_NOT_SUPPORTED; |
912 | break; |
913 | |
914 | case kIOCatalogGetCacheMissList: |
915 | kr = KERN_NOT_SUPPORTED; |
916 | break; |
917 | |
918 | case kIOCatalogGetROMMkextList: |
919 | kr = KERN_NOT_SUPPORTED; |
920 | break; |
921 | |
922 | default: |
923 | kr = kIOReturnBadArgument; |
924 | break; |
925 | } |
926 | |
927 | return kr; |
928 | } |
929 | |
930 | /* isModuleLoadedNoOSKextLock - used to check to see if a kext is loaded |
931 | * without taking the OSKext lock. We use this to avoid the problem |
932 | * where taking the IOCatalog lock then the OSKext lock will dealock when |
933 | * a kext load or unload is happening at the same time as IOCatalog changing. |
934 | * |
935 | * theKexts - is a dictionary of current kexts (from OSKext::copyKexts) with |
936 | * key set to the kext bundle ID and value set to an OSKext object |
937 | * theModuleDict - is an IOKit personality dictionary for a given module (kext) |
938 | */ |
939 | static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts, |
940 | OSDictionary *theModuleDict) |
941 | { |
942 | bool myResult = false; |
943 | const OSString * myBundleID = NULL; // do not release |
944 | OSKext * myKext = NULL; // do not release |
945 | |
946 | if (theKexts == NULL || theModuleDict == NULL) { |
947 | return( myResult ); |
948 | } |
949 | |
950 | // gIOModuleIdentifierKey is "CFBundleIdentifier" |
951 | myBundleID = OSDynamicCast(OSString, |
952 | theModuleDict->getObject(gIOModuleIdentifierKey)); |
953 | if (myBundleID == NULL) { |
954 | return( myResult ); |
955 | } |
956 | |
957 | myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy())); |
958 | if (myKext) { |
959 | myResult = myKext->isLoaded(); |
960 | } |
961 | |
962 | return( myResult ); |
963 | } |
964 | |
965 | |
966 | #if PRAGMA_MARK |
967 | #pragma mark Obsolete Kext Loading Stuff |
968 | #endif |
969 | /********************************************************************* |
970 | ********************************************************************** |
971 | *** BINARY COMPATIBILITY SECTION *** |
972 | ********************************************************************** |
973 | ********************************************************************** |
974 | * These functions are no longer used are necessary for C++ binary |
975 | * compatibility on i386. |
976 | **********************************************************************/ |
977 | |