1 /* 2 * Copyright (c) 2000 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 } 33 34 #include <libkern/version.h> 35 #include <libkern/c++/OSContainers.h> 36 #include <libkern/OSKextLibPrivate.h> 37 #include <libkern/c++/OSKext.h> 38 #include <IOKit/IOLib.h> 39 #include <IOKit/IOService.h> 40 #include <IOKit/IODeviceTreeSupport.h> 41 #include <IOKit/IOCatalogue.h> 42 43 #if PRAGMA_MARK 44 #pragma mark Bootstrap Declarations 45 #endif 46 /********************************************************************* 47 * Bootstrap Declarations 48 * 49 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap 50 * code from other parts of the kernel, so function symbols are not 51 * exported; rather pointers to those functions are exported. 52 * 53 * xxx - need to think about locking for handling the 'weak' refs. 54 * xxx - do export a non-KLD function that says you've called a 55 * xxx - bootstrap function that has been removed. 56 * 57 * ALL call-ins to this segment of the kernel must be done through 58 * exported pointers. The symbols themselves are private and not to 59 * be linked against. 60 *********************************************************************/ 61 extern "C" { 62 extern void (*record_startup_extensions_function)(void); 63 extern void (*load_security_extensions_function)(void); 64 }; 65 66 static void bootstrapRecordStartupExtensions(void); 67 static void bootstrapLoadSecurityExtensions(void); 68 69 70 #if PRAGMA_MARK 71 #pragma mark Macros 72 #endif 73 /********************************************************************* 74 * Macros 75 *********************************************************************/ 76 #define CONST_STRLEN(str) (sizeof(str) - 1) 77 78 #if PRAGMA_MARK 79 #pragma mark Kernel Component Kext Identifiers 80 #endif 81 /********************************************************************* 82 * Kernel Component Kext Identifiers 83 * 84 * We could have each kernel resource kext automatically "load" as 85 * it's created, but it's nicer to have them listed in kextstat in 86 * the order of this list. We'll walk through this after setting up 87 * all the boot kexts and have them load up. 88 *********************************************************************/ 89 static const char * sKernelComponentNames[] = { 90 // The kexts for these IDs must have a version matching 'osrelease'. 91 "com.apple.kernel", 92 "com.apple.kpi.bsd", 93 "com.apple.kpi.dsep", 94 "com.apple.kpi.iokit", 95 "com.apple.kpi.libkern", 96 "com.apple.kpi.mach", 97 "com.apple.kpi.private", 98 "com.apple.kpi.unsupported", 99 "com.apple.iokit.IONVRAMFamily", 100 "com.apple.driver.AppleNMI", 101 "com.apple.iokit.IOSystemManagementFamily", 102 "com.apple.iokit.ApplePlatformFamily", 103 104 #if defined(__i386__) || defined(__arm__) 105 /* These ones are not supported on x86_64 or any newer platforms. 106 * They must be version 7.9.9; check by "com.apple.kernel.", with 107 * the trailing period; "com.apple.kernel" always represents the 108 * current kernel version. 109 */ 110 "com.apple.kernel.6.0", 111 "com.apple.kernel.bsd", 112 "com.apple.kernel.iokit", 113 "com.apple.kernel.libkern", 114 "com.apple.kernel.mach", 115 #endif 116 117 NULL 118 }; 119 120 #if PRAGMA_MARK 121 #pragma mark KLDBootstrap Class 122 #endif 123 /********************************************************************* 124 * KLDBootstrap Class 125 * 126 * We use a C++ class here so that it can be a friend of OSKext and 127 * get at private stuff. We can't hide the class itself, but we can 128 * hide the instance through which we invoke the functions. 129 *********************************************************************/ 130 class KLDBootstrap { 131 friend void bootstrapRecordStartupExtensions(void); 132 friend void bootstrapLoadSecurityExtensions(void); 133 134 private: 135 void readStartupExtensions(void); 136 137 void readPrelinkedExtensions( 138 kernel_section_t * prelinkInfoSect); 139 void readBooterExtensions(void); 140 OSReturn readMkextExtensions( 141 OSString * deviceTreeName, 142 OSData * deviceTreeData); 143 144 OSReturn loadKernelComponentKexts(void); 145 void readBuiltinPersonalities(void); 146 147 void loadSecurityExtensions(void); 148 149 public: 150 KLDBootstrap(void); 151 ~KLDBootstrap(void); 152 }; 153 154 static KLDBootstrap sBootstrapObject; 155 156 /********************************************************************* 157 * Set the function pointers for the entry points into the bootstrap 158 * segment upon C++ static constructor invocation. 159 *********************************************************************/ 160 KLDBootstrap::KLDBootstrap(void) 161 { 162 if (this != &sBootstrapObject) { 163 panic("Attempt to access bootstrap segment."); 164 } 165 record_startup_extensions_function = &bootstrapRecordStartupExtensions; 166 load_security_extensions_function = &bootstrapLoadSecurityExtensions; 167 } 168 169 /********************************************************************* 170 * Clear the function pointers for the entry points into the bootstrap 171 * segment upon C++ static destructor invocation. 172 *********************************************************************/ 173 KLDBootstrap::~KLDBootstrap(void) 174 { 175 if (this != &sBootstrapObject) { 176 panic("Attempt to access bootstrap segment."); 177 } 178 179 180 record_startup_extensions_function = 0; 181 load_security_extensions_function = 0; 182 } 183 184 /********************************************************************* 185 *********************************************************************/ 186 void 187 KLDBootstrap::readStartupExtensions(void) 188 { 189 kernel_section_t * prelinkInfoSect = NULL; // do not free 190 191 OSKextLog(/* kext */ NULL, 192 kOSKextLogProgressLevel | 193 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag | 194 kOSKextLogKextBookkeepingFlag, 195 "Reading startup extensions."); 196 197 /* If the prelink info segment has a nonzero size, we are prelinked 198 * and won't have any individual kexts or mkexts to read. 199 * Otherwise, we need to read kexts or the mkext from what the booter 200 * has handed us. 201 */ 202 prelinkInfoSect = getsectbyname(kPrelinkInfoSegment, kPrelinkInfoSection); 203 if (prelinkInfoSect->size) { 204 readPrelinkedExtensions(prelinkInfoSect); 205 } else { 206 readBooterExtensions(); 207 } 208 209 loadKernelComponentKexts(); 210 readBuiltinPersonalities(); 211 OSKext::sendAllKextPersonalitiesToCatalog(); 212 213 return; 214 } 215 216 /********************************************************************* 217 *********************************************************************/ 218 void 219 KLDBootstrap::readPrelinkedExtensions( 220 kernel_section_t * prelinkInfoSect) 221 { 222 OSArray * infoDictArray = NULL; // do not release 223 OSObject * parsedXML = NULL; // must release 224 OSDictionary * prelinkInfoDict = NULL; // do not release 225 OSString * errorString = NULL; // must release 226 OSKext * theKernel = NULL; // must release 227 228 kernel_segment_command_t * prelinkTextSegment = NULL; // see code 229 kernel_segment_command_t * prelinkInfoSegment = NULL; // see code 230 231 /* We make some copies of data, but if anything fails we're basically 232 * going to fail the boot, so these won't be cleaned up on error. 233 */ 234 void * prelinkData = NULL; // see code 235 vm_size_t prelinkLength = 0; 236 237 #if !__LP64__ && !defined(__arm__) 238 vm_map_offset_t prelinkDataMapOffset = 0; 239 void * prelinkCopy = NULL; // see code 240 kern_return_t mem_result = KERN_SUCCESS; 241 #endif 242 243 OSDictionary * infoDict = NULL; // do not release 244 245 IORegistryEntry * registryRoot = NULL; // do not release 246 OSNumber * prelinkCountObj = NULL; // must release 247 248 u_int i = 0; 249 250 OSKextLog(/* kext */ NULL, 251 kOSKextLogProgressLevel | 252 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, 253 "Starting from prelinked kernel."); 254 255 prelinkTextSegment = getsegbyname(kPrelinkTextSegment); 256 if (!prelinkTextSegment) { 257 OSKextLog(/* kext */ NULL, 258 kOSKextLogErrorLevel | 259 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, 260 "Can't find prelinked kexts' text segment."); 261 goto finish; 262 } 263 264 prelinkData = (void *) prelinkTextSegment->vmaddr; 265 prelinkLength = prelinkTextSegment->vmsize; 266 267 #if !__LP64__ && !__arm__ 268 /* XXX: arm's pmap implementation doesn't seem to let us do this */ 269 270 /* To enable paging and write/execute protections on the kext 271 * executables, we need to copy them out of the booter-created 272 * memory, reallocate that space with VM, then prelinkCopy them back in. 273 * This isn't necessary on LP64 because kexts have their own VM 274 * region on that architecture model. 275 */ 276 277 mem_result = kmem_alloc(kernel_map, (vm_offset_t *)&prelinkCopy, 278 prelinkLength); 279 if (mem_result != KERN_SUCCESS) { 280 OSKextLog(/* kext */ NULL, 281 kOSKextLogErrorLevel | 282 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, 283 "Can't copy prelinked kexts' text for VM reassign."); 284 goto finish; 285 } 286 287 /* Copy it out. 288 */ 289 memcpy(prelinkCopy, prelinkData, prelinkLength); 290 291 /* Dump the booter memory. 292 */ 293 ml_static_mfree((vm_offset_t)prelinkData, prelinkLength); 294 295 /* Set up the VM region. 296 */ 297 prelinkDataMapOffset = (vm_map_offset_t)(uintptr_t)prelinkData; 298 mem_result = vm_map_enter_mem_object( 299 kernel_map, 300 &prelinkDataMapOffset, 301 prelinkLength, /* mask */ 0, 302 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, 303 (ipc_port_t)NULL, 304 (vm_object_offset_t) 0, 305 /* copy */ FALSE, 306 /* cur_protection */ VM_PROT_ALL, 307 /* max_protection */ VM_PROT_ALL, 308 /* inheritance */ VM_INHERIT_DEFAULT); 309 if ((mem_result != KERN_SUCCESS) || 310 (prelinkTextSegment->vmaddr != prelinkDataMapOffset)) 311 { 312 OSKextLog(/* kext */ NULL, 313 kOSKextLogErrorLevel | 314 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, 315 "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).", 316 (unsigned long long) prelinkDataMapOffset, prelinkLength, mem_result); 317 goto finish; 318 } 319 prelinkData = (void *)(uintptr_t)prelinkDataMapOffset; 320 321 /* And copy it back. 322 */ 323 memcpy(prelinkData, prelinkCopy, prelinkLength); 324 325 kmem_free(kernel_map, (vm_offset_t)prelinkCopy, prelinkLength); 326 #endif /* !__LP64__ && !__arm__*/ 327 328 /* Unserialize the info dictionary from the prelink info section. 329 */ 330 parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr, 331 &errorString); 332 if (parsedXML) { 333 prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML); 334 } 335 if (!prelinkInfoDict) { 336 const char * errorCString = "(unknown error)"; 337 338 if (errorString && errorString->getCStringNoCopy()) { 339 errorCString = errorString->getCStringNoCopy(); 340 } else if (parsedXML) { 341 errorCString = "not a dictionary"; 342 } 343 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 344 "Error unserializing prelink plist: %s.", errorCString); 345 goto finish; 346 } 347 348 infoDictArray = OSDynamicCast(OSArray, 349 prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey)); 350 if (!infoDictArray) { 351 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, 352 "The prelinked kernel has no kext info dictionaries"); 353 goto finish; 354 } 355 356 /* Create OSKext objects for each info dictionary. 357 */ 358 for (i = 0; i < infoDictArray->getCount(); ++i) { 359 infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i)); 360 if (!infoDict) { 361 OSKextLog(/* kext */ NULL, 362 kOSKextLogErrorLevel | 363 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, 364 "Can't find info dictionary for prelinked kext #%d.", i); 365 continue; 366 } 367 368 /* Create the kext for the entry, then release it, because the 369 * kext system keeps them around until explicitly removed. 370 * Any creation/registration failures are already logged for us. 371 */ 372 OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict); 373 OSSafeReleaseNULL(newKext); 374 } 375 376 /* Store the number of prelinked kexts in the registry so we can tell 377 * when the system has been started from a prelinked kernel. 378 */ 379 registryRoot = IORegistryEntry::getRegistryRoot(); 380 assert(registryRoot); 381 382 prelinkCountObj = OSNumber::withNumber( 383 (unsigned long long)infoDictArray->getCount(), 384 8 * sizeof(uint32_t)); 385 assert(prelinkCountObj); 386 if (prelinkCountObj) { 387 registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj); 388 } 389 390 OSKextLog(/* kext */ NULL, 391 kOSKextLogProgressLevel | 392 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag | 393 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, 394 "%u prelinked kexts", 395 infoDictArray->getCount()); 396 397 #if __LP64__ 398 /* On LP64 systems, kexts are copied to their own special VM region 399 * during OSKext init time, so we can free the whole segment now. 400 */ 401 ml_static_mfree((vm_offset_t) prelinkData, prelinkLength); 402 #endif /* __LP64__ */ 403 404 /* Free the prelink info segment, we're done with it. 405 */ 406 prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment); 407 if (prelinkInfoSegment) { 408 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr, 409 (vm_size_t)prelinkInfoSegment->vmsize); 410 } 411 412 finish: 413 OSSafeRelease(errorString); 414 OSSafeRelease(parsedXML); 415 OSSafeRelease(theKernel); 416 OSSafeRelease(prelinkCountObj); 417 return; 418 } 419 420 /********************************************************************* 421 *********************************************************************/ 422 #define BOOTER_KEXT_PREFIX "Driver-" 423 #define BOOTER_MKEXT_PREFIX "DriversPackage-" 424 425 typedef struct _DeviceTreeBuffer { 426 uint32_t paddr; 427 uint32_t length; 428 } _DeviceTreeBuffer; 429 430 void 431 KLDBootstrap::readBooterExtensions(void) 432 { 433 IORegistryEntry * booterMemoryMap = NULL; // must release 434 OSDictionary * propertyDict = NULL; // must release 435 OSCollectionIterator * keyIterator = NULL; // must release 436 OSString * deviceTreeName = NULL; // do not release 437 438 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not free 439 char * booterDataPtr = NULL; // do not free 440 OSData * booterData = NULL; // must release 441 442 OSKext * aKext = NULL; // must release 443 444 OSKextLog(/* kext */ NULL, 445 kOSKextLogProgressLevel | 446 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, 447 "Reading startup extensions/mkexts from booter memory."); 448 449 booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane); 450 451 if (!booterMemoryMap) { 452 OSKextLog(/* kext */ NULL, 453 kOSKextLogErrorLevel | 454 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag, 455 "Can't read booter memory map."); 456 goto finish; 457 } 458 459 propertyDict = booterMemoryMap->dictionaryWithProperties(); 460 if (!propertyDict) { 461 OSKextLog(/* kext */ NULL, 462 kOSKextLogErrorLevel | 463 kOSKextLogDirectoryScanFlag, 464 "Can't get property dictionary from memory map."); 465 goto finish; 466 } 467 468 keyIterator = OSCollectionIterator::withCollection(propertyDict); 469 if (!keyIterator) { 470 OSKextLog(/* kext */ NULL, 471 kOSKextLogErrorLevel | 472 kOSKextLogGeneralFlag, 473 "Can't allocate iterator for driver images."); 474 goto finish; 475 } 476 477 while ( ( deviceTreeName = 478 OSDynamicCast(OSString, keyIterator->getNextObject() ))) { 479 480 boolean_t isMkext = FALSE; 481 const char * devTreeNameCString = deviceTreeName->getCStringNoCopy(); 482 OSData * deviceTreeEntry = OSDynamicCast(OSData, 483 propertyDict->getObject(deviceTreeName)); 484 485 /* Clear out the booterData from the prior iteration. 486 */ 487 OSSafeReleaseNULL(booterData); 488 489 /* If there is no entry for the name, we can't do much with it. */ 490 if (!deviceTreeEntry) { 491 continue; 492 } 493 494 /* Make sure it is either a kext or an mkext */ 495 if (!strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX, 496 CONST_STRLEN(BOOTER_KEXT_PREFIX))) { 497 498 isMkext = FALSE; 499 500 } else if (!strncmp(devTreeNameCString, BOOTER_MKEXT_PREFIX, 501 CONST_STRLEN(BOOTER_MKEXT_PREFIX))) { 502 503 isMkext = TRUE; 504 505 } else { 506 continue; 507 } 508 509 deviceTreeBuffer = (const _DeviceTreeBuffer *) 510 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer)); 511 if (!deviceTreeBuffer) { 512 /* We can't get to the data, so we can't do anything, 513 * not even free it from physical memory (if it's there). 514 */ 515 OSKextLog(/* kext */ NULL, 516 kOSKextLogErrorLevel | 517 kOSKextLogDirectoryScanFlag, 518 "Device tree entry %s has NULL pointer.", 519 devTreeNameCString); 520 goto finish; // xxx - continue, panic? 521 } 522 523 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr); 524 if (!booterDataPtr) { 525 OSKextLog(/* kext */ NULL, 526 kOSKextLogErrorLevel | 527 kOSKextLogDirectoryScanFlag, 528 "Can't get virtual address for device tree mkext entry %s.", 529 devTreeNameCString); 530 goto finish; 531 } 532 533 /* Wrap the booter data buffer in an OSData and set a dealloc function 534 * so it will take care of the physical memory when freed. Kexts will 535 * retain the booterData for as long as they need it. Remove the entry 536 * from the booter memory map after this is done. 537 */ 538 booterData = OSData::withBytesNoCopy(booterDataPtr, 539 deviceTreeBuffer->length); 540 if (!booterData) { 541 OSKextLog(/* kext */ NULL, 542 kOSKextLogErrorLevel | 543 kOSKextLogGeneralFlag, 544 "Error - Can't allocate OSData wrapper for device tree entry %s.", 545 devTreeNameCString); 546 goto finish; 547 } 548 booterData->setDeallocFunction(osdata_phys_free); 549 550 if (isMkext) { 551 readMkextExtensions(deviceTreeName, booterData); 552 } else { 553 /* Create the kext for the entry, then release it, because the 554 * kext system keeps them around until explicitly removed. 555 * Any creation/registration failures are already logged for us. 556 */ 557 OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData); 558 OSSafeRelease(newKext); 559 } 560 561 booterMemoryMap->removeProperty(deviceTreeName); 562 563 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */ 564 565 finish: 566 567 OSSafeRelease(booterMemoryMap); 568 OSSafeRelease(propertyDict); 569 OSSafeRelease(keyIterator); 570 OSSafeRelease(booterData); 571 OSSafeRelease(aKext); 572 return; 573 } 574 575 /********************************************************************* 576 *********************************************************************/ 577 OSReturn 578 KLDBootstrap::readMkextExtensions( 579 OSString * deviceTreeName, 580 OSData * booterData) 581 { 582 OSReturn result = kOSReturnError; 583 584 uint32_t checksum; 585 IORegistryEntry * registryRoot = NULL; // do not release 586 OSData * checksumObj = NULL; // must release 587 588 OSKextLog(/* kext */ NULL, 589 kOSKextLogStepLevel | 590 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, 591 "Reading startup mkext archive from device tree entry %s.", 592 deviceTreeName->getCStringNoCopy()); 593 594 /* If we successfully read the archive, 595 * then save the mkext's checksum in the IORegistry. 596 * assumes we'll only ever have one mkext to boot 597 */ 598 result = OSKext::readMkextArchive(booterData, &checksum); 599 if (result == kOSReturnSuccess) { 600 601 OSKextLog(/* kext */ NULL, 602 kOSKextLogProgressLevel | 603 kOSKextLogArchiveFlag, 604 "Startup mkext archive has checksum 0x%x.", (int)checksum); 605 606 registryRoot = IORegistryEntry::getRegistryRoot(); 607 assert(registryRoot); 608 checksumObj = OSData::withBytes((void *)&checksum, sizeof(checksum)); 609 assert(checksumObj); 610 if (checksumObj) { 611 registryRoot->setProperty(kOSStartupMkextCRC, checksumObj); 612 } 613 } 614 615 return result; 616 } 617 618 /********************************************************************* 619 *********************************************************************/ 620 #define COM_APPLE "com.apple." 621 622 void 623 KLDBootstrap::loadSecurityExtensions(void) 624 { 625 OSDictionary * extensionsDict = NULL; // must release 626 OSCollectionIterator * keyIterator = NULL; // must release 627 OSString * bundleID = NULL; // don't release 628 OSKext * theKext = NULL; // don't release 629 OSBoolean * isSecurityKext = NULL; // don't release 630 631 OSKextLog(/* kext */ NULL, 632 kOSKextLogStepLevel | 633 kOSKextLogLoadFlag, 634 "Loading security extensions."); 635 636 extensionsDict = OSKext::copyKexts(); 637 if (!extensionsDict) { 638 return; 639 } 640 641 keyIterator = OSCollectionIterator::withCollection(extensionsDict); 642 if (!keyIterator) { 643 OSKextLog(/* kext */ NULL, 644 kOSKextLogErrorLevel | 645 kOSKextLogGeneralFlag, 646 "Failed to allocate iterator for security extensions."); 647 goto finish; 648 } 649 650 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) { 651 652 const char * bundle_id = bundleID->getCStringNoCopy(); 653 654 /* Skip extensions whose bundle IDs don't start with "com.apple.". 655 */ 656 if (!bundle_id || 657 (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) { 658 659 continue; 660 } 661 662 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID)); 663 if (!theKext) { 664 continue; 665 } 666 667 isSecurityKext = OSDynamicCast(OSBoolean, 668 theKext->getPropertyForHostArch("AppleSecurityExtension")); 669 if (isSecurityKext && isSecurityKext->isTrue()) { 670 OSKextLog(/* kext */ NULL, 671 kOSKextLogStepLevel | 672 kOSKextLogLoadFlag, 673 "Loading security extension %s.", bundleID->getCStringNoCopy()); 674 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(), 675 /* allowDefer */ false); 676 } 677 } 678 679 finish: 680 OSSafeRelease(keyIterator); 681 OSSafeRelease(extensionsDict); 682 683 return; 684 } 685 686 /********************************************************************* 687 * We used to require that all listed kernel components load, but 688 * nowadays we can get them from userland so we only try to load the 689 * ones we have. If an error occurs later, such is life. 690 * 691 * Note that we look the kexts up first, so we can avoid spurious 692 * (in this context, anyhow) log messages about kexts not being found. 693 * 694 * xxx - do we even need to do this any more? Check if the kernel 695 * xxx - compoonents just load in the regular paths 696 *********************************************************************/ 697 OSReturn 698 KLDBootstrap::loadKernelComponentKexts(void) 699 { 700 OSReturn result = kOSReturnSuccess; // optimistic 701 OSKext * theKext = NULL; // must release 702 const char ** kextIDPtr = NULL; // do not release 703 704 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) { 705 706 OSSafeReleaseNULL(theKext); 707 theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr); 708 709 if (theKext) { 710 if (kOSReturnSuccess != OSKext::loadKextWithIdentifier( 711 *kextIDPtr, /* allowDefer */ false)) { 712 713 // xxx - check KextBookkeeping, might be redundant 714 OSKextLog(/* kext */ NULL, 715 kOSKextLogErrorLevel | 716 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, 717 "Failed to initialize kernel component %s.", *kextIDPtr); 718 result = kOSReturnError; 719 } 720 } 721 } 722 723 OSSafeRelease(theKext); 724 return result; 725 } 726 727 /********************************************************************* 728 *********************************************************************/ 729 void 730 KLDBootstrap::readBuiltinPersonalities(void) 731 { 732 OSObject * parsedXML = NULL; // must release 733 OSArray * builtinExtensions = NULL; // do not release 734 OSArray * allPersonalities = NULL; // must release 735 OSString * errorString = NULL; // must release 736 kernel_section_t * infosect = NULL; // do not free 737 OSCollectionIterator * personalitiesIterator = NULL; // must release 738 unsigned int count, i; 739 740 OSKextLog(/* kext */ NULL, 741 kOSKextLogStepLevel | 742 kOSKextLogLoadFlag, 743 "Reading built-in kernel personalities for I/O Kit drivers."); 744 745 /* Look in the __BUILTIN __info segment for an array of Info.plist 746 * entries. For each one, extract the personalities dictionary, add 747 * it to our array, then push them all (without matching) to 748 * the IOCatalogue. This can be used to augment the personalities 749 * in gIOKernelConfigTables, especially when linking entire kexts into 750 * the mach_kernel image. 751 */ 752 infosect = getsectbyname("__BUILTIN", "__info"); 753 if (!infosect) { 754 // this isn't fatal 755 goto finish; 756 } 757 758 parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr, 759 &errorString); 760 if (parsedXML) { 761 builtinExtensions = OSDynamicCast(OSArray, parsedXML); 762 } 763 if (!builtinExtensions) { 764 const char * errorCString = "(unknown error)"; 765 766 if (errorString && errorString->getCStringNoCopy()) { 767 errorCString = errorString->getCStringNoCopy(); 768 } else if (parsedXML) { 769 errorCString = "not an array"; 770 } 771 OSKextLog(/* kext */ NULL, 772 kOSKextLogErrorLevel | 773 kOSKextLogLoadFlag, 774 "Error unserializing built-in personalities: %s.", errorCString); 775 goto finish; 776 } 777 778 // estimate 3 personalities per Info.plist/kext 779 count = builtinExtensions->getCount(); 780 allPersonalities = OSArray::withCapacity(count * 3); 781 782 for (i = 0; i < count; i++) { 783 OSDictionary * infoDict = NULL; // do not release 784 OSString * moduleName = NULL; // do not release 785 OSDictionary * personalities; // do not release 786 OSString * personalityName; // do not release 787 788 OSSafeReleaseNULL(personalitiesIterator); 789 790 infoDict = OSDynamicCast(OSDictionary, 791 builtinExtensions->getObject(i)); 792 if (!infoDict) { 793 continue; 794 } 795 796 moduleName = OSDynamicCast(OSString, 797 infoDict->getObject(kCFBundleIdentifierKey)); 798 if (!moduleName) { 799 continue; 800 } 801 802 OSKextLog(/* kext */ NULL, 803 kOSKextLogStepLevel | 804 kOSKextLogLoadFlag, 805 "Adding personalities for built-in driver %s:", 806 moduleName->getCStringNoCopy()); 807 808 personalities = OSDynamicCast(OSDictionary, 809 infoDict->getObject("IOKitPersonalities")); 810 if (!personalities) { 811 continue; 812 } 813 814 personalitiesIterator = OSCollectionIterator::withCollection(personalities); 815 if (!personalitiesIterator) { 816 continue; // xxx - well really, what can we do? should we panic? 817 } 818 819 while ((personalityName = OSDynamicCast(OSString, 820 personalitiesIterator->getNextObject()))) { 821 822 OSDictionary * personality = OSDynamicCast(OSDictionary, 823 personalities->getObject(personalityName)); 824 825 OSKextLog(/* kext */ NULL, 826 kOSKextLogDetailLevel | 827 kOSKextLogLoadFlag, 828 "Adding built-in driver personality %s.", 829 personalityName->getCStringNoCopy()); 830 831 if (personality && !personality->getObject(kCFBundleIdentifierKey)) { 832 personality->setObject(kCFBundleIdentifierKey, moduleName); 833 } 834 allPersonalities->setObject(personality); 835 } 836 } 837 838 gIOCatalogue->addDrivers(allPersonalities, false); 839 840 finish: 841 OSSafeRelease(parsedXML); 842 OSSafeRelease(allPersonalities); 843 OSSafeRelease(errorString); 844 OSSafeRelease(personalitiesIterator); 845 return; 846 } 847 848 #if PRAGMA_MARK 849 #pragma mark Bootstrap Functions 850 #endif 851 /********************************************************************* 852 * Bootstrap Functions 853 *********************************************************************/ 854 static void bootstrapRecordStartupExtensions(void) 855 { 856 sBootstrapObject.readStartupExtensions(); 857 return; 858 } 859 860 static void bootstrapLoadSecurityExtensions(void) 861 { 862 sBootstrapObject.loadSecurityExtensions(); 863 return; 864 } 865 866