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 */
28extern "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*********************************************************************/
65extern "C" {
66    extern void (*record_startup_extensions_function)(void);
67    extern void (*load_security_extensions_function)(void);
68};
69
70static void bootstrapRecordStartupExtensions(void);
71static void bootstrapLoadSecurityExtensions(void);
72
73
74#if NO_KEXTD
75extern "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*********************************************************************/
97static 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*********************************************************************/
124class KLDBootstrap {
125    friend void bootstrapRecordStartupExtensions(void);
126    friend void bootstrapLoadSecurityExtensions(void);
127
128private:
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
144public:
145    KLDBootstrap(void);
146    ~KLDBootstrap(void);
147};
148
149static KLDBootstrap sBootstrapObject;
150
151/*********************************************************************
152* Set the function pointers for the entry points into the bootstrap
153* segment upon C++ static constructor invocation.
154*********************************************************************/
155KLDBootstrap::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*********************************************************************/
168KLDBootstrap::~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*********************************************************************/
181void
182KLDBootstrap::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*********************************************************************/
214void
215KLDBootstrap::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
450finish:
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
463typedef struct _DeviceTreeBuffer {
464    uint32_t paddr;
465    uint32_t length;
466} _DeviceTreeBuffer;
467
468void
469KLDBootstrap::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
608finish:
609
610    OSSafeRelease(booterMemoryMap);
611    OSSafeRelease(propertyDict);
612    OSSafeRelease(keyIterator);
613    OSSafeRelease(booterData);
614    OSSafeRelease(aKext);
615    return;
616}
617
618/*********************************************************************
619*********************************************************************/
620OSReturn
621KLDBootstrap::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
665void
666KLDBootstrap::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
722finish:
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*********************************************************************/
740OSReturn
741KLDBootstrap::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
780void
781KLDBootstrap::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
837finish:
838    OSSafeRelease(keyIterator);
839    OSSafeRelease(extensionsDict);
840
841    return;
842}
843
844/*********************************************************************
845 *********************************************************************/
846void
847KLDBootstrap::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
957finish:
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*********************************************************************/
971static void bootstrapRecordStartupExtensions(void)
972{
973    sBootstrapObject.readStartupExtensions();
974    return;
975}
976
977static void bootstrapLoadSecurityExtensions(void)
978{
979    sBootstrapObject.loadSecurityExtensions();
980    return;
981}
982
983