xref: /xnu-11215/libsa/bootstrap.cpp (revision a3bb9fcc)
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 }
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 __x86_64__
44 #define KASLR_KEXT_DEBUG 0
45 #endif
46 
47 #if PRAGMA_MARK
48 #pragma mark Bootstrap Declarations
49 #endif
50 /*********************************************************************
51 * Bootstrap Declarations
52 *
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.
56 *
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.
60 *
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
63 * be linked against.
64 *********************************************************************/
65 extern "C" {
66     extern void (*record_startup_extensions_function)(void);
67     extern void (*load_security_extensions_function)(void);
68 };
69 
70 static void bootstrapRecordStartupExtensions(void);
71 static void bootstrapLoadSecurityExtensions(void);
72 
73 
74 #if NO_KEXTD
75 extern "C" bool IORamDiskBSDRoot(void);
76 #endif
77 
78 #if PRAGMA_MARK
79 #pragma mark Macros
80 #endif
81 /*********************************************************************
82 * Macros
83 *********************************************************************/
84 #define CONST_STRLEN(str) (sizeof(str) - 1)
85 
86 #if PRAGMA_MARK
87 #pragma mark Kernel Component Kext Identifiers
88 #endif
89 /*********************************************************************
90 * Kernel Component Kext Identifiers
91 *
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'.
99    "com.apple.kernel",
100    "com.apple.kpi.bsd",
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",
111    NULL
112 };
113 
114 #if PRAGMA_MARK
115 #pragma mark KLDBootstrap Class
116 #endif
117 /*********************************************************************
118 * KLDBootstrap Class
119 *
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 *********************************************************************/
124 class KLDBootstrap {
125     friend void bootstrapRecordStartupExtensions(void);
126     friend void bootstrapLoadSecurityExtensions(void);
127 
128 private:
129     void readStartupExtensions(void);
130 
131     void readPrelinkedExtensions(
132         kernel_section_t * prelinkInfoSect);
133     void readBooterExtensions(void);
134 
135     OSReturn loadKernelComponentKexts(void);
136     void     loadKernelExternalComponents(void);
137     void     readBuiltinPersonalities(void);
138 
139     void     loadSecurityExtensions(void);
140 
141 public:
142     KLDBootstrap(void);
143     ~KLDBootstrap(void);
144 };
145 
146 static KLDBootstrap sBootstrapObject;
147 
148 /*********************************************************************
149 * Set the function pointers for the entry points into the bootstrap
150 * segment upon C++ static constructor invocation.
151 *********************************************************************/
152 KLDBootstrap::KLDBootstrap(void)
153 {
154     if (this != &sBootstrapObject) {
155         panic("Attempt to access bootstrap segment.");
156     }
157     record_startup_extensions_function = &bootstrapRecordStartupExtensions;
158     load_security_extensions_function = &bootstrapLoadSecurityExtensions;
159 }
160 
161 /*********************************************************************
162 * Clear the function pointers for the entry points into the bootstrap
163 * segment upon C++ static destructor invocation.
164 *********************************************************************/
165 KLDBootstrap::~KLDBootstrap(void)
166 {
167     if (this != &sBootstrapObject) {
168         panic("Attempt to access bootstrap segment.");
169     }
170 
171 
172     record_startup_extensions_function = 0;
173     load_security_extensions_function = 0;
174 }
175 
176 /*********************************************************************
177 *********************************************************************/
178 void
179 KLDBootstrap::readStartupExtensions(void)
180 {
181     kernel_section_t * prelinkInfoSect = NULL;  // do not free
182 
183     OSKextLog(/* kext */ NULL,
184         kOSKextLogProgressLevel |
185         kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag |
186         kOSKextLogKextBookkeepingFlag,
187         "Reading startup extensions.");
188 
189    /* If the prelink info segment has a nonzero size, we are prelinked
190     * and won't have any individual kexts or mkexts to read.
191     * Otherwise, we need to read kexts or the mkext from what the booter
192     * has handed us.
193     */
194     prelinkInfoSect = getsectbyname(kPrelinkInfoSegment, kPrelinkInfoSection);
195     if (prelinkInfoSect->size) {
196         readPrelinkedExtensions(prelinkInfoSect);
197     } else {
198         readBooterExtensions();
199     }
200 
201     loadKernelComponentKexts();
202     loadKernelExternalComponents();
203     readBuiltinPersonalities();
204     OSKext::sendAllKextPersonalitiesToCatalog();
205 
206     return;
207 }
208 
209 /*********************************************************************
210 *********************************************************************/
211 void
212 KLDBootstrap::readPrelinkedExtensions(
213     kernel_section_t * prelinkInfoSect)
214 {
215     OSArray                   * infoDictArray           = NULL;  // do not release
216     OSObject                  * parsedXML       = NULL;  // must release
217     OSDictionary              * prelinkInfoDict         = NULL;  // do not release
218     OSString                  * errorString             = NULL;  // must release
219     OSKext                    * theKernel               = NULL;  // must release
220 
221     kernel_segment_command_t  * prelinkTextSegment      = NULL;  // see code
222     kernel_segment_command_t  * prelinkInfoSegment      = NULL;  // see code
223 
224    /* We make some copies of data, but if anything fails we're basically
225     * going to fail the boot, so these won't be cleaned up on error.
226     */
227     void                      * prelinkData             = NULL;  // see code
228     vm_size_t                   prelinkLength           = 0;
229 
230 
231     OSDictionary              * infoDict                = NULL;  // do not release
232 
233     IORegistryEntry           * registryRoot            = NULL;  // do not release
234     OSNumber                  * prelinkCountObj         = NULL;  // must release
235 
236     u_int                       i = 0;
237 #if NO_KEXTD
238     bool                        ramDiskBoot;
239     bool                        developerDevice;
240     bool                        dontLoad;
241 #endif
242 
243     OSKextLog(/* kext */ NULL,
244         kOSKextLogProgressLevel |
245         kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
246         "Starting from prelinked kernel.");
247 
248     prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
249     if (!prelinkTextSegment) {
250         OSKextLog(/* kext */ NULL,
251             kOSKextLogErrorLevel |
252             kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
253             "Can't find prelinked kexts' text segment.");
254         goto finish;
255     }
256 
257 #if KASLR_KEXT_DEBUG
258     unsigned long   scratchSize;
259     vm_offset_t     scratchAddr;
260 
261     IOLog("kaslr: prelinked kernel address info: \n");
262 
263     scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize);
264     IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
265           (unsigned long)scratchAddr,
266           (unsigned long)(scratchAddr + scratchSize),
267           scratchSize);
268 
269     scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize);
270     IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
271           (unsigned long)scratchAddr,
272           (unsigned long)(scratchAddr + scratchSize),
273           scratchSize);
274 
275     scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize);
276     IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
277           (unsigned long)scratchAddr,
278           (unsigned long)(scratchAddr + scratchSize),
279           scratchSize);
280 
281     scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize);
282     IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
283           (unsigned long)scratchAddr,
284           (unsigned long)(scratchAddr + scratchSize),
285           scratchSize);
286 
287     scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize);
288     IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
289           (unsigned long)scratchAddr,
290           (unsigned long)(scratchAddr + scratchSize),
291           scratchSize);
292 
293     scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize);
294     IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
295           (unsigned long)scratchAddr,
296           (unsigned long)(scratchAddr + scratchSize),
297           scratchSize);
298 #endif
299 
300     prelinkData = (void *) prelinkTextSegment->vmaddr;
301     prelinkLength = prelinkTextSegment->vmsize;
302 
303 
304    /* Unserialize the info dictionary from the prelink info section.
305     */
306     parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr,
307         &errorString);
308     if (parsedXML) {
309         prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML);
310     }
311     if (!prelinkInfoDict) {
312         const char * errorCString = "(unknown error)";
313 
314         if (errorString && errorString->getCStringNoCopy()) {
315             errorCString = errorString->getCStringNoCopy();
316         } else if (parsedXML) {
317             errorCString = "not a dictionary";
318         }
319         OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
320             "Error unserializing prelink plist: %s.", errorCString);
321         goto finish;
322     }
323 
324 #if NO_KEXTD
325     /* Check if we should keep developer kexts around.
326      * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
327      */
328     developerDevice = true;
329     PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice));
330 
331     ramDiskBoot = IORamDiskBSDRoot();
332 #endif /* NO_KEXTD */
333 
334     infoDictArray = OSDynamicCast(OSArray,
335         prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
336     if (!infoDictArray) {
337         OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
338             "The prelinked kernel has no kext info dictionaries");
339         goto finish;
340     }
341 
342     /* Create dictionary of excluded kexts
343      */
344     OSKext::createExcludeListFromPrelinkInfo(infoDictArray);
345 
346     /* Create OSKext objects for each info dictionary.
347      */
348     for (i = 0; i < infoDictArray->getCount(); ++i) {
349         infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i));
350         if (!infoDict) {
351             OSKextLog(/* kext */ NULL,
352                 kOSKextLogErrorLevel |
353                 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
354                 "Can't find info dictionary for prelinked kext #%d.", i);
355             continue;
356         }
357 
358 #if NO_KEXTD
359         dontLoad = false;
360 
361         /* If we're not on a developer device, skip and free developer kexts.
362          */
363         if (developerDevice == false) {
364             OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean,
365                 infoDict->getObject(kOSBundleDeveloperOnlyKey));
366             if (devOnlyBool == kOSBooleanTrue) {
367                 dontLoad = true;
368             }
369         }
370 
371         /* Skip and free kexts that are only needed when booted from a ram disk.
372          */
373         if (ramDiskBoot == false) {
374             OSBoolean *ramDiskOnlyBool = OSDynamicCast(OSBoolean,
375                 infoDict->getObject(kOSBundleRamDiskOnlyKey));
376             if (ramDiskOnlyBool == kOSBooleanTrue) {
377                 dontLoad = true;
378             }
379 	}
380 
381         if (dontLoad == true) {
382             OSString *bundleID = OSDynamicCast(OSString,
383                 infoDict->getObject(kCFBundleIdentifierKey));
384             if (bundleID) {
385                 OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
386                     "Kext %s not loading.", bundleID->getCStringNoCopy());
387             }
388 
389             OSNumber *addressNum = OSDynamicCast(OSNumber,
390                 infoDict->getObject(kPrelinkExecutableLoadKey));
391             OSNumber *lengthNum = OSDynamicCast(OSNumber,
392                 infoDict->getObject(kPrelinkExecutableSizeKey));
393             if (addressNum && lengthNum) {
394 #error Pick the right way to free prelinked data on this arch
395             }
396 
397             infoDictArray->removeObject(i--);
398             continue;
399         }
400 #endif /* NO_KEXTD */
401 
402        /* Create the kext for the entry, then release it, because the
403         * kext system keeps them around until explicitly removed.
404         * Any creation/registration failures are already logged for us.
405         */
406         OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict);
407         OSSafeReleaseNULL(newKext);
408     }
409 
410    /* Store the number of prelinked kexts in the registry so we can tell
411     * when the system has been started from a prelinked kernel.
412     */
413     registryRoot = IORegistryEntry::getRegistryRoot();
414     assert(registryRoot);
415 
416     prelinkCountObj = OSNumber::withNumber(
417         (unsigned long long)infoDictArray->getCount(),
418         8 * sizeof(uint32_t));
419     assert(prelinkCountObj);
420     if (prelinkCountObj) {
421         registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj);
422     }
423 
424     OSKextLog(/* kext */ NULL,
425         kOSKextLogProgressLevel |
426         kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
427         kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
428         "%u prelinked kexts",
429         infoDictArray->getCount());
430 
431 #if CONFIG_KEXT_BASEMENT
432         /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
433          * special VM region during OSKext init time, so we can free the whole
434          * segment now.
435          */
436         ml_static_mfree((vm_offset_t) prelinkData, prelinkLength);
437 #endif /* __x86_64__ */
438 
439    /* Free the prelink info segment, we're done with it.
440     */
441     prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
442     if (prelinkInfoSegment) {
443         ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
444             (vm_size_t)prelinkInfoSegment->vmsize);
445     }
446 
447 finish:
448     OSSafeRelease(errorString);
449     OSSafeRelease(parsedXML);
450     OSSafeRelease(theKernel);
451     OSSafeRelease(prelinkCountObj);
452     return;
453 }
454 
455 /*********************************************************************
456 *********************************************************************/
457 #define BOOTER_KEXT_PREFIX   "Driver-"
458 
459 typedef struct _DeviceTreeBuffer {
460     uint32_t paddr;
461     uint32_t length;
462 } _DeviceTreeBuffer;
463 
464 void
465 KLDBootstrap::readBooterExtensions(void)
466 {
467     IORegistryEntry           * booterMemoryMap         = NULL;  // must release
468     OSDictionary              * propertyDict            = NULL;  // must release
469     OSCollectionIterator      * keyIterator             = NULL;  // must release
470     OSString                  * deviceTreeName          = NULL;  // do not release
471 
472     const _DeviceTreeBuffer   * deviceTreeBuffer        = NULL;  // do not free
473     char                      * booterDataPtr           = NULL;  // do not free
474     OSData                    * booterData              = NULL;  // must release
475 
476     OSKext                    * aKext                   = NULL;  // must release
477 
478     OSKextLog(/* kext */ NULL,
479         kOSKextLogProgressLevel |
480         kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
481         "Reading startup extensions from booter memory.");
482 
483     booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);
484 
485     if (!booterMemoryMap) {
486         OSKextLog(/* kext */ NULL,
487             kOSKextLogErrorLevel |
488             kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
489             "Can't read booter memory map.");
490         goto finish;
491     }
492 
493     propertyDict = booterMemoryMap->dictionaryWithProperties();
494     if (!propertyDict) {
495         OSKextLog(/* kext */ NULL,
496             kOSKextLogErrorLevel |
497             kOSKextLogDirectoryScanFlag,
498             "Can't get property dictionary from memory map.");
499         goto finish;
500     }
501 
502     keyIterator = OSCollectionIterator::withCollection(propertyDict);
503     if (!keyIterator) {
504         OSKextLog(/* kext */ NULL,
505             kOSKextLogErrorLevel |
506             kOSKextLogGeneralFlag,
507             "Can't allocate iterator for driver images.");
508         goto finish;
509     }
510 
511     /* Create dictionary of excluded kexts
512      */
513     OSKext::createExcludeListFromBooterData(propertyDict, keyIterator);
514     keyIterator->reset();
515 
516     while ( ( deviceTreeName =
517         OSDynamicCast(OSString, keyIterator->getNextObject() ))) {
518 
519         const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
520         OSData * deviceTreeEntry = OSDynamicCast(OSData,
521             propertyDict->getObject(deviceTreeName));
522 
523        /* Clear out the booterData from the prior iteration.
524         */
525         OSSafeReleaseNULL(booterData);
526 
527         /* If there is no entry for the name, we can't do much with it. */
528         if (!deviceTreeEntry) {
529             continue;
530         }
531 
532         /* Make sure it is a kext */
533         if (strncmp(devTreeNameCString,
534                     BOOTER_KEXT_PREFIX,
535                     CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
536             continue;
537         }
538 
539         deviceTreeBuffer = (const _DeviceTreeBuffer *)
540             deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
541         if (!deviceTreeBuffer) {
542            /* We can't get to the data, so we can't do anything,
543             * not even free it from physical memory (if it's there).
544             */
545             OSKextLog(/* kext */ NULL,
546                 kOSKextLogErrorLevel |
547                 kOSKextLogDirectoryScanFlag,
548                 "Device tree entry %s has NULL pointer.",
549                 devTreeNameCString);
550             goto finish;  // xxx - continue, panic?
551         }
552 
553         booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
554         if (!booterDataPtr) {
555             OSKextLog(/* kext */ NULL,
556                 kOSKextLogErrorLevel |
557                 kOSKextLogDirectoryScanFlag,
558                 "Can't get virtual address for device tree entry %s.",
559                 devTreeNameCString);
560             goto finish;
561         }
562 
563        /* Wrap the booter data buffer in an OSData and set a dealloc function
564         * so it will take care of the physical memory when freed. Kexts will
565         * retain the booterData for as long as they need it. Remove the entry
566         * from the booter memory map after this is done.
567         */
568         booterData = OSData::withBytesNoCopy(booterDataPtr,
569             deviceTreeBuffer->length);
570         if (!booterData) {
571             OSKextLog(/* kext */ NULL,
572                 kOSKextLogErrorLevel |
573                 kOSKextLogGeneralFlag,
574                 "Error - Can't allocate OSData wrapper for device tree entry %s.",
575                 devTreeNameCString);
576             goto finish;
577         }
578         booterData->setDeallocFunction(osdata_phys_free);
579 
580         /* Create the kext for the entry, then release it, because the
581          * kext system keeps them around until explicitly removed.
582          * Any creation/registration failures are already logged for us.
583          */
584         OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData);
585         OSSafeRelease(newKext);
586 
587         booterMemoryMap->removeProperty(deviceTreeName);
588 
589     } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
590 
591 finish:
592 
593     OSSafeRelease(booterMemoryMap);
594     OSSafeRelease(propertyDict);
595     OSSafeRelease(keyIterator);
596     OSSafeRelease(booterData);
597     OSSafeRelease(aKext);
598     return;
599 }
600 
601 /*********************************************************************
602 *********************************************************************/
603 #define COM_APPLE  "com.apple."
604 
605 void
606 KLDBootstrap::loadSecurityExtensions(void)
607 {
608     OSDictionary         * extensionsDict = NULL;  // must release
609     OSCollectionIterator * keyIterator    = NULL;  // must release
610     OSString             * bundleID       = NULL;  // don't release
611     OSKext               * theKext        = NULL;  // don't release
612     OSBoolean            * isSecurityKext = NULL;  // don't release
613 
614     OSKextLog(/* kext */ NULL,
615         kOSKextLogStepLevel |
616         kOSKextLogLoadFlag,
617         "Loading security extensions.");
618 
619     extensionsDict = OSKext::copyKexts();
620     if (!extensionsDict) {
621         return;
622     }
623 
624     keyIterator = OSCollectionIterator::withCollection(extensionsDict);
625     if (!keyIterator) {
626         OSKextLog(/* kext */ NULL,
627             kOSKextLogErrorLevel |
628             kOSKextLogGeneralFlag,
629             "Failed to allocate iterator for security extensions.");
630         goto finish;
631     }
632 
633     while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
634 
635         const char * bundle_id = bundleID->getCStringNoCopy();
636 
637        /* Skip extensions whose bundle IDs don't start with "com.apple.".
638         */
639         if (!bundle_id ||
640             (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) {
641 
642             continue;
643         }
644 
645         theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
646         if (!theKext) {
647             continue;
648         }
649 
650         isSecurityKext = OSDynamicCast(OSBoolean,
651             theKext->getPropertyForHostArch(kAppleSecurityExtensionKey));
652         if (isSecurityKext && isSecurityKext->isTrue()) {
653             OSKextLog(/* kext */ NULL,
654                 kOSKextLogStepLevel |
655                 kOSKextLogLoadFlag,
656                 "Loading security extension %s.", bundleID->getCStringNoCopy());
657             OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
658                 /* allowDefer */ false);
659         }
660     }
661 
662 finish:
663     OSSafeRelease(keyIterator);
664     OSSafeRelease(extensionsDict);
665 
666     return;
667 }
668 
669 /*********************************************************************
670 * We used to require that all listed kernel components load, but
671 * nowadays we can get them from userland so we only try to load the
672 * ones we have. If an error occurs later, such is life.
673 *
674 * Note that we look the kexts up first, so we can avoid spurious
675 * (in this context, anyhow) log messages about kexts not being found.
676 *
677 * xxx - do we even need to do this any more? Check if the kernel
678 * xxx - compoonents just load in the regular paths
679 *********************************************************************/
680 OSReturn
681 KLDBootstrap::loadKernelComponentKexts(void)
682 {
683     OSReturn      result      = kOSReturnSuccess;  // optimistic
684     OSKext      * theKext     = NULL;              // must release
685     const char ** kextIDPtr   = NULL;              // do not release
686 
687     for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
688 
689         OSSafeReleaseNULL(theKext);
690         theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr);
691 
692         if (theKext) {
693             if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
694                 *kextIDPtr, /* allowDefer */ false)) {
695 
696                 // xxx - check KextBookkeeping, might be redundant
697                 OSKextLog(/* kext */ NULL,
698                     kOSKextLogErrorLevel |
699                     kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
700                     "Failed to initialize kernel component %s.", *kextIDPtr);
701                 result = kOSReturnError;
702             }
703         }
704     }
705 
706     OSSafeRelease(theKext);
707     return result;
708 }
709 
710 /*********************************************************************
711 * Ensure that Kernel External Components are loaded early in boot,
712 * before other kext personalities get sent to the IOCatalogue. These
713 * kexts are treated specially because they may provide the implementation
714 * for kernel-vended KPI, so they must register themselves before
715 * general purpose IOKit probing begins.
716 *********************************************************************/
717 
718 #define COM_APPLE_KEC  "com.apple.kec."
719 
720 void
721 KLDBootstrap::loadKernelExternalComponents(void)
722 {
723     OSDictionary         * extensionsDict = NULL;  // must release
724     OSCollectionIterator * keyIterator    = NULL;  // must release
725     OSString             * bundleID       = NULL;  // don't release
726     OSKext               * theKext        = NULL;  // don't release
727     OSBoolean            * isKernelExternalComponent = NULL;  // don't release
728 
729     OSKextLog(/* kext */ NULL,
730         kOSKextLogStepLevel |
731         kOSKextLogLoadFlag,
732         "Loading Kernel External Components.");
733 
734     extensionsDict = OSKext::copyKexts();
735     if (!extensionsDict) {
736         return;
737     }
738 
739     keyIterator = OSCollectionIterator::withCollection(extensionsDict);
740     if (!keyIterator) {
741         OSKextLog(/* kext */ NULL,
742             kOSKextLogErrorLevel |
743             kOSKextLogGeneralFlag,
744             "Failed to allocate iterator for Kernel External Components.");
745         goto finish;
746     }
747 
748     while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
749 
750         const char * bundle_id = bundleID->getCStringNoCopy();
751 
752        /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
753         */
754         if (!bundle_id ||
755             (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
756 
757             continue;
758         }
759 
760         theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
761         if (!theKext) {
762             continue;
763         }
764 
765         isKernelExternalComponent = OSDynamicCast(OSBoolean,
766             theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
767         if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
768             OSKextLog(/* kext */ NULL,
769                 kOSKextLogStepLevel |
770                 kOSKextLogLoadFlag,
771                 "Loading kernel external component %s.", bundleID->getCStringNoCopy());
772             OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
773                 /* allowDefer */ false);
774         }
775     }
776 
777 finish:
778     OSSafeRelease(keyIterator);
779     OSSafeRelease(extensionsDict);
780 
781     return;
782 }
783 
784 /*********************************************************************
785  *********************************************************************/
786 void
787 KLDBootstrap::readBuiltinPersonalities(void)
788 {
789     OSObject              * parsedXML             = NULL;  // must release
790     OSArray               * builtinExtensions     = NULL;  // do not release
791     OSArray               * allPersonalities      = NULL;  // must release
792     OSString              * errorString           = NULL;  // must release
793     kernel_section_t      * infosect              = NULL;  // do not free
794     OSCollectionIterator  * personalitiesIterator = NULL;  // must release
795     unsigned int            count, i;
796 
797     OSKextLog(/* kext */ NULL,
798         kOSKextLogStepLevel |
799         kOSKextLogLoadFlag,
800         "Reading built-in kernel personalities for I/O Kit drivers.");
801 
802    /* Look in the __BUILTIN __info segment for an array of Info.plist
803     * entries. For each one, extract the personalities dictionary, add
804     * it to our array, then push them all (without matching) to
805     * the IOCatalogue. This can be used to augment the personalities
806     * in gIOKernelConfigTables, especially when linking entire kexts into
807     * the mach_kernel image.
808     */
809     infosect   = getsectbyname("__BUILTIN", "__info");
810     if (!infosect) {
811         // this isn't fatal
812         goto finish;
813     }
814 
815     parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr,
816         &errorString);
817     if (parsedXML) {
818         builtinExtensions = OSDynamicCast(OSArray, parsedXML);
819     }
820     if (!builtinExtensions) {
821         const char * errorCString = "(unknown error)";
822 
823         if (errorString && errorString->getCStringNoCopy()) {
824             errorCString = errorString->getCStringNoCopy();
825         } else if (parsedXML) {
826             errorCString = "not an array";
827         }
828         OSKextLog(/* kext */ NULL,
829             kOSKextLogErrorLevel |
830             kOSKextLogLoadFlag,
831             "Error unserializing built-in personalities: %s.", errorCString);
832         goto finish;
833     }
834 
835     // estimate 3 personalities per Info.plist/kext
836     count = builtinExtensions->getCount();
837     allPersonalities = OSArray::withCapacity(count * 3);
838 
839     for (i = 0; i < count; i++) {
840         OSDictionary            * infoDict = NULL;      // do not release
841         OSString                * moduleName = NULL;    // do not release
842         OSDictionary            * personalities;        // do not release
843         OSString                * personalityName;      // do not release
844 
845         OSSafeReleaseNULL(personalitiesIterator);
846 
847         infoDict = OSDynamicCast(OSDictionary,
848             builtinExtensions->getObject(i));
849         if (!infoDict) {
850             continue;
851         }
852 
853         moduleName = OSDynamicCast(OSString,
854             infoDict->getObject(kCFBundleIdentifierKey));
855         if (!moduleName) {
856             continue;
857         }
858 
859         OSKextLog(/* kext */ NULL,
860             kOSKextLogStepLevel |
861             kOSKextLogLoadFlag,
862             "Adding personalities for built-in driver %s:",
863             moduleName->getCStringNoCopy());
864 
865         personalities = OSDynamicCast(OSDictionary,
866             infoDict->getObject("IOKitPersonalities"));
867         if (!personalities) {
868             continue;
869         }
870 
871         personalitiesIterator = OSCollectionIterator::withCollection(personalities);
872         if (!personalitiesIterator) {
873             continue;  // xxx - well really, what can we do? should we panic?
874         }
875 
876         while ((personalityName = OSDynamicCast(OSString,
877             personalitiesIterator->getNextObject()))) {
878 
879             OSDictionary * personality = OSDynamicCast(OSDictionary,
880                 personalities->getObject(personalityName));
881 
882             OSKextLog(/* kext */ NULL,
883                 kOSKextLogDetailLevel |
884                 kOSKextLogLoadFlag,
885                 "Adding built-in driver personality %s.",
886                 personalityName->getCStringNoCopy());
887 
888 			if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
889 				personality->setObject(kCFBundleIdentifierKey, moduleName);
890 			}
891             allPersonalities->setObject(personality);
892         }
893     }
894 
895     gIOCatalogue->addDrivers(allPersonalities, false);
896 
897 finish:
898     OSSafeRelease(parsedXML);
899     OSSafeRelease(allPersonalities);
900     OSSafeRelease(errorString);
901     OSSafeRelease(personalitiesIterator);
902     return;
903 }
904 
905 #if PRAGMA_MARK
906 #pragma mark Bootstrap Functions
907 #endif
908 /*********************************************************************
909 * Bootstrap Functions
910 *********************************************************************/
911 static void bootstrapRecordStartupExtensions(void)
912 {
913     sBootstrapObject.readStartupExtensions();
914     return;
915 }
916 
917 static void bootstrapLoadSecurityExtensions(void)
918 {
919     sBootstrapObject.loadSecurityExtensions();
920     return;
921 }
922 
923