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