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/libkern/OSKextLib.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) 2008 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 extern "C" {
   30 #include <libkern/OSKextLibPrivate.h>
   31 #include <libkern/mkext.h>
   32 };
   33 
   34 #include <libkern/c++/OSContainers.h>
   35 #include <libkern/c++/OSKext.h>
   36 #include <libkern/OSKextLib.h>
   37 #include <libkern/OSKextLibPrivate.h>
   38 
   39 extern "C" {
   40 
   41 #if PRAGMA_MARK
   42 #pragma mark C-based kext interface (loading/loaded kexts only)
   43 #endif
   44 /*********************************************************************
   45 *********************************************************************/
   46 kern_return_t OSKextLoadKextWithIdentifier(const char * bundle_id)
   47 {
   48     return OSKext::loadKextWithIdentifier(bundle_id);
   49 }
   50 
   51 /*********************************************************************
   52 *********************************************************************/
   53 uint32_t
   54 OSKextGetLoadTagForIdentifier(const char * kextIdentifier)
   55 {
   56     uint32_t result  = kOSKextInvalidLoadTag;
   57     OSKext * theKext = NULL;  // must release
   58 
   59     if (!kextIdentifier) {
   60         goto finish;
   61     }
   62 
   63     theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
   64     if (theKext && theKext->isLoaded()) {
   65         result = theKext->getLoadTag();
   66     }
   67 finish:
   68     if (theKext) theKext->release();
   69     return result;
   70 }
   71 
   72 /*********************************************************************
   73 *********************************************************************/
   74 OSReturn OSKextRetainKextWithLoadTag(uint32_t loadTag)
   75 {
   76     OSReturn   result = kOSKextReturnNotFound;
   77     OSKext   * theKext = NULL;  // do not release; as this function is a retain
   78 
   79     if (loadTag == kOSKextInvalidLoadTag) {
   80         result = kOSKextReturnInvalidArgument;
   81         goto finish;
   82     }
   83     theKext = OSKext::lookupKextWithLoadTag(loadTag);
   84     if (theKext) {
   85         result = kOSReturnSuccess;
   86 
   87         OSKextLog(theKext,
   88             kOSKextLogDebugLevel |
   89             kOSKextLogKextBookkeepingFlag,
   90             "Kext %s (load tag %d) has been retained.",
   91             theKext->getIdentifierCString(),
   92             loadTag);
   93 
   94        /* Call this after so a log message about autounload comes second.
   95         */
   96         theKext->setAutounloadEnabled(true);
   97     } else {
   98         OSKextLog(theKext,
   99             kOSKextLogErrorLevel |
  100             kOSKextLogKextBookkeepingFlag,
  101             "Can't retain kext with load tag %d - no such kext is loaded.",
  102            loadTag);
  103     }
  104 finish:
  105     return result;
  106 }
  107 
  108 /*********************************************************************
  109 *********************************************************************/
  110 OSReturn OSKextReleaseKextWithLoadTag(uint32_t loadTag)
  111 {
  112     OSReturn result  = kOSKextReturnNotFound;
  113     OSKext * theKext = NULL;  // must release twice!
  114     
  115     if (loadTag == kOSKextInvalidLoadTag) {
  116         result = kOSKextReturnInvalidArgument;
  117         goto finish;
  118     }
  119     theKext = OSKext::lookupKextWithLoadTag(loadTag);
  120     if (theKext) {
  121         result = kOSReturnSuccess;
  122         OSKext::considerUnloads();  // schedule autounload pass
  123         theKext->release();  // do the release the caller wants
  124         theKext->release();  // now do the release on the lookup
  125         OSKextLog(theKext,
  126             kOSKextLogDebugLevel |
  127             kOSKextLogKextBookkeepingFlag,
  128             "Kext %s (load tag %d) has been released.",
  129             theKext->getIdentifierCString(),
  130             loadTag);
  131     } else {
  132         OSKextLog(theKext,
  133             kOSKextLogErrorLevel |
  134             kOSKextLogKextBookkeepingFlag,
  135             "Can't release kext with load tag %d - no such kext is loaded.",
  136            loadTag);
  137     }
  138     
  139     // xxx - should I check that the refcount of the OSKext is above the lower bound?
  140     // xxx - do we want a OSKextGetRetainCountOfKextWithLoadTag()?
  141 finish:
  142     return result;
  143 }
  144 
  145 /*********************************************************************
  146 * Not to be called by the kext being unloaded!
  147 *********************************************************************/
  148 OSReturn OSKextUnloadKextWithLoadTag(uint32_t loadTag)
  149 {
  150     return OSKext::removeKextWithLoadTag(loadTag,
  151         /* terminateServicesAndRemovePersonalitiesFlag */ false);
  152 }
  153 
  154 
  155 #if PRAGMA_MARK
  156 #pragma mark Kext Requests
  157 #endif
  158 /*********************************************************************
  159 * Kext Requests
  160 *********************************************************************/
  161 OSReturn OSKextRequestResource(
  162     const char                    * kextIdentifier,
  163     const char                    * resourceName,
  164     OSKextRequestResourceCallback   callback,
  165     void                          * context,
  166     OSKextRequestTag              * requestTagOut)
  167 {
  168     return OSKext::requestResource(kextIdentifier, resourceName,
  169         callback, context, requestTagOut);
  170 }
  171 
  172 /*********************************************************************
  173 *********************************************************************/
  174 OSReturn OSKextCancelRequest(
  175     OSKextRequestTag    requestTag,
  176     void             ** contextOut)
  177 {
  178     return OSKext::cancelRequest(requestTag, contextOut);
  179 }
  180 
  181 #if PRAGMA_MARK
  182 #pragma mark MIG Functions & Wrappers
  183 #endif
  184 /*********************************************************************
  185 * IMPORTANT: Once we have done the vm_map_copyout(), we *must* return
  186 * KERN_SUCCESS or the kernel map gets messed up (reason as yet
  187 * unknown). We use op_result to return the real result of our work.
  188 *********************************************************************/
  189 kern_return_t kext_request(
  190     host_priv_t                             hostPriv,
  191     /* in only */  uint32_t                 clientLogSpec,
  192     /* in only */  vm_offset_t              requestIn,
  193     /* in only */  mach_msg_type_number_t   requestLengthIn,
  194     /* out only */ vm_offset_t            * responseOut,
  195     /* out only */ mach_msg_type_number_t * responseLengthOut,
  196     /* out only */ vm_offset_t            * logDataOut,
  197     /* out only */ mach_msg_type_number_t * logDataLengthOut,
  198     /* out only */ kern_return_t          * op_result)
  199 {
  200     kern_return_t     result          = KERN_FAILURE;
  201     vm_map_address_t  map_addr        = 0;     // do not free/deallocate
  202     char            * request         = NULL;  // must vm_deallocate
  203 
  204     mkext2_header   * mkextHeader     = NULL;  // do not release
  205     bool              isMkext         = false;
  206 
  207     char            * response        = NULL;  // must kmem_free
  208     uint32_t          responseLength  = 0;
  209     char            * logData         = NULL;  // must kmem_free
  210     uint32_t          logDataLength   = 0;
  211 
  212    /* MIG doesn't pass "out" parameters as empty, so clear them immediately
  213     * just in case, or MIG will try to copy out bogus data.
  214     */    
  215     *op_result = KERN_FAILURE;
  216     *responseOut = NULL;
  217     *responseLengthOut = 0;
  218     *logDataOut = NULL;
  219     *logDataLengthOut = 0;
  220 
  221    /* Check for input. Don't discard what isn't there, though.
  222     */
  223     if (!requestLengthIn || !requestIn) {
  224                 OSKextLog(/* kext */ NULL,
  225             kOSKextLogErrorLevel |
  226             kOSKextLogIPCFlag,
  227             "Invalid request from user space (no data).");
  228         *op_result = KERN_INVALID_ARGUMENT;
  229         goto finish;
  230     }
  231 
  232    /* Once we have done the vm_map_copyout(), we *must* return KERN_SUCCESS
  233     * or the kernel map gets messed up (reason as yet unknown). We will use
  234     * op_result to return the real result of our work.
  235     */
  236     result = vm_map_copyout(kernel_map, &map_addr, (vm_map_copy_t)requestIn);
  237     if (result != KERN_SUCCESS) {
  238         OSKextLog(/* kext */ NULL,
  239             kOSKextLogErrorLevel |
  240             kOSKextLogIPCFlag,
  241             "vm_map_copyout() failed for request from user space.");
  242         vm_map_copy_discard((vm_map_copy_t)requestIn);
  243         goto finish;
  244     }
  245     request = CAST_DOWN(char *, map_addr);
  246 
  247    /* Check if request is an mkext; this is always a load request
  248     * and requires root access. If it isn't an mkext, see if it's
  249     * an XML request, and check the request to see if that requires
  250     * root access.
  251     */
  252     if (requestLengthIn > sizeof(mkext2_header)) {
  253         mkextHeader = (mkext2_header *)request;
  254         if (MKEXT_GET_MAGIC(mkextHeader) == MKEXT_MAGIC &&
  255             MKEXT_GET_SIGNATURE(mkextHeader) == MKEXT_SIGN) {
  256 
  257             isMkext = true;
  258         }
  259     }
  260 
  261     if (isMkext) {
  262 #ifdef SECURE_KERNEL
  263         // xxx - something tells me if we have a secure kernel we don't even
  264         // xxx - want to log a message here. :-)
  265         *op_result = KERN_NOT_SUPPORTED;
  266         goto finish;
  267 #else
  268         // xxx - can we find out if calling task is kextd?
  269         // xxx - can we find the name of the calling task?
  270         if (hostPriv == HOST_PRIV_NULL) {
  271             OSKextLog(/* kext */ NULL,
  272                 kOSKextLogErrorLevel |
  273                 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
  274                 "Attempt by non-root process to load a kext.");
  275             *op_result = kOSKextReturnNotPrivileged;
  276             goto finish;
  277         }
  278 
  279         *op_result = OSKext::loadFromMkext((OSKextLogSpec)clientLogSpec,
  280             request, requestLengthIn,
  281             &logData, &logDataLength);
  282 
  283 #endif /* defined(SECURE_KERNEL) */
  284 
  285     } else {
  286 
  287        /* If the request isn't an mkext, then is should be XML. Parse it
  288         * if possible and hand the request over to OSKext.
  289         */
  290         *op_result = OSKext::handleRequest(hostPriv,
  291             (OSKextLogSpec)clientLogSpec,
  292             request, requestLengthIn,
  293             &response, &responseLength,
  294             &logData, &logDataLength);
  295     }
  296 
  297     if (response && responseLength > 0) {
  298         kern_return_t copyin_result;
  299 
  300         copyin_result = vm_map_copyin(kernel_map,
  301             CAST_USER_ADDR_T(response), responseLength,
  302             /* src_destroy */ false, (vm_map_copy_t *)responseOut);
  303         if (copyin_result == KERN_SUCCESS) {
  304             *responseLengthOut = responseLength;
  305         } else {
  306             OSKextLog(/* kext */ NULL,
  307                 kOSKextLogErrorLevel |
  308                 kOSKextLogIPCFlag,
  309                 "Failed to copy response to request from user space.");
  310             *op_result = copyin_result;  // xxx - should we map to our own code?
  311             *responseOut = NULL;
  312             *responseLengthOut = 0;
  313             goto finish;
  314         }
  315     }
  316 
  317     if (logData && logDataLength > 0) {
  318         kern_return_t copyin_result;
  319 
  320         copyin_result = vm_map_copyin(kernel_map,
  321             CAST_USER_ADDR_T(logData), logDataLength,
  322             /* src_destroy */ false, (vm_map_copy_t *)logDataOut);
  323         if (copyin_result == KERN_SUCCESS) {
  324             *logDataLengthOut = logDataLength;
  325         } else {
  326             OSKextLog(/* kext */ NULL,
  327                 kOSKextLogErrorLevel |
  328                 kOSKextLogIPCFlag,
  329                 "Failed to copy log data for request from user space.");
  330             *op_result = copyin_result;  // xxx - should we map to our own code?
  331             *logDataOut = NULL;
  332             *logDataLengthOut = 0;
  333             goto finish;
  334         }
  335     }
  336 
  337 finish:
  338     if (request) {
  339         (void)vm_deallocate(kernel_map, (vm_offset_t)request, requestLengthIn);
  340     }
  341     if (response) {
  342         kmem_free(kernel_map, (vm_offset_t)response, responseLength);
  343     }
  344     if (logData) {
  345         kmem_free(kernel_map, (vm_offset_t)logData, logDataLength);
  346     }
  347 
  348     return result;
  349 }
  350 
  351 /*********************************************************************
  352 * Gets the vm_map for the current kext
  353 *********************************************************************/
  354 extern vm_offset_t sectPRELINKB;
  355 extern int sectSizePRELINK;
  356 extern int kth_started;
  357 extern vm_map_t g_kext_map;
  358 
  359 vm_map_t
  360 kext_get_vm_map(kmod_info_t *info)
  361 {
  362     vm_map_t kext_map = NULL;
  363 
  364     /* Set the vm map */
  365     if ((info->address >= sectPRELINKB) && 
  366             (info->address < (sectPRELINKB + sectSizePRELINK)))
  367     {
  368         kext_map = kernel_map;
  369     } else {
  370         kext_map = g_kext_map;
  371     }
  372 
  373     return kext_map;
  374 }
  375 
  376 
  377 #if PRAGMA_MARK
  378 /********************************************************************/
  379 #pragma mark Weak linking support
  380 /********************************************************************/
  381 #endif
  382 void
  383 kext_weak_symbol_referenced(void)
  384 {
  385     panic("A kext referenced an unresolved weak symbol\n");
  386 }
  387 
  388 const void *gOSKextUnresolved = (const void *)&kext_weak_symbol_referenced;
  389 
  390 #if PRAGMA_MARK
  391 #pragma mark Kernel-Internal C Functions
  392 #endif
  393 /*********************************************************************
  394 * Called from startup.c.
  395 *********************************************************************/
  396 void OSKextRemoveKextBootstrap(void)
  397 {
  398     OSKext::removeKextBootstrap();
  399     return;
  400 }
  401 
  402 #if CONFIG_DTRACE
  403 /*********************************************************************
  404 *********************************************************************/
  405 void OSKextRegisterKextsWithDTrace(void)
  406 {
  407     OSKext::registerKextsWithDTrace();
  408     return;
  409 }
  410 #endif /* CONFIG_DTRACE */
  411 
  412 /*********************************************************************
  413 *********************************************************************/
  414 void kext_dump_panic_lists(int (*printf_func)(const char * fmt, ...))
  415 {
  416     OSKext::printKextPanicLists(printf_func);
  417     return;
  418 }
  419 
  420 #if PRAGMA_MARK
  421 #pragma mark Kmod Compatibility Functions
  422 #endif
  423 /*********************************************************************
  424 **********************************************************************
  425 *                    KMOD COMPATIBILITY FUNCTIONS                    *
  426 *              (formerly in kmod.c, or C++ bridges from)             *
  427 **********************************************************************
  428 **********************************************************************
  429 * These two functions are used in various places in the kernel, but
  430 * are not exported. We might rename them at some point to start with
  431 * kext_ or OSKext.
  432 *
  433 * kmod_panic_dump() must not be called outside of a panic context.
  434 * kmod_dump_log() must not be called in a panic context.
  435 *********************************************************************/
  436 void
  437 kmod_panic_dump(vm_offset_t * addr, unsigned int cnt)
  438 {
  439     extern int kdb_printf(const char *format, ...) __printflike(1,2);
  440 
  441     OSKext::printKextsInBacktrace(addr, cnt, &kdb_printf,
  442         /* takeLock? */ false);
  443     return;
  444 }
  445 
  446 /********************************************************************/
  447 void kmod_dump_log(vm_offset_t *addr, unsigned int cnt);
  448 
  449 void
  450 kmod_dump_log(
  451     vm_offset_t * addr,
  452     unsigned int cnt)
  453 {
  454     OSKext::printKextsInBacktrace(addr, cnt, &printf, /* lock? */ true);
  455 }
  456 
  457 /*********************************************************************
  458 * Compatibility implementation for kmod_get_info() host_priv routine.
  459 * Only supported on old 32-bit architectures.
  460 *********************************************************************/
  461 #if __i386__
  462 kern_return_t
  463 kext_get_kmod_info(
  464     kmod_info_array_t      * kmod_list,
  465     mach_msg_type_number_t * kmodCount)
  466 {
  467     return OSKext::getKmodInfo(kmod_list, kmodCount);
  468 }
  469 #endif /* __i386__ */
  470 
  471 #if PRAGMA_MARK
  472 #pragma mark Loaded Kext Summary
  473 #endif
  474 
  475 void 
  476 OSKextLoadedKextSummariesUpdated(void)
  477 {
  478     // Do nothing.
  479 }
  480 
  481 };

Cache object: bd098d4be6eacd54df8a8f39972a4f8d


[ 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.