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>
35 #include <libkern/version.h>
36 #include <libkern/c++/OSContainers.h>
37 #include <libkern/OSKextLibPrivate.h>
38 #include <libkern/c++/OSKext.h>
39 #include <IOKit/IOLib.h>
40 #include <IOKit/IOService.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOCatalogue.h>
45 #define KASLR_KEXT_DEBUG 0
49 #pragma mark Bootstrap Declarations
51 /*********************************************************************
52 * Bootstrap Declarations
54 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
55 * code from other parts of the kernel, so function symbols are not
56 * exported; rather pointers to those functions are exported.
58 * xxx - need to think about locking for handling the 'weak' refs.
59 * xxx - do export a non-KLD function that says you've called a
60 * xxx - bootstrap function that has been removed.
62 * ALL call-ins to this segment of the kernel must be done through
63 * exported pointers. The symbols themselves are private and not to
65 *********************************************************************/
67 extern void (*record_startup_extensions_function
)(void);
68 extern void (*load_security_extensions_function
)(void);
71 static void bootstrapRecordStartupExtensions(void);
72 static void bootstrapLoadSecurityExtensions(void);
76 extern "C" bool IORamDiskBSDRoot(void);
82 /*********************************************************************
84 *********************************************************************/
85 #define CONST_STRLEN(str) (sizeof(str) - 1)
88 #pragma mark Kernel Component Kext Identifiers
90 /*********************************************************************
91 * Kernel Component Kext Identifiers
93 * We could have each kernel resource kext automatically "load" as
94 * it's created, but it's nicer to have them listed in kextstat in
95 * the order of this list. We'll walk through this after setting up
96 * all the boot kexts and have them load up.
97 *********************************************************************/
98 static const char * sKernelComponentNames
[] = {
99 // The kexts for these IDs must have a version matching 'osrelease'.
102 "com.apple.kpi.dsep",
103 "com.apple.kpi.iokit",
104 "com.apple.kpi.libkern",
105 "com.apple.kpi.mach",
106 "com.apple.kpi.private",
107 "com.apple.kpi.unsupported",
108 "com.apple.iokit.IONVRAMFamily",
109 "com.apple.driver.AppleNMI",
110 "com.apple.iokit.IOSystemManagementFamily",
111 "com.apple.iokit.ApplePlatformFamily",
115 static int __whereIsAddr(vm_offset_t theAddr
, unsigned long * segSizes
, vm_offset_t
*segAddrs
, int segCount
);
117 #define PLK_SEGMENTS 11
119 static const char * plk_segNames
[] = {
135 #pragma mark KLDBootstrap Class
137 /*********************************************************************
140 * We use a C++ class here so that it can be a friend of OSKext and
141 * get at private stuff. We can't hide the class itself, but we can
142 * hide the instance through which we invoke the functions.
143 *********************************************************************/
145 friend void bootstrapRecordStartupExtensions(void);
146 friend void bootstrapLoadSecurityExtensions(void);
149 void readStartupExtensions(void);
151 void readPrelinkedExtensions(
152 kernel_section_t
* prelinkInfoSect
);
153 void readBooterExtensions(void);
155 OSReturn
loadKernelComponentKexts(void);
156 void loadKernelExternalComponents(void);
157 void readBuiltinPersonalities(void);
159 void loadSecurityExtensions(void);
166 static KLDBootstrap sBootstrapObject
;
168 /*********************************************************************
169 * Set the function pointers for the entry points into the bootstrap
170 * segment upon C++ static constructor invocation.
171 *********************************************************************/
172 KLDBootstrap::KLDBootstrap(void)
174 if (this != &sBootstrapObject
) {
175 panic("Attempt to access bootstrap segment.");
177 record_startup_extensions_function
= &bootstrapRecordStartupExtensions
;
178 load_security_extensions_function
= &bootstrapLoadSecurityExtensions
;
181 /*********************************************************************
182 * Clear the function pointers for the entry points into the bootstrap
183 * segment upon C++ static destructor invocation.
184 *********************************************************************/
185 KLDBootstrap::~KLDBootstrap(void)
187 if (this != &sBootstrapObject
) {
188 panic("Attempt to access bootstrap segment.");
192 record_startup_extensions_function
= 0;
193 load_security_extensions_function
= 0;
196 /*********************************************************************
197 *********************************************************************/
199 KLDBootstrap::readStartupExtensions(void)
201 kernel_section_t
* prelinkInfoSect
= NULL
; // do not free
203 OSKextLog(/* kext */ NULL
,
204 kOSKextLogProgressLevel
|
205 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
|
206 kOSKextLogKextBookkeepingFlag
,
207 "Reading startup extensions.");
209 /* If the prelink info segment has a nonzero size, we are prelinked
210 * and won't have any individual kexts or mkexts to read.
211 * Otherwise, we need to read kexts or the mkext from what the booter
214 prelinkInfoSect
= getsectbyname(kPrelinkInfoSegment
, kPrelinkInfoSection
);
215 if (prelinkInfoSect
->size
) {
216 readPrelinkedExtensions(prelinkInfoSect
);
218 readBooterExtensions();
221 loadKernelComponentKexts();
222 loadKernelExternalComponents();
223 readBuiltinPersonalities();
224 OSKext::sendAllKextPersonalitiesToCatalog();
229 typedef struct kaslrPackedOffsets
{
230 uint32_t count
; /* number of offsets */
231 uint32_t offsetsArray
[]; /* offsets to slide */
232 } kaslrPackedOffsets
;
234 /*********************************************************************
235 *********************************************************************/
237 KLDBootstrap::readPrelinkedExtensions(
238 kernel_section_t
* prelinkInfoSect
)
240 OSArray
* infoDictArray
= NULL
; // do not release
241 OSObject
* parsedXML
= NULL
; // must release
242 OSDictionary
* prelinkInfoDict
= NULL
; // do not release
243 OSString
* errorString
= NULL
; // must release
244 OSKext
* theKernel
= NULL
; // must release
246 kernel_segment_command_t
* prelinkTextSegment
= NULL
; // see code
247 kernel_segment_command_t
* prelinkInfoSegment
= NULL
; // see code
249 /* We make some copies of data, but if anything fails we're basically
250 * going to fail the boot, so these won't be cleaned up on error.
252 void * prelinkData
= NULL
; // see code
253 vm_size_t prelinkLength
= 0;
256 OSDictionary
* infoDict
= NULL
; // do not release
258 IORegistryEntry
* registryRoot
= NULL
; // do not release
259 OSNumber
* prelinkCountObj
= NULL
; // must release
264 bool developerDevice
;
267 OSData
* kaslrOffsets
= NULL
;
268 unsigned long plk_segSizes
[PLK_SEGMENTS
];
269 vm_offset_t plk_segAddrs
[PLK_SEGMENTS
];
271 OSKextLog(/* kext */ NULL
,
272 kOSKextLogProgressLevel
|
273 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
274 "Starting from prelinked kernel.");
276 prelinkTextSegment
= getsegbyname(kPrelinkTextSegment
);
277 if (!prelinkTextSegment
) {
278 OSKextLog(/* kext */ NULL
,
279 kOSKextLogErrorLevel
|
280 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
281 "Can't find prelinked kexts' text segment.");
286 unsigned long scratchSize
;
287 vm_offset_t scratchAddr
;
289 IOLog("kaslr: prelinked kernel address info: \n");
291 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__TEXT", &scratchSize
);
292 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
293 (unsigned long)scratchAddr
,
294 (unsigned long)(scratchAddr
+ scratchSize
),
297 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__DATA", &scratchSize
);
298 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
299 (unsigned long)scratchAddr
,
300 (unsigned long)(scratchAddr
+ scratchSize
),
303 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__LINKEDIT", &scratchSize
);
304 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
305 (unsigned long)scratchAddr
,
306 (unsigned long)(scratchAddr
+ scratchSize
),
309 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__KLD", &scratchSize
);
310 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
311 (unsigned long)scratchAddr
,
312 (unsigned long)(scratchAddr
+ scratchSize
),
315 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__PRELINK_TEXT", &scratchSize
);
316 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
317 (unsigned long)scratchAddr
,
318 (unsigned long)(scratchAddr
+ scratchSize
),
321 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__PRELINK_INFO", &scratchSize
);
322 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
323 (unsigned long)scratchAddr
,
324 (unsigned long)(scratchAddr
+ scratchSize
),
328 prelinkData
= (void *) prelinkTextSegment
->vmaddr
;
329 prelinkLength
= prelinkTextSegment
->vmsize
;
331 /* build arrays of plk info for later use */
332 const char ** segNamePtr
;
334 for (segNamePtr
= &plk_segNames
[0], i
= 0; *segNamePtr
&& i
< PLK_SEGMENTS
; segNamePtr
++, i
++) {
336 plk_segAddrs
[i
] = (vm_offset_t
)getsegdatafromheader(&_mh_execute_header
, *segNamePtr
, &plk_segSizes
[i
]);
340 /* Unserialize the info dictionary from the prelink info section.
342 parsedXML
= OSUnserializeXML((const char *)prelinkInfoSect
->addr
,
345 prelinkInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
347 if (!prelinkInfoDict
) {
348 const char * errorCString
= "(unknown error)";
350 if (errorString
&& errorString
->getCStringNoCopy()) {
351 errorCString
= errorString
->getCStringNoCopy();
352 } else if (parsedXML
) {
353 errorCString
= "not a dictionary";
355 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
356 "Error unserializing prelink plist: %s.", errorCString
);
361 /* Check if we should keep developer kexts around.
362 * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
364 developerDevice
= true;
365 PE_parse_boot_argn("developer", &developerDevice
, sizeof(developerDevice
));
367 ramDiskBoot
= IORamDiskBSDRoot();
368 #endif /* NO_KEXTD */
371 infoDictArray
= OSDynamicCast(OSArray
,
372 prelinkInfoDict
->getObject(kPrelinkInfoDictionaryKey
));
373 if (!infoDictArray
) {
374 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
375 "The prelinked kernel has no kext info dictionaries");
379 /* kaslrOffsets are available use them to slide local relocations */
380 kaslrOffsets
= OSDynamicCast(OSData
,
381 prelinkInfoDict
->getObject(kPrelinkLinkKASLROffsetsKey
));
383 /* Create dictionary of excluded kexts
385 OSKext::createExcludeListFromPrelinkInfo(infoDictArray
);
386 /* Create OSKext objects for each info dictionary.
388 for (i
= 0; i
< infoDictArray
->getCount(); ++i
) {
389 infoDict
= OSDynamicCast(OSDictionary
, infoDictArray
->getObject(i
));
391 OSKextLog(/* kext */ NULL
,
392 kOSKextLogErrorLevel
|
393 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
394 "Can't find info dictionary for prelinked kext #%d.", i
);
401 /* If we're not on a developer device, skip and free developer kexts.
403 if (developerDevice
== false) {
404 OSBoolean
*devOnlyBool
= OSDynamicCast(OSBoolean
,
405 infoDict
->getObject(kOSBundleDeveloperOnlyKey
));
406 if (devOnlyBool
== kOSBooleanTrue
) {
411 /* Skip and free kexts that are only needed when booted from a ram disk.
413 if (ramDiskBoot
== false) {
414 OSBoolean
*ramDiskOnlyBool
= OSDynamicCast(OSBoolean
,
415 infoDict
->getObject(kOSBundleRamDiskOnlyKey
));
416 if (ramDiskOnlyBool
== kOSBooleanTrue
) {
421 if (dontLoad
== true) {
422 OSString
*bundleID
= OSDynamicCast(OSString
,
423 infoDict
->getObject(kCFBundleIdentifierKey
));
425 OSKextLog(NULL
, kOSKextLogWarningLevel
| kOSKextLogGeneralFlag
,
426 "Kext %s not loading.", bundleID
->getCStringNoCopy());
429 OSNumber
*addressNum
= OSDynamicCast(OSNumber
,
430 infoDict
->getObject(kPrelinkExecutableLoadKey
));
431 OSNumber
*lengthNum
= OSDynamicCast(OSNumber
,
432 infoDict
->getObject(kPrelinkExecutableSizeKey
));
433 if (addressNum
&& lengthNum
) {
434 #error Pick the right way to free prelinked data on this arch
437 infoDictArray
->removeObject(i
--);
440 #endif /* NO_KEXTD */
442 /* Create the kext for the entry, then release it, because the
443 * kext system keeps them around until explicitly removed.
444 * Any creation/registration failures are already logged for us.
446 OSKext
* newKext
= OSKext::withPrelinkedInfoDict(infoDict
, (kaslrOffsets
? TRUE
: FALSE
));
447 OSSafeReleaseNULL(newKext
);
450 /* slide kxld relocations */
451 if (kaslrOffsets
&& vm_kernel_slide
> 0) {
452 int slidKextAddrCount
= 0;
453 int badSlideAddr
= 0;
454 int badSlideTarget
= 0;
456 kaslrPackedOffsets
* myOffsets
= NULL
;
457 myOffsets
= (kaslrPackedOffsets
*) kaslrOffsets
->getBytesNoCopy();
459 for (uint32_t j
= 0; j
< myOffsets
->count
; j
++) {
461 uint64_t slideOffset
= (uint64_t) myOffsets
->offsetsArray
[j
];
462 uintptr_t * slideAddr
= (uintptr_t *) ((uint64_t)prelinkData
+ slideOffset
);
463 int slideAddrSegIndex
= -1;
464 int addrToSlideSegIndex
= -1;
466 slideAddrSegIndex
= __whereIsAddr( (vm_offset_t
)slideAddr
, &plk_segSizes
[0], &plk_segAddrs
[0], PLK_SEGMENTS
);
467 if (slideAddrSegIndex
>= 0) {
468 addrToSlideSegIndex
= __whereIsAddr( (vm_offset_t
)(*slideAddr
+ vm_kernel_slide
), &plk_segSizes
[0], &plk_segAddrs
[0], PLK_SEGMENTS
);
469 if (addrToSlideSegIndex
< 0) {
480 *(slideAddr
) += vm_kernel_slide
;
483 /* All kexts are now slid, set VM protections for them */
484 OSKext::setAllVMAttributes();
487 /* Store the number of prelinked kexts in the registry so we can tell
488 * when the system has been started from a prelinked kernel.
490 registryRoot
= IORegistryEntry::getRegistryRoot();
491 assert(registryRoot
);
493 prelinkCountObj
= OSNumber::withNumber(
494 (unsigned long long)infoDictArray
->getCount(),
495 8 * sizeof(uint32_t));
496 assert(prelinkCountObj
);
497 if (prelinkCountObj
) {
498 registryRoot
->setProperty(kOSPrelinkKextCountKey
, prelinkCountObj
);
501 OSKextLog(/* kext */ NULL
,
502 kOSKextLogProgressLevel
|
503 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
504 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
505 "%u prelinked kexts",
506 infoDictArray
->getCount());
508 #if CONFIG_KEXT_BASEMENT
509 /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
510 * special VM region during OSKext init time, so we can free the whole
513 ml_static_mfree((vm_offset_t
) prelinkData
, prelinkLength
);
514 #endif /* __x86_64__ */
516 /* Free the prelink info segment, we're done with it.
518 prelinkInfoSegment
= getsegbyname(kPrelinkInfoSegment
);
519 if (prelinkInfoSegment
) {
520 ml_static_mfree((vm_offset_t
)prelinkInfoSegment
->vmaddr
,
521 (vm_size_t
)prelinkInfoSegment
->vmsize
);
525 OSSafeReleaseNULL(errorString
);
526 OSSafeReleaseNULL(parsedXML
);
527 OSSafeReleaseNULL(theKernel
);
528 OSSafeReleaseNULL(prelinkCountObj
);
532 static int __whereIsAddr(vm_offset_t theAddr
, unsigned long * segSizes
, vm_offset_t
*segAddrs
, int segCount
)
536 for (i
= 0; i
< segCount
; i
++) {
537 vm_offset_t myAddr
= *(segAddrs
+ i
);
538 unsigned long mySize
= *(segSizes
+ i
);
540 if (theAddr
>= myAddr
&& theAddr
< (myAddr
+ mySize
)) {
549 /*********************************************************************
550 *********************************************************************/
551 #define BOOTER_KEXT_PREFIX "Driver-"
553 typedef struct _DeviceTreeBuffer
{
559 KLDBootstrap::readBooterExtensions(void)
561 IORegistryEntry
* booterMemoryMap
= NULL
; // must release
562 OSDictionary
* propertyDict
= NULL
; // must release
563 OSCollectionIterator
* keyIterator
= NULL
; // must release
564 OSString
* deviceTreeName
= NULL
; // do not release
566 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not free
567 char * booterDataPtr
= NULL
; // do not free
568 OSData
* booterData
= NULL
; // must release
570 OSKext
* aKext
= NULL
; // must release
572 OSKextLog(/* kext */ NULL
,
573 kOSKextLogProgressLevel
|
574 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
575 "Reading startup extensions from booter memory.");
577 booterMemoryMap
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
579 if (!booterMemoryMap
) {
580 OSKextLog(/* kext */ NULL
,
581 kOSKextLogErrorLevel
|
582 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
,
583 "Can't read booter memory map.");
587 propertyDict
= booterMemoryMap
->dictionaryWithProperties();
589 OSKextLog(/* kext */ NULL
,
590 kOSKextLogErrorLevel
|
591 kOSKextLogDirectoryScanFlag
,
592 "Can't get property dictionary from memory map.");
596 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
598 OSKextLog(/* kext */ NULL
,
599 kOSKextLogErrorLevel
|
600 kOSKextLogGeneralFlag
,
601 "Can't allocate iterator for driver images.");
605 /* Create dictionary of excluded kexts
607 OSKext::createExcludeListFromBooterData(propertyDict
, keyIterator
);
608 keyIterator
->reset();
610 while ( ( deviceTreeName
=
611 OSDynamicCast(OSString
, keyIterator
->getNextObject() ))) {
613 const char * devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
614 OSData
* deviceTreeEntry
= OSDynamicCast(OSData
,
615 propertyDict
->getObject(deviceTreeName
));
617 /* Clear out the booterData from the prior iteration.
619 OSSafeReleaseNULL(booterData
);
621 /* If there is no entry for the name, we can't do much with it. */
622 if (!deviceTreeEntry
) {
626 /* Make sure it is a kext */
627 if (strncmp(devTreeNameCString
,
629 CONST_STRLEN(BOOTER_KEXT_PREFIX
))) {
633 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
634 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
635 if (!deviceTreeBuffer
) {
636 /* We can't get to the data, so we can't do anything,
637 * not even free it from physical memory (if it's there).
639 OSKextLog(/* kext */ NULL
,
640 kOSKextLogErrorLevel
|
641 kOSKextLogDirectoryScanFlag
,
642 "Device tree entry %s has NULL pointer.",
644 goto finish
; // xxx - continue, panic?
647 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
648 if (!booterDataPtr
) {
649 OSKextLog(/* kext */ NULL
,
650 kOSKextLogErrorLevel
|
651 kOSKextLogDirectoryScanFlag
,
652 "Can't get virtual address for device tree entry %s.",
657 /* Wrap the booter data buffer in an OSData and set a dealloc function
658 * so it will take care of the physical memory when freed. Kexts will
659 * retain the booterData for as long as they need it. Remove the entry
660 * from the booter memory map after this is done.
662 booterData
= OSData::withBytesNoCopy(booterDataPtr
,
663 deviceTreeBuffer
->length
);
665 OSKextLog(/* kext */ NULL
,
666 kOSKextLogErrorLevel
|
667 kOSKextLogGeneralFlag
,
668 "Error - Can't allocate OSData wrapper for device tree entry %s.",
672 booterData
->setDeallocFunction(osdata_phys_free
);
674 /* Create the kext for the entry, then release it, because the
675 * kext system keeps them around until explicitly removed.
676 * Any creation/registration failures are already logged for us.
678 OSKext
* newKext
= OSKext::withBooterData(deviceTreeName
, booterData
);
679 OSSafeReleaseNULL(newKext
);
681 booterMemoryMap
->removeProperty(deviceTreeName
);
683 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
687 OSSafeReleaseNULL(booterMemoryMap
);
688 OSSafeReleaseNULL(propertyDict
);
689 OSSafeReleaseNULL(keyIterator
);
690 OSSafeReleaseNULL(booterData
);
691 OSSafeReleaseNULL(aKext
);
695 /*********************************************************************
696 *********************************************************************/
697 #define COM_APPLE "com.apple."
700 KLDBootstrap::loadSecurityExtensions(void)
702 OSDictionary
* extensionsDict
= NULL
; // must release
703 OSCollectionIterator
* keyIterator
= NULL
; // must release
704 OSString
* bundleID
= NULL
; // don't release
705 OSKext
* theKext
= NULL
; // don't release
706 OSBoolean
* isSecurityKext
= NULL
; // don't release
708 OSKextLog(/* kext */ NULL
,
709 kOSKextLogStepLevel
|
711 "Loading security extensions.");
713 extensionsDict
= OSKext::copyKexts();
714 if (!extensionsDict
) {
718 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
720 OSKextLog(/* kext */ NULL
,
721 kOSKextLogErrorLevel
|
722 kOSKextLogGeneralFlag
,
723 "Failed to allocate iterator for security extensions.");
727 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
729 const char * bundle_id
= bundleID
->getCStringNoCopy();
731 /* Skip extensions whose bundle IDs don't start with "com.apple.".
734 (strncmp(bundle_id
, COM_APPLE
, CONST_STRLEN(COM_APPLE
)) != 0)) {
739 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
744 isSecurityKext
= OSDynamicCast(OSBoolean
,
745 theKext
->getPropertyForHostArch(kAppleSecurityExtensionKey
));
746 if (isSecurityKext
&& isSecurityKext
->isTrue()) {
747 OSKextLog(/* kext */ NULL
,
748 kOSKextLogStepLevel
|
750 "Loading security extension %s.", bundleID
->getCStringNoCopy());
751 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
752 /* allowDefer */ false);
757 OSSafeReleaseNULL(keyIterator
);
758 OSSafeReleaseNULL(extensionsDict
);
763 /*********************************************************************
764 * We used to require that all listed kernel components load, but
765 * nowadays we can get them from userland so we only try to load the
766 * ones we have. If an error occurs later, such is life.
768 * Note that we look the kexts up first, so we can avoid spurious
769 * (in this context, anyhow) log messages about kexts not being found.
771 * xxx - do we even need to do this any more? Check if the kernel
772 * xxx - compoonents just load in the regular paths
773 *********************************************************************/
775 KLDBootstrap::loadKernelComponentKexts(void)
777 OSReturn result
= kOSReturnSuccess
; // optimistic
778 OSKext
* theKext
= NULL
; // must release
779 const char ** kextIDPtr
= NULL
; // do not release
781 for (kextIDPtr
= &sKernelComponentNames
[0]; *kextIDPtr
; kextIDPtr
++) {
783 OSSafeReleaseNULL(theKext
);
784 theKext
= OSKext::lookupKextWithIdentifier(*kextIDPtr
);
787 if (kOSReturnSuccess
!= OSKext::loadKextWithIdentifier(
788 *kextIDPtr
, /* allowDefer */ false)) {
790 // xxx - check KextBookkeeping, might be redundant
791 OSKextLog(/* kext */ NULL
,
792 kOSKextLogErrorLevel
|
793 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
794 "Failed to initialize kernel component %s.", *kextIDPtr
);
795 result
= kOSReturnError
;
800 OSSafeReleaseNULL(theKext
);
804 /*********************************************************************
805 * Ensure that Kernel External Components are loaded early in boot,
806 * before other kext personalities get sent to the IOCatalogue. These
807 * kexts are treated specially because they may provide the implementation
808 * for kernel-vended KPI, so they must register themselves before
809 * general purpose IOKit probing begins.
810 *********************************************************************/
812 #define COM_APPLE_KEC "com.apple.kec."
815 KLDBootstrap::loadKernelExternalComponents(void)
817 OSDictionary
* extensionsDict
= NULL
; // must release
818 OSCollectionIterator
* keyIterator
= NULL
; // must release
819 OSString
* bundleID
= NULL
; // don't release
820 OSKext
* theKext
= NULL
; // don't release
821 OSBoolean
* isKernelExternalComponent
= NULL
; // don't release
823 OSKextLog(/* kext */ NULL
,
824 kOSKextLogStepLevel
|
826 "Loading Kernel External Components.");
828 extensionsDict
= OSKext::copyKexts();
829 if (!extensionsDict
) {
833 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
835 OSKextLog(/* kext */ NULL
,
836 kOSKextLogErrorLevel
|
837 kOSKextLogGeneralFlag
,
838 "Failed to allocate iterator for Kernel External Components.");
842 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
844 const char * bundle_id
= bundleID
->getCStringNoCopy();
846 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
849 (strncmp(bundle_id
, COM_APPLE_KEC
, CONST_STRLEN(COM_APPLE_KEC
)) != 0)) {
854 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
859 isKernelExternalComponent
= OSDynamicCast(OSBoolean
,
860 theKext
->getPropertyForHostArch(kAppleKernelExternalComponentKey
));
861 if (isKernelExternalComponent
&& isKernelExternalComponent
->isTrue()) {
862 OSKextLog(/* kext */ NULL
,
863 kOSKextLogStepLevel
|
865 "Loading kernel external component %s.", bundleID
->getCStringNoCopy());
866 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
867 /* allowDefer */ false);
872 OSSafeReleaseNULL(keyIterator
);
873 OSSafeReleaseNULL(extensionsDict
);
878 /*********************************************************************
879 *********************************************************************/
881 KLDBootstrap::readBuiltinPersonalities(void)
883 OSObject
* parsedXML
= NULL
; // must release
884 OSArray
* builtinExtensions
= NULL
; // do not release
885 OSArray
* allPersonalities
= NULL
; // must release
886 OSString
* errorString
= NULL
; // must release
887 kernel_section_t
* infosect
= NULL
; // do not free
888 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
889 unsigned int count
, i
;
891 OSKextLog(/* kext */ NULL
,
892 kOSKextLogStepLevel
|
894 "Reading built-in kernel personalities for I/O Kit drivers.");
896 /* Look in the __BUILTIN __info segment for an array of Info.plist
897 * entries. For each one, extract the personalities dictionary, add
898 * it to our array, then push them all (without matching) to
899 * the IOCatalogue. This can be used to augment the personalities
900 * in gIOKernelConfigTables, especially when linking entire kexts into
901 * the mach_kernel image.
903 infosect
= getsectbyname("__BUILTIN", "__info");
909 parsedXML
= OSUnserializeXML((const char *) (uintptr_t)infosect
->addr
,
912 builtinExtensions
= OSDynamicCast(OSArray
, parsedXML
);
914 if (!builtinExtensions
) {
915 const char * errorCString
= "(unknown error)";
917 if (errorString
&& errorString
->getCStringNoCopy()) {
918 errorCString
= errorString
->getCStringNoCopy();
919 } else if (parsedXML
) {
920 errorCString
= "not an array";
922 OSKextLog(/* kext */ NULL
,
923 kOSKextLogErrorLevel
|
925 "Error unserializing built-in personalities: %s.", errorCString
);
929 // estimate 3 personalities per Info.plist/kext
930 count
= builtinExtensions
->getCount();
931 allPersonalities
= OSArray::withCapacity(count
* 3);
933 for (i
= 0; i
< count
; i
++) {
934 OSDictionary
* infoDict
= NULL
; // do not release
935 OSString
* moduleName
= NULL
; // do not release
936 OSDictionary
* personalities
; // do not release
937 OSString
* personalityName
; // do not release
939 OSSafeReleaseNULL(personalitiesIterator
);
941 infoDict
= OSDynamicCast(OSDictionary
,
942 builtinExtensions
->getObject(i
));
947 moduleName
= OSDynamicCast(OSString
,
948 infoDict
->getObject(kCFBundleIdentifierKey
));
953 OSKextLog(/* kext */ NULL
,
954 kOSKextLogStepLevel
|
956 "Adding personalities for built-in driver %s:",
957 moduleName
->getCStringNoCopy());
959 personalities
= OSDynamicCast(OSDictionary
,
960 infoDict
->getObject("IOKitPersonalities"));
961 if (!personalities
) {
965 personalitiesIterator
= OSCollectionIterator::withCollection(personalities
);
966 if (!personalitiesIterator
) {
967 continue; // xxx - well really, what can we do? should we panic?
970 while ((personalityName
= OSDynamicCast(OSString
,
971 personalitiesIterator
->getNextObject()))) {
973 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
974 personalities
->getObject(personalityName
));
976 OSKextLog(/* kext */ NULL
,
977 kOSKextLogDetailLevel
|
979 "Adding built-in driver personality %s.",
980 personalityName
->getCStringNoCopy());
982 if (personality
&& !personality
->getObject(kCFBundleIdentifierKey
)) {
983 personality
->setObject(kCFBundleIdentifierKey
, moduleName
);
985 allPersonalities
->setObject(personality
);
989 gIOCatalogue
->addDrivers(allPersonalities
, false);
992 OSSafeReleaseNULL(parsedXML
);
993 OSSafeReleaseNULL(allPersonalities
);
994 OSSafeReleaseNULL(errorString
);
995 OSSafeReleaseNULL(personalitiesIterator
);
1000 #pragma mark Bootstrap Functions
1002 /*********************************************************************
1003 * Bootstrap Functions
1004 *********************************************************************/
1005 static void bootstrapRecordStartupExtensions(void)
1007 sBootstrapObject
.readStartupExtensions();
1011 static void bootstrapLoadSecurityExtensions(void)
1013 sBootstrapObject
.loadSecurityExtensions();