The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libsa/kext.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   42 extern "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 
   58 extern "C" {
   59 extern kern_return_t
   60 kmod_create_internal(
   61             kmod_info_t *info,
   62             kmod_t *id);
   63 
   64 extern kern_return_t
   65 kmod_destroy_internal(kmod_t id);
   66 
   67 extern kern_return_t
   68 kmod_start_or_stop(
   69     kmod_t id,
   70     int start,
   71     kmod_args_t *data,
   72     mach_msg_type_number_t *dataCount);
   73 
   74 extern kern_return_t kmod_retain(kmod_t id);
   75 extern kern_return_t kmod_release(kmod_t id);
   76 
   77 extern Boolean kmod_load_request(const char * moduleName, Boolean make_request);
   78 };
   79 
   80 extern kmod_args_t
   81 get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen);
   82 
   83 extern 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 *********************************************************************/
  104 static
  105 bool 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 
  206 finish:
  207 
  208     return result;
  209 }
  210 
  211 
  212 /*********************************************************************
  213 *
  214 *********************************************************************/
  215 static
  216 bool 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 *********************************************************************/
  281 static
  282 bool 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 
  352 finish:
  353 
  354     return result;
  355 }
  356 
  357 /*********************************************************************
  358 *********************************************************************/
  359 static bool
  360 addDependenciesForKext(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 
  471 finish:
  472     if (keyIterator) keyIterator->release();
  473     return result;
  474 }
  475 
  476 /*********************************************************************
  477 *********************************************************************/
  478 static
  479 bool 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 *********************************************************************/
  509 static
  510 bool 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 
  729 finish:
  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__
  752 kern_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 
  815 finish:
  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
  826 load_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 }

Cache object: a9f92b0650985d2c2b6633b816e34d07


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.