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