Loading...
libsa/kext.cpp /dev/null xnu-1228.5.18
--- /dev/null
+++ xnu/xnu-1228.5.18/libsa/kext.cpp
@@ -0,0 +1,889 @@
+/*
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
+ * support for mandatory and extensible security protections.  This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ */
+
+#include <libkern/c++/OSContainers.h>
+#include <IOKit/IOCatalogue.h>
+#include <IOKit/IOLib.h>
+#include <libsa/kext.h>
+#include <libsa/catalogue.h>
+
+extern "C" {
+#include <mach-o/kld.h>
+#include <libsa/vers_rsrc.h>
+#include <libsa/stdlib.h>
+#include <mach/kmod.h>
+#include <vm/vm_kern.h>
+#include <mach/kern_return.h>
+#include <mach-o/fat.h>
+#include <mach_loader.h>
+
+#include "kld_patch.h"
+#include "dgraph.h"
+#include "load.h"
+};
+
+
+extern "C" {
+extern kern_return_t
+kmod_create_internal(
+            kmod_info_t *info,
+            kmod_t *id);
+
+extern kern_return_t
+kmod_destroy_internal(kmod_t id);
+
+extern kern_return_t
+kmod_start_or_stop(
+    kmod_t id,
+    int start,
+    kmod_args_t *data,
+    mach_msg_type_number_t *dataCount);
+
+extern kern_return_t kmod_retain(kmod_t id);
+extern kern_return_t kmod_release(kmod_t id);
+
+extern Boolean kmod_load_request(const char * moduleName, Boolean make_request);
+};
+
+extern kmod_args_t
+get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen);
+
+extern struct mac_module_data *osdict_encode(OSDictionary *dict);
+
+#define DEBUG
+#ifdef DEBUG
+#define LOG_DELAY(x)    IODelay((x) * 1000000)
+#define VTYELLOW  "\033[33m"
+#define VTRESET   "\033[0m"
+#else
+#define LOG_DELAY(x)
+#define VTYELLOW
+#define VTRESET
+#endif /* DEBUG */
+
+
+#define KERNEL_PREFIX  "com.apple.kernel"
+#define KPI_PREFIX     "com.apple.kpi"
+
+
+/*********************************************************************
+*
+*********************************************************************/
+static
+bool getKext(
+    const char * bundleid,
+    OSDictionary ** plist,
+    unsigned char ** code,
+    unsigned long * code_size,
+    bool * caller_owns_code)
+{
+    bool result = true;
+    OSDictionary * extensionsDict;   // don't release
+    OSDictionary * extDict;          // don't release
+    OSDictionary * extPlist;         // don't release
+    unsigned long code_size_local;
+
+   /* Get the dictionary of startup extensions.
+    * This is keyed by module name.
+    */
+    extensionsDict = getStartupExtensions();
+    if (!extensionsDict) {
+        IOLog("startup extensions dictionary is missing\n");
+        result = false;
+        goto finish;
+    }
+
+   /* Get the requested extension's dictionary entry and its property
+    * list, containing module dependencies.
+    */
+    extDict = OSDynamicCast(OSDictionary,
+        extensionsDict->getObject(bundleid));
+
+    if (!extDict) {
+        IOLog("extension \"%s\" cannot be found\n",
+           bundleid);
+        result = false;
+        goto finish;
+    }
+
+    if (plist) {
+        extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
+        if (!extPlist) {
+            IOLog("extension \"%s\" has no info dictionary\n",
+                bundleid);
+            result = false;
+            goto finish;
+        }
+        *plist = extPlist;
+    }
+
+    if (code) {
+
+       /* If asking for code, the caller must provide a return buffer
+        * for ownership!
+        */
+        if (!caller_owns_code) {
+            IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
+            result = false;
+            goto finish;
+        }
+    
+        *code = 0;
+        if (code_size) {
+            *code_size = 0;
+        }
+        *caller_owns_code = false;
+    
+        *code = (unsigned char *)kld_file_getaddr(bundleid,
+            (unsigned long *)&code_size_local);
+        if (*code) {
+            if (code_size) {
+                *code_size = code_size_local;
+            }
+        } else {
+            OSData * driverCode = 0; // release only if uncompressing!
+    
+            driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
+            if (driverCode) {
+                *code = (unsigned char *)driverCode->getBytesNoCopy();
+                if (code_size) {
+                    *code_size = driverCode->getLength();
+                }
+            } else { // Look for compressed code and uncompress it
+                OSData * compressedCode = 0;
+                compressedCode = OSDynamicCast(OSData,
+                    extDict->getObject("compressedCode"));
+                if (compressedCode) {
+                    if (!uncompressModule(compressedCode, &driverCode)) {
+                        IOLog("extension \"%s\": couldn't uncompress code\n",
+                            bundleid);
+                        result = false;
+                        goto finish;
+                    }
+                    *caller_owns_code = true;
+                    *code = (unsigned char *)driverCode->getBytesNoCopy();
+                    if (code_size) {
+                        *code_size = driverCode->getLength();
+                    }
+                    driverCode->release();
+                }
+            }
+        }
+    }
+
+finish:
+
+    return result;
+}
+
+
+/*********************************************************************
+*
+*********************************************************************/
+static
+bool verifyCompatibility(OSString * extName, OSString * requiredVersion)
+{
+    OSDictionary * extPlist;         // don't release
+    OSString     * extVersion;       // don't release
+    OSString     * extCompatVersion; // don't release
+    VERS_version ext_version;
+    VERS_version ext_compat_version;
+    VERS_version required_version;
+
+    if (!getKext(extName->getCStringNoCopy(), &extPlist, NULL, NULL, NULL)) {
+        return false;
+    }
+
+    extVersion = OSDynamicCast(OSString,
+        extPlist->getObject("CFBundleVersion"));
+    if (!extVersion) {
+        IOLog("verifyCompatibility(): "
+            "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
+            extName->getCStringNoCopy());
+        return false;
+    }
+
+    extCompatVersion = OSDynamicCast(OSString,
+        extPlist->getObject("OSBundleCompatibleVersion"));
+    if (!extCompatVersion) {
+        IOLog("verifyCompatibility(): "
+            "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
+            extName->getCStringNoCopy());
+        return false;
+    }
+
+    required_version = VERS_parse_string(requiredVersion->getCStringNoCopy());
+    if (required_version < 0) {
+        IOLog("verifyCompatibility(): "
+            "Can't parse required version \"%s\" of dependency %s.\n",
+            requiredVersion->getCStringNoCopy(),
+            extName->getCStringNoCopy());
+        return false;
+    }
+    ext_version = VERS_parse_string(extVersion->getCStringNoCopy());
+    if (ext_version < 0) {
+        IOLog("verifyCompatibility(): "
+            "Can't parse version \"%s\" of dependency %s.\n",
+            extVersion->getCStringNoCopy(),
+            extName->getCStringNoCopy());
+        return false;
+    }
+    ext_compat_version = VERS_parse_string(extCompatVersion->getCStringNoCopy());
+    if (ext_compat_version < 0) {
+        IOLog("verifyCompatibility(): "
+            "Can't parse compatible version \"%s\" of dependency %s.\n",
+            extCompatVersion->getCStringNoCopy(),
+            extName->getCStringNoCopy());
+        return false;
+    }
+
+    if (required_version > ext_version || required_version < ext_compat_version) {
+        return false;
+    }
+
+    return true;
+}
+
+/*********************************************************************
+*********************************************************************/
+static
+bool kextIsDependency(const char * kext_name, char * is_kernel) {
+    bool result = true;
+    OSDictionary * extensionsDict = 0;    // don't release
+    OSDictionary * extDict = 0;           // don't release
+    OSDictionary * extPlist = 0;          // don't release
+    OSBoolean * isKernelResourceObj = 0;  // don't release
+    OSData * driverCode = 0;              // don't release
+    OSData * compressedCode = 0;          // don't release
+
+    if (is_kernel) {
+        *is_kernel = 0;
+    }
+
+   /* Get the dictionary of startup extensions.
+    * This is keyed by module name.
+    */
+    extensionsDict = getStartupExtensions();
+    if (!extensionsDict) {
+        IOLog("startup extensions dictionary is missing\n");
+        result = false;
+        goto finish;
+    }
+
+   /* Get the requested extension's dictionary entry and its property
+    * list, containing module dependencies.
+    */
+    extDict = OSDynamicCast(OSDictionary,
+        extensionsDict->getObject(kext_name));
+
+    if (!extDict) {
+        IOLog("extension \"%s\" cannot be found\n",
+           kext_name);
+        result = false;
+        goto finish;
+    }
+
+    extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
+    if (!extPlist) {
+        IOLog("extension \"%s\" has no info dictionary\n",
+            kext_name);
+        result = false;
+        goto finish;
+    }
+
+   /* A kext that is a kernel component is still a dependency, as there
+    * are fake kmod entries for them.
+    */
+    isKernelResourceObj = OSDynamicCast(OSBoolean,
+        extPlist->getObject("OSKernelResource"));
+    if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
+        if (is_kernel) {
+            *is_kernel = 1;
+        }
+    }
+
+    driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
+    compressedCode = OSDynamicCast(OSData,
+        extDict->getObject("compressedCode"));
+
+   /* A kernel component that has code represents a KPI.
+    */
+    if ((driverCode || compressedCode) && is_kernel && *is_kernel) {
+        *is_kernel = 2;
+    }
+
+    if (!driverCode && !compressedCode && !isKernelResourceObj) {
+        result = false;
+        goto finish;
+    }
+
+finish:
+
+    return result;
+}
+
+/*********************************************************************
+*********************************************************************/
+static bool
+addDependenciesForKext(OSDictionary * kextPlist,
+    OSArray   * dependencyList,
+    OSString * trueParent,
+    Boolean    skipKernelDependencies)
+{
+    bool result = true;
+    bool hasDirectKernelDependency = false;
+    bool hasKernelStyleDependency = false;
+    bool hasKPIStyleDependency = false;
+    OSString * kextName = 0;  // don't release
+    OSDictionary * libraries = 0;  // don't release
+    OSCollectionIterator * keyIterator = 0; // must release
+    OSString * libraryName = 0; // don't release
+    OSString * dependentName = 0; // don't release
+
+    kextName = OSDynamicCast(OSString,
+        kextPlist->getObject("CFBundleIdentifier"));
+    if (!kextName) {
+        // XXX: Add log message
+        result = false;
+        goto finish;
+    }
+
+    libraries = OSDynamicCast(OSDictionary,
+        kextPlist->getObject("OSBundleLibraries"));
+    if (!libraries) {
+        result = true;
+        goto finish;
+    }
+
+    keyIterator = OSCollectionIterator::withCollection(libraries);
+    if (!keyIterator) {
+        // XXX: Add log message
+        result = false;
+        goto finish;
+    }
+
+    dependentName = trueParent ? trueParent : kextName;
+
+    while ( (libraryName = OSDynamicCast(OSString,
+        keyIterator->getNextObject())) ) {
+
+        OSString * libraryVersion = OSDynamicCast(OSString,
+            libraries->getObject(libraryName));
+        if (!libraryVersion) {
+            // XXX: Add log message
+            result = false;
+            goto finish;
+        }
+        if (!verifyCompatibility(libraryName, libraryVersion)) {
+            result = false;
+            goto finish;
+        } else {
+            char is_kernel_component;
+
+            if (!kextIsDependency(libraryName->getCStringNoCopy(),
+                &is_kernel_component)) {
+
+                is_kernel_component = 0;
+            }
+
+            if (!skipKernelDependencies || !is_kernel_component) {
+                dependencyList->setObject(dependentName);
+                dependencyList->setObject(libraryName);
+            }
+            if (!hasDirectKernelDependency && is_kernel_component) {
+                hasDirectKernelDependency = true;
+            }
+
+           /* We already know from the kextIsDependency() call whether
+            * the dependency *itself* is kernel- or KPI-style, but since
+            * the declaration semantic is by bundle ID, we check that here
+            * instead.
+            */
+            if (strncmp(libraryName->getCStringNoCopy(),
+                KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0) {
+
+                hasKernelStyleDependency = true;
+
+            } else if (strncmp(libraryName->getCStringNoCopy(),
+                KPI_PREFIX, strlen(KPI_PREFIX)) == 0) {
+
+                hasKPIStyleDependency = true;
+            }
+        }
+    }
+
+    if (!hasDirectKernelDependency) {
+        const OSSymbol * kernelName = 0;
+
+        /* a kext without any kernel dependency is assumed dependent on 6.0 */
+        dependencyList->setObject(dependentName);
+
+        kernelName = OSSymbol::withCString("com.apple.kernel.libkern");
+        if (!kernelName) {
+            // XXX: Add log message
+            result = false;
+            goto finish;
+        }
+        dependencyList->setObject(kernelName);
+        kernelName->release();
+
+        IOLog("Extension \"%s\" has no explicit kernel dependency; using version 6.0.\n",
+            kextName->getCStringNoCopy());
+
+    } else if (hasKernelStyleDependency && hasKPIStyleDependency) {
+        IOLog("Extension \"%s\" has immediate dependencies "
+            "on both com.apple.kernel and com.apple.kpi components; use only one style.\n",
+            kextName->getCStringNoCopy());
+    }
+
+finish:
+    if (keyIterator) keyIterator->release();
+    return result;
+}
+
+/*********************************************************************
+*********************************************************************/
+static
+bool getVersionForKext(OSDictionary * kextPlist, char ** version)
+{
+    OSString * kextName = 0;  // don't release
+    OSString * kextVersion;       // don't release
+
+    kextName = OSDynamicCast(OSString,
+        kextPlist->getObject("CFBundleIdentifier"));
+    if (!kextName) {
+        // XXX: Add log message
+        return false;
+    }
+
+    kextVersion = OSDynamicCast(OSString,
+        kextPlist->getObject("CFBundleVersion"));
+    if (!kextVersion) {
+        IOLog("getVersionForKext(): "
+            "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
+            kextName->getCStringNoCopy());
+        return false;
+    }
+
+    if (version) {
+        *version = (char *)kextVersion->getCStringNoCopy();
+    }
+
+    return true;
+}
+
+/*********************************************************************
+*********************************************************************/
+static
+bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
+{
+    bool result = true;
+    OSDictionary * kextPlist = 0; // don't release
+    unsigned int index = 0;
+    OSArray * dependencyList = 0;  // must release
+    unsigned char * code = 0;
+    unsigned long code_length = 0;
+    bool code_is_kmem = false;
+    char * kmod_vers = 0; // from plist, don't free
+    char is_kernel_component = 0;
+    dgraph_entry_t * dgraph_entry = 0; // don't free
+    dgraph_entry_t * dgraph_dependency = 0; // don't free
+    bool kext_is_dependency = true;
+
+#if CONFIG_MACF_KEXT
+    kmod_args_t user_data = 0;
+    mach_msg_type_number_t user_data_length;
+#endif
+
+   /*****
+    * Set up the root kmod.
+    */
+    if (!getKext(kmod_name, &kextPlist, &code, &code_length,
+        &code_is_kmem)) {
+        IOLog("can't find extension %s\n", kmod_name);
+        result = false;
+        goto finish;
+    }
+
+    if (!kextIsDependency(kmod_name, &is_kernel_component)) {
+        IOLog("extension %s is not loadable\n", kmod_name);
+        result = false;
+        goto finish;
+    }
+
+    if (!getVersionForKext(kextPlist, &kmod_vers)) {
+        IOLog("can't get version for extension %s\n", kmod_name);
+        result = false;
+        goto finish;
+    }
+
+#if CONFIG_MACF_KEXT
+    // check kext for module data in the plist
+    user_data = get_module_data(kextPlist, &user_data_length);
+#endif
+
+    dgraph_entry = dgraph_add_dependent(dgraph, kmod_name,
+        code, code_length, code_is_kmem,
+#if CONFIG_MACF_KEXT
+        user_data, user_data_length,
+#endif
+        kmod_name, kmod_vers,
+        0 /* load_address not yet known */, is_kernel_component);
+    if (!dgraph_entry) {
+        IOLog("can't record %s in dependency graph\n", kmod_name);
+        result = false;
+        // kmem_alloc()ed code is freed in finish: block.
+        goto finish;
+    }
+
+    // pass ownership of code to kld patcher
+    if (code) {
+        if (kload_map_entry(dgraph_entry) != kload_error_none) {
+            IOLog("can't map %s in preparation for loading\n", kmod_name);
+            result = false;
+            // kmem_alloc()ed code is freed in finish: block.
+           goto finish;
+        }
+    }
+    // clear local record of code
+    code = 0;
+    code_length = 0;
+    code_is_kmem = false;
+
+   /*****
+    * Now handle all the dependencies.
+    */
+    dependencyList = OSArray::withCapacity(5);
+    if (!dependencyList) {
+        IOLog("memory allocation failure\n");
+        result = false;
+        goto finish;
+    }
+
+    index = 0;
+    if (!addDependenciesForKext(kextPlist, dependencyList, NULL, false)) {
+        IOLog("can't determine immediate dependencies for extension %s\n",
+            kmod_name);
+        result = false;
+        goto finish;
+    }
+
+   /* IMPORTANT: loop condition gets list count every time through, as the
+    * array CAN change each iteration.
+    */
+    for (index = 0; index < dependencyList->getCount(); index += 2) {
+        OSString * dependentName = 0;
+        OSString * libraryName = 0;
+        const char * dependent_name = 0;
+        const char * library_name = 0;
+
+       /* 255 is an arbitrary limit. Multiplied  by 2 because the dependency
+        * list is stocked with pairs (dependent -> dependency).
+        */
+        if (index > (2 * 255)) {
+            IOLog("extension dependency graph ridiculously long, indicating a loop\n");
+            result = false;
+            goto finish;
+        }
+
+        dependentName = OSDynamicCast(OSString,
+            dependencyList->getObject(index));
+        libraryName = OSDynamicCast(OSString,
+            dependencyList->getObject(index + 1));
+
+        if (!dependentName || !libraryName) {
+            IOLog("malformed dependency list\n");
+            result = false;
+            goto finish;
+        }
+
+        dependent_name = dependentName->getCStringNoCopy();
+        library_name = libraryName->getCStringNoCopy();
+
+        if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
+
+            IOLog("can't find extension %s\n", library_name);
+            result = false;
+            goto finish;
+        }
+
+        OSString * string = OSDynamicCast(OSString,
+            kextPlist->getObject("OSBundleSharedExecutableIdentifier"));
+        if (string) {
+            library_name = string->getCStringNoCopy();
+            if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
+                IOLog("can't find extension %s\n", library_name);
+                result = false;
+                goto finish;
+            }
+        }
+
+        kext_is_dependency = kextIsDependency(library_name,
+            &is_kernel_component);
+
+        if (kext_is_dependency) {
+                dgraph_entry = dgraph_find_dependent(dgraph, dependent_name);
+                if (!dgraph_entry) {
+                    IOLog("internal error with dependency graph\n");
+                    LOG_DELAY(1);
+                    result = false;
+                    goto finish;
+                }
+
+                if (!getVersionForKext(kextPlist, &kmod_vers)) {
+                    IOLog("can't get version for extension %s\n", library_name);
+                    result = false;
+                    goto finish;
+                }
+
+               /* It's okay for code to be zero, as for a pseudokext
+                * representing a kernel component.
+                */
+                if (!getKext(library_name, NULL /* already got it */,
+                    &code, &code_length, &code_is_kmem)) {
+                    IOLog("can't find extension %s\n", library_name);
+                    result = false;
+                    goto finish;
+                }
+
+#if CONFIG_MACF_KEXT
+                // check kext for module data in the plist
+                // XXX - is this really needed?
+                user_data = get_module_data(kextPlist, &user_data_length);
+#endif
+                dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry,
+                    library_name, code, code_length, code_is_kmem,
+#if CONFIG_MACF_KEXT
+                    user_data, user_data_length,
+#endif
+                    library_name, kmod_vers,
+                    0 /* load_address not yet known */, is_kernel_component);
+
+                if (!dgraph_dependency) {
+                    IOLog("can't record dependency %s -> %s\n", dependent_name,
+                        library_name);
+                    result = false;
+                    // kmem_alloc()ed code is freed in finish: block.
+                    goto finish;
+                }
+
+                // pass ownership of code to kld patcher
+                if (code) {
+                    if (kload_map_entry(dgraph_dependency) != kload_error_none) {
+                        IOLog("can't map %s in preparation for loading\n", library_name);
+                        result = false;
+                        // kmem_alloc()ed code is freed in finish: block.
+                        goto finish;
+                    }
+                }
+                // clear local record of code
+                code = 0;
+                code_length = 0;
+                code_is_kmem = false;
+            }
+
+           /* Now put the library's dependencies onto the pending set.
+            */
+            if (!addDependenciesForKext(kextPlist, dependencyList,
+                kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) {
+
+                IOLog("can't determine immediate dependencies for extension %s\n",
+                    library_name);
+                result = false;
+                goto finish;
+            }
+        }
+
+finish:
+    if (code && code_is_kmem) {
+        kmem_free(kernel_map, (unsigned int)code, code_length);
+    }
+    if (dependencyList)  dependencyList->release();
+
+#if CONFIG_MACF_KEXT
+    if (user_data && !result) {
+        vm_map_copy_discard((vm_map_copy_t)user_data);
+    }
+#endif
+
+    return result;
+}
+
+/*********************************************************************
+* This is the function that IOCatalogue calls in order to load a kmod.
+* It first checks whether the kmod is already loaded. If the kmod
+* isn't loaded, this function builds a dependency list and calls
+* load_kmod() repeatedly to guarantee that each dependency is in fact
+* loaded.
+*********************************************************************/
+__private_extern__
+kern_return_t load_kernel_extension(char * kmod_name)
+{
+    kern_return_t result = KERN_SUCCESS;
+    kload_error load_result = kload_error_none;
+    dgraph_t dgraph;
+    bool free_dgraph = false;
+    kmod_info_t * kmod_info;
+
+// Put this in for lots of messages about kext loading.
+#if 0
+    kload_set_log_level(kload_log_level_load_details);
+#endif
+
+   /* See if the kmod is already loaded.
+    */
+    if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) {
+        kfree(kmod_info, sizeof(kmod_info_t));
+        return KERN_SUCCESS;
+    }
+
+    if (dgraph_init(&dgraph) != dgraph_valid) {
+        IOLog("Can't initialize dependency graph to load %s.\n",
+            kmod_name);
+        result = KERN_FAILURE;
+        goto finish;
+    }
+
+    free_dgraph = true;
+    if (!add_dependencies_for_kmod(kmod_name, &dgraph)) {
+        IOLog("Can't determine dependencies for %s.\n",
+            kmod_name);
+        result = KERN_FAILURE;
+        goto finish;
+    }
+
+    dgraph.root = dgraph_find_root(&dgraph);
+
+    if (!dgraph.root) {
+        IOLog("Dependency graph to load %s has no root.\n",
+            kmod_name);
+        result = KERN_FAILURE;
+        goto finish;
+    }
+
+   /* A kernel component is built in and need not be loaded.
+    */
+    if (dgraph.root->is_kernel_component) {
+        result = KERN_SUCCESS;
+        goto finish;
+    }
+
+    dgraph_establish_load_order(&dgraph);
+
+    load_result = kload_load_dgraph(&dgraph);
+    if (load_result != kload_error_none &&
+        load_result != kload_error_already_loaded) {
+
+        IOLog(VTYELLOW "Failed to load extension %s.\n" VTRESET, kmod_name);
+
+        result = KERN_FAILURE;
+        goto finish;
+    }
+
+finish:
+
+    if (free_dgraph) {
+        dgraph_free(&dgraph, 0 /* don't free dgraph itself */);
+    }
+    return result;
+}
+
+#define COM_APPLE  "com.apple."
+
+__private_extern__ void
+load_security_extensions (void)
+{
+    OSDictionary        * extensionsDict = NULL;  // don't release
+    OSCollectionIterator* keyIterator = NULL;     // must release
+    OSString            * key = NULL;             // don't release
+    OSDictionary        * extDict;                // don't release
+    OSDictionary        * extPlist;               // don't release
+    OSBoolean           * isSec = 0;              // don't release
+    Boolean             ret;
+
+    extensionsDict = getStartupExtensions();
+    if (!extensionsDict) {
+        IOLog("startup extensions dictionary is missing\n");
+        LOG_DELAY(1);
+        return;
+    }
+
+    keyIterator = OSCollectionIterator::withCollection(extensionsDict);
+    if (!keyIterator) {
+        IOLog("Error: Failed to allocate iterator for extensions.\n");
+        LOG_DELAY(1);
+        return;
+    }
+
+    while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
+
+        const char * bundle_id = key->getCStringNoCopy();
+        
+       /* Skip extensions whose bundle IDs don't start with "com.apple.".
+        */
+        if (!bundle_id || (strncmp(bundle_id, COM_APPLE, strlen(COM_APPLE)) != 0)) {
+            continue;
+        }
+
+        extDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(key));
+        if (!extDict) {
+            IOLog("extension \"%s\" cannot be found\n",
+                  key->getCStringNoCopy());
+            continue;
+        }
+
+        extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
+        if (!extPlist) {
+            IOLog("extension \"%s\" has no info dictionary\n",
+                  key->getCStringNoCopy());
+            continue;
+        }
+
+        isSec = OSDynamicCast(OSBoolean,
+                             extPlist->getObject("AppleSecurityExtension"));
+        if (isSec && isSec->isTrue()) {
+            printf("Loading security extension %s\n", key->getCStringNoCopy());
+            ret = kmod_load_request(key->getCStringNoCopy(), false);
+            if (!ret) {
+                load_kernel_extension((char *)key->getCStringNoCopy());
+            }
+        }
+    }
+
+    if (keyIterator)
+        keyIterator->release();
+
+    return;
+}