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