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