1/*
2 * Copyright (c) 2000-2007 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
29/*
30 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
31 * support for mandatory and extensible security protections.  This notice
32 * is included in support of clause 2.2 (b) of the Apple Public License,
33 * Version 2.0.
34 */
35
36#include <libkern/c++/OSContainers.h>
37#include <IOKit/IOCatalogue.h>
38#include <IOKit/IOLib.h>
39#include <libsa/kext.h>
40#include <libsa/catalogue.h>
41
42extern "C" {
43#include <mach-o/kld.h>
44#include <libsa/vers_rsrc.h>
45#include <libsa/stdlib.h>
46#include <mach/kmod.h>
47#include <vm/vm_kern.h>
48#include <mach/kern_return.h>
49#include <mach-o/fat.h>
50#include <mach_loader.h>
51
52#include "kld_patch.h"
53#include "dgraph.h"
54#include "load.h"
55};
56
57
58extern "C" {
59extern kern_return_t
60kmod_create_internal(
61            kmod_info_t *info,
62            kmod_t *id);
63
64extern kern_return_t
65kmod_destroy_internal(kmod_t id);
66
67extern kern_return_t
68kmod_start_or_stop(
69    kmod_t id,
70    int start,
71    kmod_args_t *data,
72    mach_msg_type_number_t *dataCount);
73
74extern kern_return_t kmod_retain(kmod_t id);
75extern kern_return_t kmod_release(kmod_t id);
76
77extern Boolean kmod_load_request(const char * moduleName, Boolean make_request);
78};
79
80extern kmod_args_t
81get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen);
82
83extern struct mac_module_data *osdict_encode(OSDictionary *dict);
84
85#define DEBUG
86#ifdef DEBUG
87#define LOG_DELAY(x)    IODelay((x) * 1000000)
88#define VTYELLOW  "\033[33m"
89#define VTRESET   "\033[0m"
90#else
91#define LOG_DELAY(x)
92#define VTYELLOW
93#define VTRESET
94#endif /* DEBUG */
95
96
97#define KERNEL_PREFIX  "com.apple.kernel"
98#define KPI_PREFIX     "com.apple.kpi"
99
100
101/*********************************************************************
102*
103*********************************************************************/
104static
105bool getKext(
106    const char * bundleid,
107    OSDictionary ** plist,
108    unsigned char ** code,
109    unsigned long * code_size,
110    bool * caller_owns_code)
111{
112    bool result = true;
113    OSDictionary * extensionsDict;   // don't release
114    OSDictionary * extDict;          // don't release
115    OSDictionary * extPlist;         // don't release
116    unsigned long code_size_local;
117
118   /* Get the dictionary of startup extensions.
119    * This is keyed by module name.
120    */
121    extensionsDict = getStartupExtensions();
122    if (!extensionsDict) {
123        IOLog("startup extensions dictionary is missing\n");
124        result = false;
125        goto finish;
126    }
127
128   /* Get the requested extension's dictionary entry and its property
129    * list, containing module dependencies.
130    */
131    extDict = OSDynamicCast(OSDictionary,
132        extensionsDict->getObject(bundleid));
133
134    if (!extDict) {
135        IOLog("extension \"%s\" cannot be found\n",
136           bundleid);
137        result = false;
138        goto finish;
139    }
140
141    if (plist) {
142        extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
143        if (!extPlist) {
144            IOLog("extension \"%s\" has no info dictionary\n",
145                bundleid);
146            result = false;
147            goto finish;
148        }
149        *plist = extPlist;
150    }
151
152    if (code) {
153
154       /* If asking for code, the caller must provide a return buffer
155        * for ownership!
156        */
157        if (!caller_owns_code) {
158            IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
159            result = false;
160            goto finish;
161        }
162
163        *code = 0;
164        if (code_size) {
165            *code_size = 0;
166        }
167        *caller_owns_code = false;
168
169        *code = (unsigned char *)kld_file_getaddr(bundleid,
170            (unsigned long *)&code_size_local);
171        if (*code) {
172            if (code_size) {
173                *code_size = code_size_local;
174            }
175        } else {
176            OSData * driverCode = 0; // release only if uncompressing!
177
178            driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
179            if (driverCode) {
180                *code = (unsigned char *)driverCode->getBytesNoCopy();
181                if (code_size) {
182                    *code_size = driverCode->getLength();
183                }
184            } else { // Look for compressed code and uncompress it
185                OSData * compressedCode = 0;
186                compressedCode = OSDynamicCast(OSData,
187                    extDict->getObject("compressedCode"));
188                if (compressedCode) {
189                    if (!uncompressModule(compressedCode, &driverCode)) {
190                        IOLog("extension \"%s\": couldn't uncompress code\n",
191                            bundleid);
192                        result = false;
193                        goto finish;
194                    }
195                    *caller_owns_code = true;
196                    *code = (unsigned char *)driverCode->getBytesNoCopy();
197                    if (code_size) {
198                        *code_size = driverCode->getLength();
199                    }
200                    driverCode->release();
201                }
202            }
203        }
204    }
205
206finish:
207
208    return result;
209}
210
211
212/*********************************************************************
213*
214*********************************************************************/
215static
216bool verifyCompatibility(OSString * extName, OSString * requiredVersion)
217{
218    OSDictionary * extPlist;         // don't release
219    OSString     * extVersion;       // don't release
220    OSString     * extCompatVersion; // don't release
221    VERS_version ext_version;
222    VERS_version ext_compat_version;
223    VERS_version required_version;
224
225    if (!getKext(extName->getCStringNoCopy(), &extPlist, NULL, NULL, NULL)) {
226        return false;
227    }
228
229    extVersion = OSDynamicCast(OSString,
230        extPlist->getObject("CFBundleVersion"));
231    if (!extVersion) {
232        IOLog("verifyCompatibility(): "
233            "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
234            extName->getCStringNoCopy());
235        return false;
236    }
237
238    extCompatVersion = OSDynamicCast(OSString,
239        extPlist->getObject("OSBundleCompatibleVersion"));
240    if (!extCompatVersion) {
241        IOLog("verifyCompatibility(): "
242            "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
243            extName->getCStringNoCopy());
244        return false;
245    }
246
247    required_version = VERS_parse_string(requiredVersion->getCStringNoCopy());
248    if (required_version < 0) {
249        IOLog("verifyCompatibility(): "
250            "Can't parse required version \"%s\" of dependency %s.\n",
251            requiredVersion->getCStringNoCopy(),
252            extName->getCStringNoCopy());
253        return false;
254    }
255    ext_version = VERS_parse_string(extVersion->getCStringNoCopy());
256    if (ext_version < 0) {
257        IOLog("verifyCompatibility(): "
258            "Can't parse version \"%s\" of dependency %s.\n",
259            extVersion->getCStringNoCopy(),
260            extName->getCStringNoCopy());
261        return false;
262    }
263    ext_compat_version = VERS_parse_string(extCompatVersion->getCStringNoCopy());
264    if (ext_compat_version < 0) {
265        IOLog("verifyCompatibility(): "
266            "Can't parse compatible version \"%s\" of dependency %s.\n",
267            extCompatVersion->getCStringNoCopy(),
268            extName->getCStringNoCopy());
269        return false;
270    }
271
272    if (required_version > ext_version || required_version < ext_compat_version) {
273        return false;
274    }
275
276    return true;
277}
278
279/*********************************************************************
280*********************************************************************/
281static
282bool kextIsDependency(const char * kext_name, char * is_kernel) {
283    bool result = true;
284    OSDictionary * extensionsDict = 0;    // don't release
285    OSDictionary * extDict = 0;           // don't release
286    OSDictionary * extPlist = 0;          // don't release
287    OSBoolean * isKernelResourceObj = 0;  // don't release
288    OSData * driverCode = 0;              // don't release
289    OSData * compressedCode = 0;          // don't release
290
291    if (is_kernel) {
292        *is_kernel = 0;
293    }
294
295   /* Get the dictionary of startup extensions.
296    * This is keyed by module name.
297    */
298    extensionsDict = getStartupExtensions();
299    if (!extensionsDict) {
300        IOLog("startup extensions dictionary is missing\n");
301        result = false;
302        goto finish;
303    }
304
305   /* Get the requested extension's dictionary entry and its property
306    * list, containing module dependencies.
307    */
308    extDict = OSDynamicCast(OSDictionary,
309        extensionsDict->getObject(kext_name));
310
311    if (!extDict) {
312        IOLog("extension \"%s\" cannot be found\n",
313           kext_name);
314        result = false;
315        goto finish;
316    }
317
318    extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
319    if (!extPlist) {
320        IOLog("extension \"%s\" has no info dictionary\n",
321            kext_name);
322        result = false;
323        goto finish;
324    }
325
326   /* A kext that is a kernel component is still a dependency, as there
327    * are fake kmod entries for them.
328    */
329    isKernelResourceObj = OSDynamicCast(OSBoolean,
330        extPlist->getObject("OSKernelResource"));
331    if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
332        if (is_kernel) {
333            *is_kernel = 1;
334        }
335    }
336
337    driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
338    compressedCode = OSDynamicCast(OSData,
339        extDict->getObject("compressedCode"));
340
341   /* A kernel component that has code represents a KPI.
342    */
343    if ((driverCode || compressedCode) && is_kernel && *is_kernel) {
344        *is_kernel = 2;
345    }
346
347    if (!driverCode && !compressedCode && !isKernelResourceObj) {
348        result = false;
349        goto finish;
350    }
351
352finish:
353
354    return result;
355}
356
357/*********************************************************************
358*********************************************************************/
359static bool
360addDependenciesForKext(OSDictionary * kextPlist,
361    OSArray   * dependencyList,
362    OSString * trueParent,
363    Boolean    skipKernelDependencies)
364{
365    bool result = true;
366    bool hasDirectKernelDependency = false;
367    bool hasKernelStyleDependency = false;
368    bool hasKPIStyleDependency = false;
369    OSString * kextName = 0;  // don't release
370    OSDictionary * libraries = 0;  // don't release
371    OSCollectionIterator * keyIterator = 0; // must release
372    OSString * libraryName = 0; // don't release
373    OSString * dependentName = 0; // don't release
374
375    kextName = OSDynamicCast(OSString,
376        kextPlist->getObject("CFBundleIdentifier"));
377    if (!kextName) {
378        // XXX: Add log message
379        result = false;
380        goto finish;
381    }
382
383    libraries = OSDynamicCast(OSDictionary,
384        kextPlist->getObject("OSBundleLibraries"));
385    if (!libraries) {
386        result = true;
387        goto finish;
388    }
389
390    keyIterator = OSCollectionIterator::withCollection(libraries);
391    if (!keyIterator) {
392        // XXX: Add log message
393        result = false;
394        goto finish;
395    }
396
397    dependentName = trueParent ? trueParent : kextName;
398
399    while ( (libraryName = OSDynamicCast(OSString,
400        keyIterator->getNextObject())) ) {
401
402        OSString * libraryVersion = OSDynamicCast(OSString,
403            libraries->getObject(libraryName));
404        if (!libraryVersion) {
405            // XXX: Add log message
406            result = false;
407            goto finish;
408        }
409        if (!verifyCompatibility(libraryName, libraryVersion)) {
410            result = false;
411            goto finish;
412        } else {
413            char is_kernel_component;
414
415            if (!kextIsDependency(libraryName->getCStringNoCopy(),
416                &is_kernel_component)) {
417
418                is_kernel_component = 0;
419            }
420
421            if (!skipKernelDependencies || !is_kernel_component) {
422                dependencyList->setObject(dependentName);
423                dependencyList->setObject(libraryName);
424            }
425            if (!hasDirectKernelDependency && is_kernel_component) {
426                hasDirectKernelDependency = true;
427            }
428
429           /* We already know from the kextIsDependency() call whether
430            * the dependency *itself* is kernel- or KPI-style, but since
431            * the declaration semantic is by bundle ID, we check that here
432            * instead.
433            */
434            if (strncmp(libraryName->getCStringNoCopy(),
435                KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0) {
436
437                hasKernelStyleDependency = true;
438
439            } else if (strncmp(libraryName->getCStringNoCopy(),
440                KPI_PREFIX, strlen(KPI_PREFIX)) == 0) {
441
442                hasKPIStyleDependency = true;
443            }
444        }
445    }
446
447    if (!hasDirectKernelDependency) {
448        const OSSymbol * kernelName = 0;
449
450        /* a kext without any kernel dependency is assumed dependent on 6.0 */
451        dependencyList->setObject(dependentName);
452
453        kernelName = OSSymbol::withCString("com.apple.kernel.libkern");
454        if (!kernelName) {
455            // XXX: Add log message
456            result = false;
457            goto finish;
458        }
459        dependencyList->setObject(kernelName);
460        kernelName->release();
461
462        IOLog("Extension \"%s\" has no explicit kernel dependency; using version 6.0.\n",
463            kextName->getCStringNoCopy());
464
465    } else if (hasKernelStyleDependency && hasKPIStyleDependency) {
466        IOLog("Extension \"%s\" has immediate dependencies "
467            "on both com.apple.kernel and com.apple.kpi components; use only one style.\n",
468            kextName->getCStringNoCopy());
469    }
470
471finish:
472    if (keyIterator) keyIterator->release();
473    return result;
474}
475
476/*********************************************************************
477*********************************************************************/
478static
479bool getVersionForKext(OSDictionary * kextPlist, char ** version)
480{
481    OSString * kextName = 0;  // don't release
482    OSString * kextVersion;       // don't release
483
484    kextName = OSDynamicCast(OSString,
485        kextPlist->getObject("CFBundleIdentifier"));
486    if (!kextName) {
487        // XXX: Add log message
488        return false;
489    }
490
491    kextVersion = OSDynamicCast(OSString,
492        kextPlist->getObject("CFBundleVersion"));
493    if (!kextVersion) {
494        IOLog("getVersionForKext(): "
495            "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
496            kextName->getCStringNoCopy());
497        return false;
498    }
499
500    if (version) {
501        *version = (char *)kextVersion->getCStringNoCopy();
502    }
503
504    return true;
505}
506
507/*********************************************************************
508*********************************************************************/
509static
510bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
511{
512    bool result = true;
513    OSDictionary * kextPlist = 0; // don't release
514    unsigned int index = 0;
515    OSArray * dependencyList = 0;  // must release
516    unsigned char * code = 0;
517    unsigned long code_length = 0;
518    bool code_is_kmem = false;
519    char * kmod_vers = 0; // from plist, don't free
520    char is_kernel_component = 0;
521    dgraph_entry_t * dgraph_entry = 0; // don't free
522    dgraph_entry_t * dgraph_dependency = 0; // don't free
523    bool kext_is_dependency = true;
524
525#if CONFIG_MACF_KEXT
526    kmod_args_t user_data = 0;
527    mach_msg_type_number_t user_data_length;
528#endif
529
530   /*****
531    * Set up the root kmod.
532    */
533    if (!getKext(kmod_name, &kextPlist, &code, &code_length,
534        &code_is_kmem)) {
535        IOLog("can't find extension %s\n", kmod_name);
536        result = false;
537        goto finish;
538    }
539
540    if (!kextIsDependency(kmod_name, &is_kernel_component)) {
541        IOLog("extension %s is not loadable\n", kmod_name);
542        result = false;
543        goto finish;
544    }
545
546    if (!getVersionForKext(kextPlist, &kmod_vers)) {
547        IOLog("can't get version for extension %s\n", kmod_name);
548        result = false;
549        goto finish;
550    }
551
552#if CONFIG_MACF_KEXT
553    // check kext for module data in the plist
554    user_data = get_module_data(kextPlist, &user_data_length);
555#endif
556
557    dgraph_entry = dgraph_add_dependent(dgraph, kmod_name,
558        code, code_length, code_is_kmem,
559#if CONFIG_MACF_KEXT
560        user_data, user_data_length,
561#endif
562        kmod_name, kmod_vers,
563        0 /* load_address not yet known */, is_kernel_component);
564    if (!dgraph_entry) {
565        IOLog("can't record %s in dependency graph\n", kmod_name);
566        result = false;
567        // kmem_alloc()ed code is freed in finish: block.
568        goto finish;
569    }
570
571    // pass ownership of code to kld patcher
572    if (code) {
573        if (kload_map_entry(dgraph_entry) != kload_error_none) {
574            IOLog("can't map %s in preparation for loading\n", kmod_name);
575            result = false;
576            // kmem_alloc()ed code is freed in finish: block.
577           goto finish;
578        }
579    }
580    // clear local record of code
581    code = 0;
582    code_length = 0;
583    code_is_kmem = false;
584
585   /*****
586    * Now handle all the dependencies.
587    */
588    dependencyList = OSArray::withCapacity(5);
589    if (!dependencyList) {
590        IOLog("memory allocation failure\n");
591        result = false;
592        goto finish;
593    }
594
595    index = 0;
596    if (!addDependenciesForKext(kextPlist, dependencyList, NULL, false)) {
597        IOLog("can't determine immediate dependencies for extension %s\n",
598            kmod_name);
599        result = false;
600        goto finish;
601    }
602
603   /* IMPORTANT: loop condition gets list count every time through, as the
604    * array CAN change each iteration.
605    */
606    for (index = 0; index < dependencyList->getCount(); index += 2) {
607        OSString * dependentName = 0;
608        OSString * libraryName = 0;
609        const char * dependent_name = 0;
610        const char * library_name = 0;
611
612       /* 255 is an arbitrary limit. Multiplied  by 2 because the dependency
613        * list is stocked with pairs (dependent -> dependency).
614        */
615        if (index > (2 * 255)) {
616            IOLog("extension dependency graph ridiculously long, indicating a loop\n");
617            result = false;
618            goto finish;
619        }
620
621        dependentName = OSDynamicCast(OSString,
622            dependencyList->getObject(index));
623        libraryName = OSDynamicCast(OSString,
624            dependencyList->getObject(index + 1));
625
626        if (!dependentName || !libraryName) {
627            IOLog("malformed dependency list\n");
628            result = false;
629            goto finish;
630        }
631
632        dependent_name = dependentName->getCStringNoCopy();
633        library_name = libraryName->getCStringNoCopy();
634
635        if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
636
637            IOLog("can't find extension %s\n", library_name);
638            result = false;
639            goto finish;
640        }
641
642        OSString * string = OSDynamicCast(OSString,
643            kextPlist->getObject("OSBundleSharedExecutableIdentifier"));
644        if (string) {
645            library_name = string->getCStringNoCopy();
646            if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
647                IOLog("can't find extension %s\n", library_name);
648                result = false;
649                goto finish;
650            }
651        }
652
653        kext_is_dependency = kextIsDependency(library_name,
654            &is_kernel_component);
655
656        if (kext_is_dependency) {
657                dgraph_entry = dgraph_find_dependent(dgraph, dependent_name);
658                if (!dgraph_entry) {
659                    IOLog("internal error with dependency graph\n");
660                    LOG_DELAY(1);
661                    result = false;
662                    goto finish;
663                }
664
665                if (!getVersionForKext(kextPlist, &kmod_vers)) {
666                    IOLog("can't get version for extension %s\n", library_name);
667                    result = false;
668                    goto finish;
669                }
670
671               /* It's okay for code to be zero, as for a pseudokext
672                * representing a kernel component.
673                */
674                if (!getKext(library_name, NULL /* already got it */,
675                    &code, &code_length, &code_is_kmem)) {
676                    IOLog("can't find extension %s\n", library_name);
677                    result = false;
678                    goto finish;
679                }
680
681#if CONFIG_MACF_KEXT
682                // check kext for module data in the plist
683                // XXX - is this really needed?
684                user_data = get_module_data(kextPlist, &user_data_length);
685#endif
686                dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry,
687                    library_name, code, code_length, code_is_kmem,
688#if CONFIG_MACF_KEXT
689                    user_data, user_data_length,
690#endif
691                    library_name, kmod_vers,
692                    0 /* load_address not yet known */, is_kernel_component);
693
694                if (!dgraph_dependency) {
695                    IOLog("can't record dependency %s -> %s\n", dependent_name,
696                        library_name);
697                    result = false;
698                    // kmem_alloc()ed code is freed in finish: block.
699                    goto finish;
700                }
701
702                // pass ownership of code to kld patcher
703                if (code) {
704                    if (kload_map_entry(dgraph_dependency) != kload_error_none) {
705                        IOLog("can't map %s in preparation for loading\n", library_name);
706                        result = false;
707                        // kmem_alloc()ed code is freed in finish: block.
708                        goto finish;
709                    }
710                }
711                // clear local record of code
712                code = 0;
713                code_length = 0;
714                code_is_kmem = false;
715            }
716
717           /* Now put the library's dependencies onto the pending set.
718            */
719            if (!addDependenciesForKext(kextPlist, dependencyList,
720                kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) {
721
722                IOLog("can't determine immediate dependencies for extension %s\n",
723                    library_name);
724                result = false;
725                goto finish;
726            }
727        }
728
729finish:
730    if (code && code_is_kmem) {
731        kmem_free(kernel_map, (unsigned int)code, code_length);
732    }
733    if (dependencyList)  dependencyList->release();
734
735#if CONFIG_MACF_KEXT
736    if (user_data && !result) {
737        vm_map_copy_discard((vm_map_copy_t)user_data);
738    }
739#endif
740
741    return result;
742}
743
744/*********************************************************************
745* This is the function that IOCatalogue calls in order to load a kmod.
746* It first checks whether the kmod is already loaded. If the kmod
747* isn't loaded, this function builds a dependency list and calls
748* load_kmod() repeatedly to guarantee that each dependency is in fact
749* loaded.
750*********************************************************************/
751__private_extern__
752kern_return_t load_kernel_extension(char * kmod_name)
753{
754    kern_return_t result = KERN_SUCCESS;
755    kload_error load_result = kload_error_none;
756    dgraph_t dgraph;
757    bool free_dgraph = false;
758    kmod_info_t * kmod_info;
759
760// Put this in for lots of messages about kext loading.
761#if 0
762    kload_set_log_level(kload_log_level_load_details);
763#endif
764
765   /* See if the kmod is already loaded.
766    */
767    if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) {
768        kfree(kmod_info, sizeof(kmod_info_t));
769        return KERN_SUCCESS;
770    }
771
772    if (dgraph_init(&dgraph) != dgraph_valid) {
773        IOLog("Can't initialize dependency graph to load %s.\n",
774            kmod_name);
775        result = KERN_FAILURE;
776        goto finish;
777    }
778
779    free_dgraph = true;
780    if (!add_dependencies_for_kmod(kmod_name, &dgraph)) {
781        IOLog("Can't determine dependencies for %s.\n",
782            kmod_name);
783        result = KERN_FAILURE;
784        goto finish;
785    }
786
787    dgraph.root = dgraph_find_root(&dgraph);
788
789    if (!dgraph.root) {
790        IOLog("Dependency graph to load %s has no root.\n",
791            kmod_name);
792        result = KERN_FAILURE;
793        goto finish;
794    }
795
796   /* A kernel component is built in and need not be loaded.
797    */
798    if (dgraph.root->is_kernel_component) {
799        result = KERN_SUCCESS;
800        goto finish;
801    }
802
803    dgraph_establish_load_order(&dgraph);
804
805    load_result = kload_load_dgraph(&dgraph);
806    if (load_result != kload_error_none &&
807        load_result != kload_error_already_loaded) {
808
809        IOLog(VTYELLOW "Failed to load extension %s.\n" VTRESET, kmod_name);
810
811        result = KERN_FAILURE;
812        goto finish;
813    }
814
815finish:
816
817    if (free_dgraph) {
818        dgraph_free(&dgraph, 0 /* don't free dgraph itself */);
819    }
820    return result;
821}
822
823#define COM_APPLE  "com.apple."
824
825__private_extern__ void
826load_security_extensions (void)
827{
828    OSDictionary        * extensionsDict = NULL;  // don't release
829    OSCollectionIterator* keyIterator = NULL;     // must release
830    OSString            * key = NULL;             // don't release
831    OSDictionary        * extDict;                // don't release
832    OSDictionary        * extPlist;               // don't release
833    OSBoolean           * isSec = 0;              // don't release
834    Boolean             ret;
835
836    extensionsDict = getStartupExtensions();
837    if (!extensionsDict) {
838        IOLog("startup extensions dictionary is missing\n");
839        LOG_DELAY(1);
840        return;
841    }
842
843    keyIterator = OSCollectionIterator::withCollection(extensionsDict);
844    if (!keyIterator) {
845        IOLog("Error: Failed to allocate iterator for extensions.\n");
846        LOG_DELAY(1);
847        return;
848    }
849
850    while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
851
852        const char * bundle_id = key->getCStringNoCopy();
853
854       /* Skip extensions whose bundle IDs don't start with "com.apple.".
855        */
856        if (!bundle_id || (strncmp(bundle_id, COM_APPLE, strlen(COM_APPLE)) != 0)) {
857            continue;
858        }
859
860        extDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(key));
861        if (!extDict) {
862            IOLog("extension \"%s\" cannot be found\n",
863                  key->getCStringNoCopy());
864            continue;
865        }
866
867        extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
868        if (!extPlist) {
869            IOLog("extension \"%s\" has no info dictionary\n",
870                  key->getCStringNoCopy());
871            continue;
872        }
873
874        isSec = OSDynamicCast(OSBoolean,
875                             extPlist->getObject("AppleSecurityExtension"));
876        if (isSec && isSec->isTrue()) {
877            printf("Loading security extension %s\n", key->getCStringNoCopy());
878            ret = kmod_load_request(key->getCStringNoCopy(), false);
879            if (!ret) {
880                load_kernel_extension((char *)key->getCStringNoCopy());
881            }
882        }
883    }
884
885    if (keyIterator)
886        keyIterator->release();
887
888    return;
889}
890