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