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 340 #if !XNU_TARGET_OS_OSX 341 /* 342 * For now, we are limiting this freeing to embedded platforms. 343 * To enable freeing of prelink info segment on macOS, we need to 344 * fix rdar://88929016 345 */ 346 bool freedPrelinkInfo = false; 347 kernel_segment_command_t *prelinkInfoSegment = NULL; 348 prelinkInfoSegment = getsegbynamefromheader(mh, kPrelinkInfoSegment); 349 if (prelinkInfoSegment) { 350 if (prelinkInfoSegment->vmsize != 0) { 351 freedPrelinkInfo = true; 352 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr, 353 (vm_size_t)prelinkInfoSegment->vmsize); 354 } 355 } 356 357 if (!freedPrelinkInfo) { 358 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "Failed to free prelink info."); 359 } 360 #endif 361 return; 362 } 363 364 365 /********************************************************************* 366 *********************************************************************/ 367 #define BOOTER_KEXT_PREFIX "Driver-" 368 369 typedef struct _DeviceTreeBuffer { 370 uint32_t paddr; 371 uint32_t length; 372 } _DeviceTreeBuffer; 373 374 void 375 KLDBootstrap::readBooterExtensions(void) 376 { 377 OSSharedPtr<IORegistryEntry> booterMemoryMap; 378 OSSharedPtr<OSDictionary> propertyDict; 379 OSSharedPtr<OSCollectionIterator> keyIterator; 380 OSString * deviceTreeName = NULL;// do not release 381 382 const _DeviceTreeBuffer * deviceTreeBuffer = NULL;// do not free 383 char * booterDataPtr = NULL;// do not free 384 OSSharedPtr<OSData> booterData; 385 OSSharedPtr<OSKext> aKext; 386 387 OSKextLog(/* kext */ NULL, 388 kOSKextLogProgressLevel | 389 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, 390 "Reading startup extensions from booter memory."); 391 392 booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane); 393 394 if (!booterMemoryMap) { 395 OSKextLog(/* kext */ NULL, 396 kOSKextLogErrorLevel | 397 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag, 398 "Can't read booter memory map."); 399 goto finish; 400 } 401 402 propertyDict = booterMemoryMap->dictionaryWithProperties(); 403 if (!propertyDict) { 404 OSKextLog(/* kext */ NULL, 405 kOSKextLogErrorLevel | 406 kOSKextLogDirectoryScanFlag, 407 "Can't get property dictionary from memory map."); 408 goto finish; 409 } 410 411 keyIterator = OSCollectionIterator::withCollection(propertyDict.get()); 412 if (!keyIterator) { 413 OSKextLog(/* kext */ NULL, 414 kOSKextLogErrorLevel | 415 kOSKextLogGeneralFlag, 416 "Can't allocate iterator for driver images."); 417 goto finish; 418 } 419 420 /* Create dictionary of excluded kexts 421 */ 422 #ifndef CONFIG_EMBEDDED 423 OSKext::createExcludeListFromBooterData(propertyDict.get(), keyIterator.get()); 424 #endif 425 // !! reset the iterator, not the pointer 426 keyIterator->reset(); 427 428 while ((deviceTreeName = 429 OSDynamicCast(OSString, keyIterator->getNextObject()))) { 430 const char * devTreeNameCString = deviceTreeName->getCStringNoCopy(); 431 OSData * deviceTreeEntry = OSDynamicCast(OSData, 432 propertyDict->getObject(deviceTreeName)); 433 434 /* If there is no entry for the name, we can't do much with it. */ 435 if (!deviceTreeEntry) { 436 continue; 437 } 438 439 /* Make sure it is a kext */ 440 if (strncmp(devTreeNameCString, 441 BOOTER_KEXT_PREFIX, 442 CONST_STRLEN(BOOTER_KEXT_PREFIX))) { 443 continue; 444 } 445 446 deviceTreeBuffer = (const _DeviceTreeBuffer *) 447 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer)); 448 if (!deviceTreeBuffer) { 449 /* We can't get to the data, so we can't do anything, 450 * not even free it from physical memory (if it's there). 451 */ 452 OSKextLog(/* kext */ NULL, 453 kOSKextLogErrorLevel | 454 kOSKextLogDirectoryScanFlag, 455 "Device tree entry %s has NULL pointer.", 456 devTreeNameCString); 457 goto finish; // xxx - continue, panic? 458 } 459 460 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr); 461 if (!booterDataPtr) { 462 OSKextLog(/* kext */ NULL, 463 kOSKextLogErrorLevel | 464 kOSKextLogDirectoryScanFlag, 465 "Can't get virtual address for device tree entry %s.", 466 devTreeNameCString); 467 goto finish; 468 } 469 470 /* Wrap the booter data buffer in an OSData and set a dealloc function 471 * so it will take care of the physical memory when freed. Kexts will 472 * retain the booterData for as long as they need it. Remove the entry 473 * from the booter memory map after this is done. 474 */ 475 booterData = OSData::withBytesNoCopy(booterDataPtr, 476 deviceTreeBuffer->length); 477 if (!booterData) { 478 OSKextLog(/* kext */ NULL, 479 kOSKextLogErrorLevel | 480 kOSKextLogGeneralFlag, 481 "Error - Can't allocate OSData wrapper for device tree entry %s.", 482 devTreeNameCString); 483 goto finish; 484 } 485 booterData->setDeallocFunction(osdata_phys_free); 486 487 /* Create the kext for the entry, then release it, because the 488 * kext system keeps them around until explicitly removed. 489 * Any creation/registration failures are already logged for us. 490 */ 491 OSSharedPtr<OSKext> newKext = OSKext::withBooterData(deviceTreeName, booterData.get()); 492 493 booterMemoryMap->removeProperty(deviceTreeName); 494 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */ 495 496 finish: 497 return; 498 } 499 500 /********************************************************************* 501 *********************************************************************/ 502 #define COM_APPLE "com.apple." 503 504 void 505 KLDBootstrap::loadSecurityExtensions(void) 506 { 507 OSSharedPtr<OSDictionary> extensionsDict; 508 OSSharedPtr<OSCollectionIterator> keyIterator; 509 OSString * bundleID = NULL;// don't release 510 OSKext * theKext = NULL;// don't release 511 512 OSKextLog(/* kext */ NULL, 513 kOSKextLogStepLevel | 514 kOSKextLogLoadFlag, 515 "Loading security extensions."); 516 517 extensionsDict = OSKext::copyKexts(); 518 if (!extensionsDict) { 519 return; 520 } 521 522 keyIterator = OSCollectionIterator::withCollection(extensionsDict.get()); 523 if (!keyIterator) { 524 OSKextLog(/* kext */ NULL, 525 kOSKextLogErrorLevel | 526 kOSKextLogGeneralFlag, 527 "Failed to allocate iterator for security extensions."); 528 goto finish; 529 } 530 531 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) { 532 const char * bundle_id = bundleID->getCStringNoCopy(); 533 534 /* Skip extensions whose bundle IDs don't start with "com.apple.". 535 */ 536 if (!bundle_id || 537 (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) { 538 continue; 539 } 540 541 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID)); 542 if (!theKext) { 543 continue; 544 } 545 546 if (kOSBooleanTrue == theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)) { 547 OSKextLog(/* kext */ NULL, 548 kOSKextLogStepLevel | 549 kOSKextLogLoadFlag, 550 "Loading security extension %s.", bundleID->getCStringNoCopy()); 551 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(), 552 /* allowDefer */ false); 553 } 554 } 555 556 finish: 557 return; 558 } 559 560 /********************************************************************* 561 * We used to require that all listed kernel components load, but 562 * nowadays we can get them from userland so we only try to load the 563 * ones we have. If an error occurs later, such is life. 564 * 565 * Note that we look the kexts up first, so we can avoid spurious 566 * (in this context, anyhow) log messages about kexts not being found. 567 * 568 * xxx - do we even need to do this any more? Check if the kernel 569 * xxx - compoonents just load in the regular paths 570 *********************************************************************/ 571 OSReturn 572 KLDBootstrap::loadKernelComponentKexts(void) 573 { 574 OSReturn result = kOSReturnSuccess;// optimistic 575 OSSharedPtr<OSKext> theKext; 576 const char ** kextIDPtr = NULL; // do not release 577 578 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) { 579 theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr); 580 581 if (theKext) { 582 if (kOSReturnSuccess != OSKext::loadKextWithIdentifier( 583 *kextIDPtr, /* allowDefer */ false)) { 584 // xxx - check KextBookkeeping, might be redundant 585 OSKextLog(/* kext */ NULL, 586 kOSKextLogErrorLevel | 587 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, 588 "Failed to initialize kernel component %s.", *kextIDPtr); 589 result = kOSReturnError; 590 } 591 } 592 } 593 594 return result; 595 } 596 597 /********************************************************************* 598 * Ensure that Kernel External Components are loaded early in boot, 599 * before other kext personalities get sent to the IOCatalogue. These 600 * kexts are treated specially because they may provide the implementation 601 * for kernel-vended KPI, so they must register themselves before 602 * general purpose IOKit probing begins. 603 *********************************************************************/ 604 605 #define COM_APPLE_KEC "com.apple.kec." 606 607 void 608 KLDBootstrap::loadKernelExternalComponents(void) 609 { 610 OSSharedPtr<OSDictionary> extensionsDict; 611 OSSharedPtr<OSCollectionIterator> keyIterator; 612 OSString * bundleID = NULL;// don't release 613 OSKext * theKext = NULL;// don't release 614 OSBoolean * isKernelExternalComponent = NULL;// don't release 615 616 OSKextLog(/* kext */ NULL, 617 kOSKextLogStepLevel | 618 kOSKextLogLoadFlag, 619 "Loading Kernel External Components."); 620 621 extensionsDict = OSKext::copyKexts(); 622 if (!extensionsDict) { 623 return; 624 } 625 626 keyIterator = OSCollectionIterator::withCollection(extensionsDict.get()); 627 if (!keyIterator) { 628 OSKextLog(/* kext */ NULL, 629 kOSKextLogErrorLevel | 630 kOSKextLogGeneralFlag, 631 "Failed to allocate iterator for Kernel External Components."); 632 goto finish; 633 } 634 635 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) { 636 const char * bundle_id = bundleID->getCStringNoCopy(); 637 638 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.". 639 */ 640 if (!bundle_id || 641 (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) { 642 continue; 643 } 644 645 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID)); 646 if (!theKext) { 647 continue; 648 } 649 650 isKernelExternalComponent = OSDynamicCast(OSBoolean, 651 theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey)); 652 if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) { 653 OSKextLog(/* kext */ NULL, 654 kOSKextLogStepLevel | 655 kOSKextLogLoadFlag, 656 "Loading kernel external component %s.", bundleID->getCStringNoCopy()); 657 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(), 658 /* allowDefer */ false); 659 } 660 } 661 662 finish: 663 return; 664 } 665 666 /********************************************************************* 667 *********************************************************************/ 668 void 669 KLDBootstrap::readBuiltinPersonalities(void) 670 { 671 OSSharedPtr<OSObject> parsedXML; 672 OSArray * builtinExtensions = NULL;// do not release 673 OSSharedPtr<OSArray> allPersonalities; 674 OSSharedPtr<OSString> errorString; 675 kernel_section_t * infosect = NULL;// do not free 676 OSSharedPtr<OSCollectionIterator> personalitiesIterator; 677 unsigned int count, i; 678 679 OSKextLog(/* kext */ NULL, 680 kOSKextLogStepLevel | 681 kOSKextLogLoadFlag, 682 "Reading built-in kernel personalities for I/O Kit drivers."); 683 684 /* Look in the __BUILTIN __info segment for an array of Info.plist 685 * entries. For each one, extract the personalities dictionary, add 686 * it to our array, then push them all (without matching) to 687 * the IOCatalogue. This can be used to augment the personalities 688 * in gIOKernelConfigTables, especially when linking entire kexts into 689 * the mach_kernel image. 690 */ 691 infosect = getsectbyname("__BUILTIN", "__info"); 692 if (!infosect) { 693 // this isn't fatal 694 goto finish; 695 } 696 697 parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr, 698 errorString); 699 if (parsedXML) { 700 builtinExtensions = OSDynamicCast(OSArray, parsedXML.get()); 701 } 702 if (!builtinExtensions) { 703 const char * errorCString = "(unknown error)"; 704 705 if (errorString && errorString->getCStringNoCopy()) { 706 errorCString = errorString->getCStringNoCopy(); 707 } else if (parsedXML) { 708 errorCString = "not an array"; 709 } 710 OSKextLog(/* kext */ NULL, 711 kOSKextLogErrorLevel | 712 kOSKextLogLoadFlag, 713 "Error unserializing built-in personalities: %s.", errorCString); 714 goto finish; 715 } 716 717 // estimate 3 personalities per Info.plist/kext 718 count = builtinExtensions->getCount(); 719 allPersonalities = OSArray::withCapacity(count * 3); 720 721 for (i = 0; i < count; i++) { 722 OSDictionary * infoDict = NULL;// do not release 723 OSString * moduleName = NULL;// do not release 724 OSDictionary * personalities;// do not release 725 OSString * personalityName;// do not release 726 727 infoDict = OSDynamicCast(OSDictionary, 728 builtinExtensions->getObject(i)); 729 if (!infoDict) { 730 continue; 731 } 732 733 moduleName = OSDynamicCast(OSString, 734 infoDict->getObject(kCFBundleIdentifierKey)); 735 if (!moduleName) { 736 continue; 737 } 738 739 OSKextLog(/* kext */ NULL, 740 kOSKextLogStepLevel | 741 kOSKextLogLoadFlag, 742 "Adding personalities for built-in driver %s:", 743 moduleName->getCStringNoCopy()); 744 745 personalities = OSDynamicCast(OSDictionary, 746 infoDict->getObject("IOKitPersonalities")); 747 if (!personalities) { 748 continue; 749 } 750 751 personalitiesIterator = OSCollectionIterator::withCollection(personalities); 752 if (!personalitiesIterator) { 753 continue; // xxx - well really, what can we do? should we panic? 754 } 755 756 while ((personalityName = OSDynamicCast(OSString, 757 personalitiesIterator->getNextObject()))) { 758 OSDictionary * personality = OSDynamicCast(OSDictionary, 759 personalities->getObject(personalityName)); 760 761 OSKextLog(/* kext */ NULL, 762 kOSKextLogDetailLevel | 763 kOSKextLogLoadFlag, 764 "Adding built-in driver personality %s.", 765 personalityName->getCStringNoCopy()); 766 767 if (personality && !personality->getObject(kCFBundleIdentifierKey)) { 768 personality->setObject(kCFBundleIdentifierKey, moduleName); 769 } 770 allPersonalities->setObject(personality); 771 } 772 } 773 774 gIOCatalogue->addDrivers(allPersonalities.get(), false); 775 776 finish: 777 return; 778 } 779 780 #if PRAGMA_MARK 781 #pragma mark Bootstrap Functions 782 #endif 783 /********************************************************************* 784 * Bootstrap Functions 785 *********************************************************************/ 786 static void 787 bootstrapRecordStartupExtensions(void) 788 { 789 sBootstrapObject.readStartupExtensions(); 790 return; 791 } 792 793 static void 794 bootstrapLoadSecurityExtensions(void) 795 { 796 sBootstrapObject.loadSecurityExtensions(); 797 return; 798 } 799 800