2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/kmod.h>
30 #include <libkern/kernel_mach_header.h>
31 #include <libkern/prelink.h>
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>
44 #define KASLR_KEXT_DEBUG 0
48 #pragma mark Bootstrap Declarations
50 /*********************************************************************
51 * Bootstrap Declarations
53 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
54 * code from other parts of the kernel, so function symbols are not
55 * exported; rather pointers to those functions are exported.
57 * xxx - need to think about locking for handling the 'weak' refs.
58 * xxx - do export a non-KLD function that says you've called a
59 * xxx - bootstrap function that has been removed.
61 * ALL call-ins to this segment of the kernel must be done through
62 * exported pointers. The symbols themselves are private and not to
64 *********************************************************************/
66 extern void (*record_startup_extensions_function
)(void);
67 extern void (*load_security_extensions_function
)(void);
70 static void bootstrapRecordStartupExtensions(void);
71 static void bootstrapLoadSecurityExtensions(void);
75 extern "C" bool IORamDiskBSDRoot(void);
81 /*********************************************************************
83 *********************************************************************/
84 #define CONST_STRLEN(str) (sizeof(str) - 1)
87 #pragma mark Kernel Component Kext Identifiers
89 /*********************************************************************
90 * Kernel Component Kext Identifiers
92 * We could have each kernel resource kext automatically "load" as
93 * it's created, but it's nicer to have them listed in kextstat in
94 * the order of this list. We'll walk through this after setting up
95 * all the boot kexts and have them load up.
96 *********************************************************************/
97 static const char * sKernelComponentNames
[] = {
98 // The kexts for these IDs must have a version matching 'osrelease'.
101 "com.apple.kpi.dsep",
102 "com.apple.kpi.iokit",
103 "com.apple.kpi.libkern",
104 "com.apple.kpi.mach",
105 "com.apple.kpi.private",
106 "com.apple.kpi.unsupported",
107 "com.apple.iokit.IONVRAMFamily",
108 "com.apple.driver.AppleNMI",
109 "com.apple.iokit.IOSystemManagementFamily",
110 "com.apple.iokit.ApplePlatformFamily",
115 #pragma mark KLDBootstrap Class
117 /*********************************************************************
120 * We use a C++ class here so that it can be a friend of OSKext and
121 * get at private stuff. We can't hide the class itself, but we can
122 * hide the instance through which we invoke the functions.
123 *********************************************************************/
125 friend void bootstrapRecordStartupExtensions(void);
126 friend void bootstrapLoadSecurityExtensions(void);
129 void readStartupExtensions(void);
131 void readPrelinkedExtensions(
132 kernel_section_t
* prelinkInfoSect
);
133 void readBooterExtensions(void);
134 OSReturn
readMkextExtensions(
135 OSString
* deviceTreeName
,
136 OSData
* deviceTreeData
);
138 OSReturn
loadKernelComponentKexts(void);
139 void loadKernelExternalComponents(void);
140 void readBuiltinPersonalities(void);
142 void loadSecurityExtensions(void);
149 static KLDBootstrap sBootstrapObject
;
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)
157 if (this != &sBootstrapObject
) {
158 panic("Attempt to access bootstrap segment.");
160 record_startup_extensions_function
= &bootstrapRecordStartupExtensions
;
161 load_security_extensions_function
= &bootstrapLoadSecurityExtensions
;
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)
170 if (this != &sBootstrapObject
) {
171 panic("Attempt to access bootstrap segment.");
175 record_startup_extensions_function
= 0;
176 load_security_extensions_function
= 0;
179 /*********************************************************************
180 *********************************************************************/
182 KLDBootstrap::readStartupExtensions(void)
184 kernel_section_t
* prelinkInfoSect
= NULL
; // do not free
186 OSKextLog(/* kext */ NULL
,
187 kOSKextLogProgressLevel
|
188 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
|
189 kOSKextLogKextBookkeepingFlag
,
190 "Reading startup extensions.");
192 /* If the prelink info segment has a nonzero size, we are prelinked
193 * and won't have any individual kexts or mkexts to read.
194 * Otherwise, we need to read kexts or the mkext from what the booter
197 prelinkInfoSect
= getsectbyname(kPrelinkInfoSegment
, kPrelinkInfoSection
);
198 if (prelinkInfoSect
->size
) {
199 readPrelinkedExtensions(prelinkInfoSect
);
201 readBooterExtensions();
204 loadKernelComponentKexts();
205 loadKernelExternalComponents();
206 readBuiltinPersonalities();
207 OSKext::sendAllKextPersonalitiesToCatalog();
212 /*********************************************************************
213 *********************************************************************/
215 KLDBootstrap::readPrelinkedExtensions(
216 kernel_section_t
* prelinkInfoSect
)
218 OSArray
* infoDictArray
= NULL
; // do not release
219 OSObject
* parsedXML
= NULL
; // must release
220 OSDictionary
* prelinkInfoDict
= NULL
; // do not release
221 OSString
* errorString
= NULL
; // must release
222 OSKext
* theKernel
= NULL
; // must release
224 kernel_segment_command_t
* prelinkTextSegment
= NULL
; // see code
225 kernel_segment_command_t
* prelinkInfoSegment
= NULL
; // see code
227 /* We make some copies of data, but if anything fails we're basically
228 * going to fail the boot, so these won't be cleaned up on error.
230 void * prelinkData
= NULL
; // see code
231 vm_size_t prelinkLength
= 0;
234 OSDictionary
* infoDict
= NULL
; // do not release
236 IORegistryEntry
* registryRoot
= NULL
; // do not release
237 OSNumber
* prelinkCountObj
= NULL
; // must release
242 bool developerDevice
;
246 OSKextLog(/* kext */ NULL
,
247 kOSKextLogProgressLevel
|
248 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
249 "Starting from prelinked kernel.");
251 prelinkTextSegment
= getsegbyname(kPrelinkTextSegment
);
252 if (!prelinkTextSegment
) {
253 OSKextLog(/* kext */ NULL
,
254 kOSKextLogErrorLevel
|
255 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
256 "Can't find prelinked kexts' text segment.");
261 unsigned long scratchSize
;
262 vm_offset_t scratchAddr
;
264 IOLog("kaslr: prelinked kernel address info: \n");
266 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__TEXT", &scratchSize
);
267 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
268 (unsigned long)scratchAddr
,
269 (unsigned long)(scratchAddr
+ scratchSize
),
272 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__DATA", &scratchSize
);
273 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
274 (unsigned long)scratchAddr
,
275 (unsigned long)(scratchAddr
+ scratchSize
),
278 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__LINKEDIT", &scratchSize
);
279 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
280 (unsigned long)scratchAddr
,
281 (unsigned long)(scratchAddr
+ scratchSize
),
284 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__KLD", &scratchSize
);
285 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
286 (unsigned long)scratchAddr
,
287 (unsigned long)(scratchAddr
+ scratchSize
),
290 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__PRELINK_TEXT", &scratchSize
);
291 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
292 (unsigned long)scratchAddr
,
293 (unsigned long)(scratchAddr
+ scratchSize
),
296 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__PRELINK_INFO", &scratchSize
);
297 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
298 (unsigned long)scratchAddr
,
299 (unsigned long)(scratchAddr
+ scratchSize
),
303 prelinkData
= (void *) prelinkTextSegment
->vmaddr
;
304 prelinkLength
= prelinkTextSegment
->vmsize
;
307 /* Unserialize the info dictionary from the prelink info section.
309 parsedXML
= OSUnserializeXML((const char *)prelinkInfoSect
->addr
,
312 prelinkInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
314 if (!prelinkInfoDict
) {
315 const char * errorCString
= "(unknown error)";
317 if (errorString
&& errorString
->getCStringNoCopy()) {
318 errorCString
= errorString
->getCStringNoCopy();
319 } else if (parsedXML
) {
320 errorCString
= "not a dictionary";
322 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
323 "Error unserializing prelink plist: %s.", errorCString
);
328 /* Check if we should keep developer kexts around.
329 * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
331 developerDevice
= true;
332 PE_parse_boot_argn("developer", &developerDevice
, sizeof(developerDevice
));
334 ramDiskBoot
= IORamDiskBSDRoot();
335 #endif /* NO_KEXTD */
337 infoDictArray
= OSDynamicCast(OSArray
,
338 prelinkInfoDict
->getObject(kPrelinkInfoDictionaryKey
));
339 if (!infoDictArray
) {
340 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
341 "The prelinked kernel has no kext info dictionaries");
345 /* Create dictionary of excluded kexts
347 OSKext::createExcludeListFromPrelinkInfo(infoDictArray
);
349 /* Create OSKext objects for each info dictionary.
351 for (i
= 0; i
< infoDictArray
->getCount(); ++i
) {
352 infoDict
= OSDynamicCast(OSDictionary
, infoDictArray
->getObject(i
));
354 OSKextLog(/* kext */ NULL
,
355 kOSKextLogErrorLevel
|
356 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
357 "Can't find info dictionary for prelinked kext #%d.", i
);
364 /* If we're not on a developer device, skip and free developer kexts.
366 if (developerDevice
== false) {
367 OSBoolean
*devOnlyBool
= OSDynamicCast(OSBoolean
,
368 infoDict
->getObject(kOSBundleDeveloperOnlyKey
));
369 if (devOnlyBool
== kOSBooleanTrue
) {
374 /* Skip and free kexts that are only needed when booted from a ram disk.
376 if (ramDiskBoot
== false) {
377 OSBoolean
*ramDiskOnlyBool
= OSDynamicCast(OSBoolean
,
378 infoDict
->getObject(kOSBundleRamDiskOnlyKey
));
379 if (ramDiskOnlyBool
== kOSBooleanTrue
) {
384 if (dontLoad
== true) {
385 OSString
*bundleID
= OSDynamicCast(OSString
,
386 infoDict
->getObject(kCFBundleIdentifierKey
));
388 OSKextLog(NULL
, kOSKextLogWarningLevel
| kOSKextLogGeneralFlag
,
389 "Kext %s not loading.", bundleID
->getCStringNoCopy());
392 OSNumber
*addressNum
= OSDynamicCast(OSNumber
,
393 infoDict
->getObject(kPrelinkExecutableLoadKey
));
394 OSNumber
*lengthNum
= OSDynamicCast(OSNumber
,
395 infoDict
->getObject(kPrelinkExecutableSizeKey
));
396 if (addressNum
&& lengthNum
) {
397 #error Pick the right way to free prelinked data on this arch
400 infoDictArray
->removeObject(i
--);
403 #endif /* NO_KEXTD */
405 /* Create the kext for the entry, then release it, because the
406 * kext system keeps them around until explicitly removed.
407 * Any creation/registration failures are already logged for us.
409 OSKext
* newKext
= OSKext::withPrelinkedInfoDict(infoDict
);
410 OSSafeReleaseNULL(newKext
);
413 /* Store the number of prelinked kexts in the registry so we can tell
414 * when the system has been started from a prelinked kernel.
416 registryRoot
= IORegistryEntry::getRegistryRoot();
417 assert(registryRoot
);
419 prelinkCountObj
= OSNumber::withNumber(
420 (unsigned long long)infoDictArray
->getCount(),
421 8 * sizeof(uint32_t));
422 assert(prelinkCountObj
);
423 if (prelinkCountObj
) {
424 registryRoot
->setProperty(kOSPrelinkKextCountKey
, prelinkCountObj
);
427 OSKextLog(/* kext */ NULL
,
428 kOSKextLogProgressLevel
|
429 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
430 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
431 "%u prelinked kexts",
432 infoDictArray
->getCount());
434 #if CONFIG_KEXT_BASEMENT
435 /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
436 * special VM region during OSKext init time, so we can free the whole
439 ml_static_mfree((vm_offset_t
) prelinkData
, prelinkLength
);
440 #endif /* __x86_64__ */
442 /* Free the prelink info segment, we're done with it.
444 prelinkInfoSegment
= getsegbyname(kPrelinkInfoSegment
);
445 if (prelinkInfoSegment
) {
446 ml_static_mfree((vm_offset_t
)prelinkInfoSegment
->vmaddr
,
447 (vm_size_t
)prelinkInfoSegment
->vmsize
);
451 OSSafeRelease(errorString
);
452 OSSafeRelease(parsedXML
);
453 OSSafeRelease(theKernel
);
454 OSSafeRelease(prelinkCountObj
);
458 /*********************************************************************
459 *********************************************************************/
460 #define BOOTER_KEXT_PREFIX "Driver-"
461 #define BOOTER_MKEXT_PREFIX "DriversPackage-"
463 typedef struct _DeviceTreeBuffer
{
469 KLDBootstrap::readBooterExtensions(void)
471 IORegistryEntry
* booterMemoryMap
= NULL
; // must release
472 OSDictionary
* propertyDict
= NULL
; // must release
473 OSCollectionIterator
* keyIterator
= NULL
; // must release
474 OSString
* deviceTreeName
= NULL
; // do not release
476 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not free
477 char * booterDataPtr
= NULL
; // do not free
478 OSData
* booterData
= NULL
; // must release
480 OSKext
* aKext
= NULL
; // must release
482 OSKextLog(/* kext */ NULL
,
483 kOSKextLogProgressLevel
|
484 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
485 "Reading startup extensions/mkexts from booter memory.");
487 booterMemoryMap
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
489 if (!booterMemoryMap
) {
490 OSKextLog(/* kext */ NULL
,
491 kOSKextLogErrorLevel
|
492 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
,
493 "Can't read booter memory map.");
497 propertyDict
= booterMemoryMap
->dictionaryWithProperties();
499 OSKextLog(/* kext */ NULL
,
500 kOSKextLogErrorLevel
|
501 kOSKextLogDirectoryScanFlag
,
502 "Can't get property dictionary from memory map.");
506 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
508 OSKextLog(/* kext */ NULL
,
509 kOSKextLogErrorLevel
|
510 kOSKextLogGeneralFlag
,
511 "Can't allocate iterator for driver images.");
515 /* Create dictionary of excluded kexts
517 OSKext::createExcludeListFromBooterData(propertyDict
, keyIterator
);
518 keyIterator
->reset();
520 while ( ( deviceTreeName
=
521 OSDynamicCast(OSString
, keyIterator
->getNextObject() ))) {
523 boolean_t isMkext
= FALSE
;
524 const char * devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
525 OSData
* deviceTreeEntry
= OSDynamicCast(OSData
,
526 propertyDict
->getObject(deviceTreeName
));
528 /* Clear out the booterData from the prior iteration.
530 OSSafeReleaseNULL(booterData
);
532 /* If there is no entry for the name, we can't do much with it. */
533 if (!deviceTreeEntry
) {
537 /* Make sure it is either a kext or an mkext */
538 if (!strncmp(devTreeNameCString
, BOOTER_KEXT_PREFIX
,
539 CONST_STRLEN(BOOTER_KEXT_PREFIX
))) {
543 } else if (!strncmp(devTreeNameCString
, BOOTER_MKEXT_PREFIX
,
544 CONST_STRLEN(BOOTER_MKEXT_PREFIX
))) {
552 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
553 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
554 if (!deviceTreeBuffer
) {
555 /* We can't get to the data, so we can't do anything,
556 * not even free it from physical memory (if it's there).
558 OSKextLog(/* kext */ NULL
,
559 kOSKextLogErrorLevel
|
560 kOSKextLogDirectoryScanFlag
,
561 "Device tree entry %s has NULL pointer.",
563 goto finish
; // xxx - continue, panic?
566 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
567 if (!booterDataPtr
) {
568 OSKextLog(/* kext */ NULL
,
569 kOSKextLogErrorLevel
|
570 kOSKextLogDirectoryScanFlag
,
571 "Can't get virtual address for device tree mkext entry %s.",
576 /* Wrap the booter data buffer in an OSData and set a dealloc function
577 * so it will take care of the physical memory when freed. Kexts will
578 * retain the booterData for as long as they need it. Remove the entry
579 * from the booter memory map after this is done.
581 booterData
= OSData::withBytesNoCopy(booterDataPtr
,
582 deviceTreeBuffer
->length
);
584 OSKextLog(/* kext */ NULL
,
585 kOSKextLogErrorLevel
|
586 kOSKextLogGeneralFlag
,
587 "Error - Can't allocate OSData wrapper for device tree entry %s.",
591 booterData
->setDeallocFunction(osdata_phys_free
);
594 readMkextExtensions(deviceTreeName
, booterData
);
596 /* Create the kext for the entry, then release it, because the
597 * kext system keeps them around until explicitly removed.
598 * Any creation/registration failures are already logged for us.
600 OSKext
* newKext
= OSKext::withBooterData(deviceTreeName
, booterData
);
601 OSSafeRelease(newKext
);
604 booterMemoryMap
->removeProperty(deviceTreeName
);
606 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
610 OSSafeRelease(booterMemoryMap
);
611 OSSafeRelease(propertyDict
);
612 OSSafeRelease(keyIterator
);
613 OSSafeRelease(booterData
);
614 OSSafeRelease(aKext
);
618 /*********************************************************************
619 *********************************************************************/
621 KLDBootstrap::readMkextExtensions(
622 OSString
* deviceTreeName
,
625 OSReturn result
= kOSReturnError
;
628 IORegistryEntry
* registryRoot
= NULL
; // do not release
629 OSData
* checksumObj
= NULL
; // must release
631 OSKextLog(/* kext */ NULL
,
632 kOSKextLogStepLevel
|
633 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
634 "Reading startup mkext archive from device tree entry %s.",
635 deviceTreeName
->getCStringNoCopy());
637 /* If we successfully read the archive,
638 * then save the mkext's checksum in the IORegistry.
639 * assumes we'll only ever have one mkext to boot
641 result
= OSKext::readMkextArchive(booterData
, &checksum
);
642 if (result
== kOSReturnSuccess
) {
644 OSKextLog(/* kext */ NULL
,
645 kOSKextLogProgressLevel
|
646 kOSKextLogArchiveFlag
,
647 "Startup mkext archive has checksum 0x%x.", (int)checksum
);
649 registryRoot
= IORegistryEntry::getRegistryRoot();
650 assert(registryRoot
);
651 checksumObj
= OSData::withBytes((void *)&checksum
, sizeof(checksum
));
654 registryRoot
->setProperty(kOSStartupMkextCRC
, checksumObj
);
661 /*********************************************************************
662 *********************************************************************/
663 #define COM_APPLE "com.apple."
666 KLDBootstrap::loadSecurityExtensions(void)
668 OSDictionary
* extensionsDict
= NULL
; // must release
669 OSCollectionIterator
* keyIterator
= NULL
; // must release
670 OSString
* bundleID
= NULL
; // don't release
671 OSKext
* theKext
= NULL
; // don't release
672 OSBoolean
* isSecurityKext
= NULL
; // don't release
674 OSKextLog(/* kext */ NULL
,
675 kOSKextLogStepLevel
|
677 "Loading security extensions.");
679 extensionsDict
= OSKext::copyKexts();
680 if (!extensionsDict
) {
684 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
686 OSKextLog(/* kext */ NULL
,
687 kOSKextLogErrorLevel
|
688 kOSKextLogGeneralFlag
,
689 "Failed to allocate iterator for security extensions.");
693 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
695 const char * bundle_id
= bundleID
->getCStringNoCopy();
697 /* Skip extensions whose bundle IDs don't start with "com.apple.".
700 (strncmp(bundle_id
, COM_APPLE
, CONST_STRLEN(COM_APPLE
)) != 0)) {
705 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
710 isSecurityKext
= OSDynamicCast(OSBoolean
,
711 theKext
->getPropertyForHostArch(kAppleSecurityExtensionKey
));
712 if (isSecurityKext
&& isSecurityKext
->isTrue()) {
713 OSKextLog(/* kext */ NULL
,
714 kOSKextLogStepLevel
|
716 "Loading security extension %s.", bundleID
->getCStringNoCopy());
717 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
718 /* allowDefer */ false);
723 OSSafeRelease(keyIterator
);
724 OSSafeRelease(extensionsDict
);
729 /*********************************************************************
730 * We used to require that all listed kernel components load, but
731 * nowadays we can get them from userland so we only try to load the
732 * ones we have. If an error occurs later, such is life.
734 * Note that we look the kexts up first, so we can avoid spurious
735 * (in this context, anyhow) log messages about kexts not being found.
737 * xxx - do we even need to do this any more? Check if the kernel
738 * xxx - compoonents just load in the regular paths
739 *********************************************************************/
741 KLDBootstrap::loadKernelComponentKexts(void)
743 OSReturn result
= kOSReturnSuccess
; // optimistic
744 OSKext
* theKext
= NULL
; // must release
745 const char ** kextIDPtr
= NULL
; // do not release
747 for (kextIDPtr
= &sKernelComponentNames
[0]; *kextIDPtr
; kextIDPtr
++) {
749 OSSafeReleaseNULL(theKext
);
750 theKext
= OSKext::lookupKextWithIdentifier(*kextIDPtr
);
753 if (kOSReturnSuccess
!= OSKext::loadKextWithIdentifier(
754 *kextIDPtr
, /* allowDefer */ false)) {
756 // xxx - check KextBookkeeping, might be redundant
757 OSKextLog(/* kext */ NULL
,
758 kOSKextLogErrorLevel
|
759 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
760 "Failed to initialize kernel component %s.", *kextIDPtr
);
761 result
= kOSReturnError
;
766 OSSafeRelease(theKext
);
770 /*********************************************************************
771 * Ensure that Kernel External Components are loaded early in boot,
772 * before other kext personalities get sent to the IOCatalogue. These
773 * kexts are treated specially because they may provide the implementation
774 * for kernel-vended KPI, so they must register themselves before
775 * general purpose IOKit probing begins.
776 *********************************************************************/
778 #define COM_APPLE_KEC "com.apple.kec."
781 KLDBootstrap::loadKernelExternalComponents(void)
783 OSDictionary
* extensionsDict
= NULL
; // must release
784 OSCollectionIterator
* keyIterator
= NULL
; // must release
785 OSString
* bundleID
= NULL
; // don't release
786 OSKext
* theKext
= NULL
; // don't release
787 OSBoolean
* isKernelExternalComponent
= NULL
; // don't release
789 OSKextLog(/* kext */ NULL
,
790 kOSKextLogStepLevel
|
792 "Loading Kernel External Components.");
794 extensionsDict
= OSKext::copyKexts();
795 if (!extensionsDict
) {
799 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
801 OSKextLog(/* kext */ NULL
,
802 kOSKextLogErrorLevel
|
803 kOSKextLogGeneralFlag
,
804 "Failed to allocate iterator for Kernel External Components.");
808 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
810 const char * bundle_id
= bundleID
->getCStringNoCopy();
812 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
815 (strncmp(bundle_id
, COM_APPLE_KEC
, CONST_STRLEN(COM_APPLE_KEC
)) != 0)) {
820 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
825 isKernelExternalComponent
= OSDynamicCast(OSBoolean
,
826 theKext
->getPropertyForHostArch(kAppleKernelExternalComponentKey
));
827 if (isKernelExternalComponent
&& isKernelExternalComponent
->isTrue()) {
828 OSKextLog(/* kext */ NULL
,
829 kOSKextLogStepLevel
|
831 "Loading kernel external component %s.", bundleID
->getCStringNoCopy());
832 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
833 /* allowDefer */ false);
838 OSSafeRelease(keyIterator
);
839 OSSafeRelease(extensionsDict
);
844 /*********************************************************************
845 *********************************************************************/
847 KLDBootstrap::readBuiltinPersonalities(void)
849 OSObject
* parsedXML
= NULL
; // must release
850 OSArray
* builtinExtensions
= NULL
; // do not release
851 OSArray
* allPersonalities
= NULL
; // must release
852 OSString
* errorString
= NULL
; // must release
853 kernel_section_t
* infosect
= NULL
; // do not free
854 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
855 unsigned int count
, i
;
857 OSKextLog(/* kext */ NULL
,
858 kOSKextLogStepLevel
|
860 "Reading built-in kernel personalities for I/O Kit drivers.");
862 /* Look in the __BUILTIN __info segment for an array of Info.plist
863 * entries. For each one, extract the personalities dictionary, add
864 * it to our array, then push them all (without matching) to
865 * the IOCatalogue. This can be used to augment the personalities
866 * in gIOKernelConfigTables, especially when linking entire kexts into
867 * the mach_kernel image.
869 infosect
= getsectbyname("__BUILTIN", "__info");
875 parsedXML
= OSUnserializeXML((const char *) (uintptr_t)infosect
->addr
,
878 builtinExtensions
= OSDynamicCast(OSArray
, parsedXML
);
880 if (!builtinExtensions
) {
881 const char * errorCString
= "(unknown error)";
883 if (errorString
&& errorString
->getCStringNoCopy()) {
884 errorCString
= errorString
->getCStringNoCopy();
885 } else if (parsedXML
) {
886 errorCString
= "not an array";
888 OSKextLog(/* kext */ NULL
,
889 kOSKextLogErrorLevel
|
891 "Error unserializing built-in personalities: %s.", errorCString
);
895 // estimate 3 personalities per Info.plist/kext
896 count
= builtinExtensions
->getCount();
897 allPersonalities
= OSArray::withCapacity(count
* 3);
899 for (i
= 0; i
< count
; i
++) {
900 OSDictionary
* infoDict
= NULL
; // do not release
901 OSString
* moduleName
= NULL
; // do not release
902 OSDictionary
* personalities
; // do not release
903 OSString
* personalityName
; // do not release
905 OSSafeReleaseNULL(personalitiesIterator
);
907 infoDict
= OSDynamicCast(OSDictionary
,
908 builtinExtensions
->getObject(i
));
913 moduleName
= OSDynamicCast(OSString
,
914 infoDict
->getObject(kCFBundleIdentifierKey
));
919 OSKextLog(/* kext */ NULL
,
920 kOSKextLogStepLevel
|
922 "Adding personalities for built-in driver %s:",
923 moduleName
->getCStringNoCopy());
925 personalities
= OSDynamicCast(OSDictionary
,
926 infoDict
->getObject("IOKitPersonalities"));
927 if (!personalities
) {
931 personalitiesIterator
= OSCollectionIterator::withCollection(personalities
);
932 if (!personalitiesIterator
) {
933 continue; // xxx - well really, what can we do? should we panic?
936 while ((personalityName
= OSDynamicCast(OSString
,
937 personalitiesIterator
->getNextObject()))) {
939 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
940 personalities
->getObject(personalityName
));
942 OSKextLog(/* kext */ NULL
,
943 kOSKextLogDetailLevel
|
945 "Adding built-in driver personality %s.",
946 personalityName
->getCStringNoCopy());
948 if (personality
&& !personality
->getObject(kCFBundleIdentifierKey
)) {
949 personality
->setObject(kCFBundleIdentifierKey
, moduleName
);
951 allPersonalities
->setObject(personality
);
955 gIOCatalogue
->addDrivers(allPersonalities
, false);
958 OSSafeRelease(parsedXML
);
959 OSSafeRelease(allPersonalities
);
960 OSSafeRelease(errorString
);
961 OSSafeRelease(personalitiesIterator
);
966 #pragma mark Bootstrap Functions
968 /*********************************************************************
969 * Bootstrap Functions
970 *********************************************************************/
971 static void bootstrapRecordStartupExtensions(void)
973 sBootstrapObject
.readStartupExtensions();
977 static void bootstrapLoadSecurityExtensions(void)
979 sBootstrapObject
.loadSecurityExtensions();