1 /* 2 * Copyright (c) 2000-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 extern "C" { 29 #include <mach/kmod.h> 30 #include <libkern/kernel_mach_header.h> 31 #include <libkern/prelink.h> 32 #include <libkern/crypto/sha2.h> 33 } 34 35 #define IOKIT_ENABLE_SHARED_PTR 36 37 #include <libkern/version.h> 38 #include <libkern/c++/OSContainers.h> 39 #include <libkern/OSKextLibPrivate.h> 40 #include <libkern/c++/OSKext.h> 41 #include <IOKit/IOLib.h> 42 #include <IOKit/IOService.h> 43 #include <IOKit/IODeviceTreeSupport.h> 44 #include <IOKit/IOCatalogue.h> 45 46 #if __x86_64__ 47 #define KASLR_KEXT_DEBUG 0 48 #endif 49 50 #if PRAGMA_MARK 51 #pragma mark Bootstrap Declarations 52 #endif 53 /********************************************************************* 54 * Bootstrap Declarations 55 * 56 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap 57 * code from other parts of the kernel, so function symbols are not 58 * exported; rather pointers to those functions are exported. 59 * 60 * xxx - need to think about locking for handling the 'weak' refs. 61 * xxx - do export a non-KLD function that says you've called a 62 * xxx - bootstrap function that has been removed. 63 * 64 * ALL call-ins to this segment of the kernel must be done through 65 * exported pointers. The symbols themselves are private and not to 66 * be linked against. 67 *********************************************************************/ 68 extern "C" { 69 extern void (*record_startup_extensions_function)(void); 70 extern void (*load_security_extensions_function)(void); 71 }; 72 73 static void bootstrapRecordStartupExtensions(void); 74 static void bootstrapLoadSecurityExtensions(void); 75 76 77 #if NO_KEXTD 78 extern "C" bool IORamDiskBSDRoot(void); 79 #endif 80 81 #if PRAGMA_MARK 82 #pragma mark Macros 83 #endif 84 /********************************************************************* 85 * Macros 86 *********************************************************************/ 87 #define CONST_STRLEN(str) (sizeof(str) - 1) 88 89 #if PRAGMA_MARK 90 #pragma mark Kernel Component Kext Identifiers 91 #endif 92 /********************************************************************* 93 * Kernel Component Kext Identifiers 94 * 95 * We could have each kernel resource kext automatically "load" as 96 * it's created, but it's nicer to have them listed in kextstat in 97 * the order of this list. We'll walk through this after setting up 98 * all the boot kexts and have them load up. 99 *********************************************************************/ 100 static const char * sKernelComponentNames[] = { 101 // The kexts for these IDs must have a version matching 'osrelease'. 102 "com.apple.kernel", 103 "com.apple.kpi.bsd", 104 "com.apple.kpi.dsep", 105 "com.apple.kpi.iokit", 106 "com.apple.kpi.kasan", 107 "com.apple.kpi.kcov", 108 "com.apple.kpi.libkern", 109 "com.apple.kpi.mach", 110 "com.apple.kpi.private", 111 "com.apple.kpi.unsupported", 112 "com.apple.iokit.IONVRAMFamily", 113 "com.apple.driver.AppleNMI", 114 "com.apple.iokit.IOSystemManagementFamily", 115 "com.apple.iokit.ApplePlatformFamily", 116 NULL 117 }; 118 119 #if PRAGMA_MARK 120 #pragma mark KLDBootstrap Class 121 #endif 122 /********************************************************************* 123 * KLDBootstrap Class 124 * 125 * We use a C++ class here so that it can be a friend of OSKext and 126 * get at private stuff. We can't hide the class itself, but we can 127 * hide the instance through which we invoke the functions. 128 *********************************************************************/ 129 class KLDBootstrap { 130 friend void bootstrapRecordStartupExtensions(void); 131 friend void bootstrapLoadSecurityExtensions(void); 132 133 private: 134 void readStartupExtensions(void); 135 136 void readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type); 137 void readBooterExtensions(void); 138 139 OSReturn loadKernelComponentKexts(void); 140 void loadKernelExternalComponents(void); 141 void readBuiltinPersonalities(void); 142 143 void loadSecurityExtensions(void); 144 145 public: 146 KLDBootstrap(void); 147 ~KLDBootstrap(void); 148 }; 149 150 LIBKERN_ALWAYS_DESTROY static KLDBootstrap sBootstrapObject; 151 152 /********************************************************************* 153 * Set the function pointers for the entry points into the bootstrap 154 * segment upon C++ static constructor invocation. 155 *********************************************************************/ 156 KLDBootstrap::KLDBootstrap(void) 157 { 158 if (this != &sBootstrapObject) { 159 panic("Attempt to access bootstrap segment."); 160 } 161 record_startup_extensions_function = &bootstrapRecordStartupExtensions; 162 load_security_extensions_function = &bootstrapLoadSecurityExtensions; 163 } 164 165 /********************************************************************* 166 * Clear the function pointers for the entry points into the bootstrap 167 * segment upon C++ static destructor invocation. 168 *********************************************************************/ 169 KLDBootstrap::~KLDBootstrap(void) 170 { 171 if (this != &sBootstrapObject) { 172 panic("Attempt to access bootstrap segment."); 173 } 174 175 176 record_startup_extensions_function = NULL; 177 load_security_extensions_function = NULL; 178 } 179 180 /********************************************************************* 181 *********************************************************************/ 182 void 183 KLDBootstrap::readStartupExtensions(void) 184 { 185 kernel_section_t * prelinkInfoSect = NULL; // do not free 186 187 OSKextLog(/* kext */ NULL, 188 kOSKextLogProgressLevel | 189 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag | 190 kOSKextLogKextBookkeepingFlag, 191 "Reading startup extensions."); 192 193 kc_format_t kc_format; 194 kernel_mach_header_t *mh = &_mh_execute_header; 195 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) { 196 mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary); 197 } 198 199 /* If the prelink info segment has a nonzero size, we are prelinked 200 * and won't have any individual kexts or mkexts to read. 201 * Otherwise, we need to read kexts or the mkext from what the booter 202 * has handed us. 203 */ 204 prelinkInfoSect = getsectbynamefromheader(mh, kPrelinkInfoSegment, kPrelinkInfoSection); 205 if (prelinkInfoSect->size) { 206 readPrelinkedExtensions(mh, KCKindPrimary); 207 } else { 208 readBooterExtensions(); 209 } 210 211 kernel_mach_header_t *akc_mh; 212 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary); 213 if (akc_mh) { 214 readPrelinkedExtensions(akc_mh, KCKindAuxiliary); 215 } 216 217 loadKernelComponentKexts(); 218 loadKernelExternalComponents(); 219 readBuiltinPersonalities(); 220 OSKext::sendAllKextPersonalitiesToCatalog(true); 221 222 return; 223 } 224 225 /********************************************************************* 226 *********************************************************************/ 227 void 228 KLDBootstrap::readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type) 229 { 230 bool ret; 231 OSSharedPtr<OSData> loaded_kcUUID; 232 OSSharedPtr<OSString> errorString; 233 OSSharedPtr<OSObject> parsedXML; 234 kernel_section_t *infoPlistSection = NULL; 235 OSDictionary *infoDict = NULL; // do not release 236 237 OSKextLog(/* kext */ NULL, 238 kOSKextLogProgressLevel | 239 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, 240 "Starting from prelinked kernel."); 241 242 /* 243 * The 'infoPlistSection' should contains an XML dictionary that 244 * contains some meta data about the KC, and also describes each kext 245 * included in the kext collection. Unserialize this dictionary and 246 * then iterate over each kext. 247 */ 248 infoPlistSection = getsectbynamefromheader(mh, kPrelinkInfoSegment, kPrelinkInfoSection); 249 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString); 250 if (parsedXML) { 251 infoDict = OSDynamicCast(OSDictionary, parsedXML.get()); 252 } 253 254 if (!infoDict) { 255 const char *errorCString = "(unknown error)"; 256 257 if (errorString && errorString->getCStringNoCopy()) { 258 errorCString = errorString->getCStringNoCopy(); 259 } else if (parsedXML) { 260 errorCString = "not a dictionary"; 261 } 262 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 263 "Error unserializing kext info plist section: %s.", errorCString); 264 return; 265 } 266 267 /* Validate that the Kext Collection is prelinked to the loaded KC */ 268 if (type == KCKindAuxiliary) { 269 if (OSKext::validateKCFileSetUUID(infoDict, KCKindAuxiliary) != 0) { 270 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 271 "Early boot AuxKC doesn't appear to be linked against the loaded BootKC."); 272 return; 273 } 274 275 /* 276 * Defer further processing of the AuxKC, but keep the 277 * processed info dictionary around so we can ml_static_free 278 * the segment. 279 */ 280 if (!OSKext::registerDeferredKextCollection(mh, parsedXML, KCKindAuxiliary)) { 281 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 282 "Error deferring AuxKC kext processing: Kexts in this collection will be unusable."); 283 } 284 goto skip_adding_kexts; 285 } 286 287 /* 288 * this function does all the heavy lifting of adding OSKext objects 289 * and potentially sliding them if necessary 290 */ 291 ret = OSKext::addKextsFromKextCollection(mh, infoDict, 292 kPrelinkTextSegment, loaded_kcUUID, (mh->filetype == MH_FILESET) ? type : KCKindUnknown); 293 294 if (!ret) { 295 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 296 "Error loading kext info from prelinked primary KC"); 297 return; 298 } 299 300 /* Copy in the kernelcache UUID */ 301 if (!loaded_kcUUID) { 302 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 303 "WARNING: did not find UUID in %s KC!", (type == KCKindAuxiliary) ? "Aux" : "Primary"); 304 } else if (type != KCKindAuxiliary) { 305 kernelcache_uuid_valid = TRUE; 306 memcpy((void *)&kernelcache_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength()); 307 uuid_unparse_upper(kernelcache_uuid, kernelcache_uuid_string); 308 } else { 309 auxkc_uuid_valid = TRUE; 310 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength()); 311 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string); 312 } 313 314 skip_adding_kexts: 315 #if CONFIG_KEXT_BASEMENT 316 if (mh->filetype != MH_FILESET) { 317 /* 318 * On CONFIG_KEXT_BASEMENT systems which do _not_ boot the new 319 * MH_FILESET kext collection, kexts are copied to their own 320 * special VM region during OSKext init time, so we can free 321 * the whole segment now. 322 */ 323 kernel_segment_command_t *prelinkTextSegment = NULL; 324 prelinkTextSegment = getsegbyname(kPrelinkTextSegment); 325 if (!prelinkTextSegment) { 326 OSKextLog(/* kext */ NULL, 327 kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 328 "Can't find prelinked kexts' text segment."); 329 return; 330 } 331 332 ml_static_mfree((vm_offset_t)prelinkTextSegment->vmaddr, prelinkTextSegment->vmsize); 333 } 334 #endif /* CONFIG_KEXT_BASEMENT */ 335 336 /* 337 * Free the prelink info segment, we're done with it. 338 */ 339 kernel_segment_command_t *prelinkInfoSegment = NULL; 340 prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment); 341 if (prelinkInfoSegment) { 342 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr, 343 (vm_size_t)prelinkInfoSegment->vmsize); 344 } 345 346 return; 347 } 348 349 350 /********************************************************************* 351 *********************************************************************/ 352 #define BOOTER_KEXT_PREFIX "Driver-" 353 354 typedef struct _DeviceTreeBuffer { 355 uint32_t paddr; 356 uint32_t length; 357 } _DeviceTreeBuffer; 358 359 void 360 KLDBootstrap::readBooterExtensions(void) 361 { 362 OSSharedPtr<IORegistryEntry> booterMemoryMap; 363 OSSharedPtr<OSDictionary> propertyDict; 364 OSSharedPtr<OSCollectionIterator> keyIterator; 365 OSString * deviceTreeName = NULL;// do not release 366 367 const _DeviceTreeBuffer * deviceTreeBuffer = NULL;// do not free 368 char * booterDataPtr = NULL;// do not free 369 OSSharedPtr<OSData> booterData; 370 OSSharedPtr<OSKext> aKext; 371 372 OSKextLog(/* kext */ NULL, 373 kOSKextLogProgressLevel | 374 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, 375 "Reading startup extensions from booter memory."); 376 377 booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane); 378 379 if (!booterMemoryMap) { 380 OSKextLog(/* kext */ NULL, 381 kOSKextLogErrorLevel | 382 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag, 383 "Can't read booter memory map."); 384 goto finish; 385 } 386 387 propertyDict = booterMemoryMap->dictionaryWithProperties(); 388 if (!propertyDict) { 389 OSKextLog(/* kext */ NULL, 390 kOSKextLogErrorLevel | 391 kOSKextLogDirectoryScanFlag, 392 "Can't get property dictionary from memory map."); 393 goto finish; 394 } 395 396 keyIterator = OSCollectionIterator::withCollection(propertyDict.get()); 397 if (!keyIterator) { 398 OSKextLog(/* kext */ NULL, 399 kOSKextLogErrorLevel | 400 kOSKextLogGeneralFlag, 401 "Can't allocate iterator for driver images."); 402 goto finish; 403 } 404 405 /* Create dictionary of excluded kexts 406 */ 407 #ifndef CONFIG_EMBEDDED 408 OSKext::createExcludeListFromBooterData(propertyDict.get(), keyIterator.get()); 409 #endif 410 // !! reset the iterator, not the pointer 411 keyIterator->reset(); 412 413 while ((deviceTreeName = 414 OSDynamicCast(OSString, keyIterator->getNextObject()))) { 415 const char * devTreeNameCString = deviceTreeName->getCStringNoCopy(); 416 OSData * deviceTreeEntry = OSDynamicCast(OSData, 417 propertyDict->getObject(deviceTreeName)); 418 419 /* If there is no entry for the name, we can't do much with it. */ 420 if (!deviceTreeEntry) { 421 continue; 422 } 423 424 /* Make sure it is a kext */ 425 if (strncmp(devTreeNameCString, 426 BOOTER_KEXT_PREFIX, 427 CONST_STRLEN(BOOTER_KEXT_PREFIX))) { 428 continue; 429 } 430 431 deviceTreeBuffer = (const _DeviceTreeBuffer *) 432 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer)); 433 if (!deviceTreeBuffer) { 434 /* We can't get to the data, so we can't do anything, 435 * not even free it from physical memory (if it's there). 436 */ 437 OSKextLog(/* kext */ NULL, 438 kOSKextLogErrorLevel | 439 kOSKextLogDirectoryScanFlag, 440 "Device tree entry %s has NULL pointer.", 441 devTreeNameCString); 442 goto finish; // xxx - continue, panic? 443 } 444 445 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr); 446 if (!booterDataPtr) { 447 OSKextLog(/* kext */ NULL, 448 kOSKextLogErrorLevel | 449 kOSKextLogDirectoryScanFlag, 450 "Can't get virtual address for device tree entry %s.", 451 devTreeNameCString); 452 goto finish; 453 } 454 455 /* Wrap the booter data buffer in an OSData and set a dealloc function 456 * so it will take care of the physical memory when freed. Kexts will 457 * retain the booterData for as long as they need it. Remove the entry 458 * from the booter memory map after this is done. 459 */ 460 booterData = OSData::withBytesNoCopy(booterDataPtr, 461 deviceTreeBuffer->length); 462 if (!booterData) { 463 OSKextLog(/* kext */ NULL, 464 kOSKextLogErrorLevel | 465 kOSKextLogGeneralFlag, 466 "Error - Can't allocate OSData wrapper for device tree entry %s.", 467 devTreeNameCString); 468 goto finish; 469 } 470 booterData->setDeallocFunction(osdata_phys_free); 471 472 /* Create the kext for the entry, then release it, because the 473 * kext system keeps them around until explicitly removed. 474 * Any creation/registration failures are already logged for us. 475 */ 476 OSSharedPtr<OSKext> newKext = OSKext::withBooterData(deviceTreeName, booterData.get()); 477 478 booterMemoryMap->removeProperty(deviceTreeName); 479 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */ 480 481 finish: 482 return; 483 } 484 485 /********************************************************************* 486 *********************************************************************/ 487 #define COM_APPLE "com.apple." 488 489 void 490 KLDBootstrap::loadSecurityExtensions(void) 491 { 492 OSSharedPtr<OSDictionary> extensionsDict; 493 OSSharedPtr<OSCollectionIterator> keyIterator; 494 OSString * bundleID = NULL;// don't release 495 OSKext * theKext = NULL;// don't release 496 497 OSKextLog(/* kext */ NULL, 498 kOSKextLogStepLevel | 499 kOSKextLogLoadFlag, 500 "Loading security extensions."); 501 502 extensionsDict = OSKext::copyKexts(); 503 if (!extensionsDict) { 504 return; 505 } 506 507 keyIterator = OSCollectionIterator::withCollection(extensionsDict.get()); 508 if (!keyIterator) { 509 OSKextLog(/* kext */ NULL, 510 kOSKextLogErrorLevel | 511 kOSKextLogGeneralFlag, 512 "Failed to allocate iterator for security extensions."); 513 goto finish; 514 } 515 516 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) { 517 const char * bundle_id = bundleID->getCStringNoCopy(); 518 519 /* Skip extensions whose bundle IDs don't start with "com.apple.". 520 */ 521 if (!bundle_id || 522 (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) { 523 continue; 524 } 525 526 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID)); 527 if (!theKext) { 528 continue; 529 } 530 531 if (kOSBooleanTrue == theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)) { 532 OSKextLog(/* kext */ NULL, 533 kOSKextLogStepLevel | 534 kOSKextLogLoadFlag, 535 "Loading security extension %s.", bundleID->getCStringNoCopy()); 536 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(), 537 /* allowDefer */ false); 538 } 539 } 540 541 finish: 542 return; 543 } 544 545 /********************************************************************* 546 * We used to require that all listed kernel components load, but 547 * nowadays we can get them from userland so we only try to load the 548 * ones we have. If an error occurs later, such is life. 549 * 550 * Note that we look the kexts up first, so we can avoid spurious 551 * (in this context, anyhow) log messages about kexts not being found. 552 * 553 * xxx - do we even need to do this any more? Check if the kernel 554 * xxx - compoonents just load in the regular paths 555 *********************************************************************/ 556 OSReturn 557 KLDBootstrap::loadKernelComponentKexts(void) 558 { 559 OSReturn result = kOSReturnSuccess;// optimistic 560 OSSharedPtr<OSKext> theKext; 561 const char ** kextIDPtr = NULL; // do not release 562 563 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) { 564 theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr); 565 566 if (theKext) { 567 if (kOSReturnSuccess != OSKext::loadKextWithIdentifier( 568 *kextIDPtr, /* allowDefer */ false)) { 569 // xxx - check KextBookkeeping, might be redundant 570 OSKextLog(/* kext */ NULL, 571 kOSKextLogErrorLevel | 572 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, 573 "Failed to initialize kernel component %s.", *kextIDPtr); 574 result = kOSReturnError; 575 } 576 } 577 } 578 579 return result; 580 } 581 582 /********************************************************************* 583 * Ensure that Kernel External Components are loaded early in boot, 584 * before other kext personalities get sent to the IOCatalogue. These 585 * kexts are treated specially because they may provide the implementation 586 * for kernel-vended KPI, so they must register themselves before 587 * general purpose IOKit probing begins. 588 *********************************************************************/ 589 590 #define COM_APPLE_KEC "com.apple.kec." 591 592 void 593 KLDBootstrap::loadKernelExternalComponents(void) 594 { 595 OSSharedPtr<OSDictionary> extensionsDict; 596 OSSharedPtr<OSCollectionIterator> keyIterator; 597 OSString * bundleID = NULL;// don't release 598 OSKext * theKext = NULL;// don't release 599 OSBoolean * isKernelExternalComponent = NULL;// don't release 600 601 OSKextLog(/* kext */ NULL, 602 kOSKextLogStepLevel | 603 kOSKextLogLoadFlag, 604 "Loading Kernel External Components."); 605 606 extensionsDict = OSKext::copyKexts(); 607 if (!extensionsDict) { 608 return; 609 } 610 611 keyIterator = OSCollectionIterator::withCollection(extensionsDict.get()); 612 if (!keyIterator) { 613 OSKextLog(/* kext */ NULL, 614 kOSKextLogErrorLevel | 615 kOSKextLogGeneralFlag, 616 "Failed to allocate iterator for Kernel External Components."); 617 goto finish; 618 } 619 620 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) { 621 const char * bundle_id = bundleID->getCStringNoCopy(); 622 623 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.". 624 */ 625 if (!bundle_id || 626 (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) { 627 continue; 628 } 629 630 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID)); 631 if (!theKext) { 632 continue; 633 } 634 635 isKernelExternalComponent = OSDynamicCast(OSBoolean, 636 theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey)); 637 if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) { 638 OSKextLog(/* kext */ NULL, 639 kOSKextLogStepLevel | 640 kOSKextLogLoadFlag, 641 "Loading kernel external component %s.", bundleID->getCStringNoCopy()); 642 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(), 643 /* allowDefer */ false); 644 } 645 } 646 647 finish: 648 return; 649 } 650 651 /********************************************************************* 652 *********************************************************************/ 653 void 654 KLDBootstrap::readBuiltinPersonalities(void) 655 { 656 OSSharedPtr<OSObject> parsedXML; 657 OSArray * builtinExtensions = NULL;// do not release 658 OSSharedPtr<OSArray> allPersonalities; 659 OSSharedPtr<OSString> errorString; 660 kernel_section_t * infosect = NULL;// do not free 661 OSSharedPtr<OSCollectionIterator> personalitiesIterator; 662 unsigned int count, i; 663 664 OSKextLog(/* kext */ NULL, 665 kOSKextLogStepLevel | 666 kOSKextLogLoadFlag, 667 "Reading built-in kernel personalities for I/O Kit drivers."); 668 669 /* Look in the __BUILTIN __info segment for an array of Info.plist 670 * entries. For each one, extract the personalities dictionary, add 671 * it to our array, then push them all (without matching) to 672 * the IOCatalogue. This can be used to augment the personalities 673 * in gIOKernelConfigTables, especially when linking entire kexts into 674 * the mach_kernel image. 675 */ 676 infosect = getsectbyname("__BUILTIN", "__info"); 677 if (!infosect) { 678 // this isn't fatal 679 goto finish; 680 } 681 682 parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr, 683 errorString); 684 if (parsedXML) { 685 builtinExtensions = OSDynamicCast(OSArray, parsedXML.get()); 686 } 687 if (!builtinExtensions) { 688 const char * errorCString = "(unknown error)"; 689 690 if (errorString && errorString->getCStringNoCopy()) { 691 errorCString = errorString->getCStringNoCopy(); 692 } else if (parsedXML) { 693 errorCString = "not an array"; 694 } 695 OSKextLog(/* kext */ NULL, 696 kOSKextLogErrorLevel | 697 kOSKextLogLoadFlag, 698 "Error unserializing built-in personalities: %s.", errorCString); 699 goto finish; 700 } 701 702 // estimate 3 personalities per Info.plist/kext 703 count = builtinExtensions->getCount(); 704 allPersonalities = OSArray::withCapacity(count * 3); 705 706 for (i = 0; i < count; i++) { 707 OSDictionary * infoDict = NULL;// do not release 708 OSString * moduleName = NULL;// do not release 709 OSDictionary * personalities;// do not release 710 OSString * personalityName;// do not release 711 712 infoDict = OSDynamicCast(OSDictionary, 713 builtinExtensions->getObject(i)); 714 if (!infoDict) { 715 continue; 716 } 717 718 moduleName = OSDynamicCast(OSString, 719 infoDict->getObject(kCFBundleIdentifierKey)); 720 if (!moduleName) { 721 continue; 722 } 723 724 OSKextLog(/* kext */ NULL, 725 kOSKextLogStepLevel | 726 kOSKextLogLoadFlag, 727 "Adding personalities for built-in driver %s:", 728 moduleName->getCStringNoCopy()); 729 730 personalities = OSDynamicCast(OSDictionary, 731 infoDict->getObject("IOKitPersonalities")); 732 if (!personalities) { 733 continue; 734 } 735 736 personalitiesIterator = OSCollectionIterator::withCollection(personalities); 737 if (!personalitiesIterator) { 738 continue; // xxx - well really, what can we do? should we panic? 739 } 740 741 while ((personalityName = OSDynamicCast(OSString, 742 personalitiesIterator->getNextObject()))) { 743 OSDictionary * personality = OSDynamicCast(OSDictionary, 744 personalities->getObject(personalityName)); 745 746 OSKextLog(/* kext */ NULL, 747 kOSKextLogDetailLevel | 748 kOSKextLogLoadFlag, 749 "Adding built-in driver personality %s.", 750 personalityName->getCStringNoCopy()); 751 752 if (personality && !personality->getObject(kCFBundleIdentifierKey)) { 753 personality->setObject(kCFBundleIdentifierKey, moduleName); 754 } 755 allPersonalities->setObject(personality); 756 } 757 } 758 759 gIOCatalogue->addDrivers(allPersonalities.get(), false); 760 761 finish: 762 return; 763 } 764 765 #if PRAGMA_MARK 766 #pragma mark Bootstrap Functions 767 #endif 768 /********************************************************************* 769 * Bootstrap Functions 770 *********************************************************************/ 771 static void 772 bootstrapRecordStartupExtensions(void) 773 { 774 sBootstrapObject.readStartupExtensions(); 775 return; 776 } 777 778 static void 779 bootstrapLoadSecurityExtensions(void) 780 { 781 sBootstrapObject.loadSecurityExtensions(); 782 return; 783 } 784 785