]> git.saurik.com Git - apple/xnu.git/blobdiff - libsa/kext.cpp
xnu-1228.5.20.tar.gz
[apple/xnu.git] / libsa / kext.cpp
index 8f785d9d03b6642f9ef8b5137ad8a5ae9c659f22..48ef63d1655aae93db6a970eb7b2f00b89de9b47 100644 (file)
@@ -1,24 +1,38 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * 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.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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 OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * 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_LICENSE_HEADER_END@
+ * @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>
@@ -60,10 +74,14 @@ kmod_start_or_stop(
 extern kern_return_t kmod_retain(kmod_t id);
 extern kern_return_t kmod_release(kmod_t id);
 
-extern void flush_dcache(vm_offset_t addr, unsigned cnt, int phys);
-extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys);
+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)
@@ -75,6 +93,11 @@ extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys);
 #define VTRESET
 #endif /* DEBUG */
 
+
+#define KERNEL_PREFIX  "com.apple.kernel"
+#define KPI_PREFIX     "com.apple.kpi"
+
+
 /*********************************************************************
 *
 *********************************************************************/
@@ -144,7 +167,7 @@ bool getKext(
         *caller_owns_code = false;
     
         *code = (unsigned char *)kld_file_getaddr(bundleid,
-            (long *)&code_size_local);
+            (unsigned long *)&code_size_local);
         if (*code) {
             if (code_size) {
                 *code_size = code_size_local;
@@ -166,7 +189,6 @@ bool getKext(
                     if (!uncompressModule(compressedCode, &driverCode)) {
                         IOLog("extension \"%s\": couldn't uncompress code\n",
                             bundleid);
-                        LOG_DELAY(1);
                         result = false;
                         goto finish;
                     }
@@ -267,7 +289,7 @@ bool kextIsDependency(const char * kext_name, char * is_kernel) {
     OSData * compressedCode = 0;          // don't release
 
     if (is_kernel) {
-        *is_kernel = false;
+        *is_kernel = 0;
     }
 
    /* Get the dictionary of startup extensions.
@@ -308,7 +330,7 @@ bool kextIsDependency(const char * kext_name, char * is_kernel) {
         extPlist->getObject("OSKernelResource"));
     if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
         if (is_kernel) {
-            *is_kernel = true;
+            *is_kernel = 1;
         }
     }
 
@@ -316,8 +338,10 @@ bool kextIsDependency(const char * kext_name, char * is_kernel) {
     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;
+        *is_kernel = 2;
     }
 
     if (!driverCode && !compressedCode && !isKernelResourceObj) {
@@ -333,15 +357,20 @@ finish:
 /*********************************************************************
 *********************************************************************/
 static bool
-figureDependenciesForKext(OSDictionary * kextPlist,
-    OSDictionary * dependencies,
-    OSString * trueParent)
+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"));
@@ -365,6 +394,8 @@ figureDependenciesForKext(OSDictionary * kextPlist,
         goto finish;
     }
 
+    dependentName = trueParent ? trueParent : kextName;
+
     while ( (libraryName = OSDynamicCast(OSString,
         keyIterator->getNextObject())) ) {
 
@@ -379,9 +410,62 @@ figureDependenciesForKext(OSDictionary * kextPlist,
             result = false;
             goto finish;
         } else {
-            dependencies->setObject(libraryName,
-                trueParent ? trueParent : kextName);
+            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:
@@ -427,24 +511,25 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
 {
     bool result = true;
     OSDictionary * kextPlist = 0; // don't release
-    OSDictionary * workingDependencies = 0; // must release
-    OSDictionary * pendingDependencies = 0; // must release
-    OSDictionary * swapDict = 0; // don't release
-    OSString * dependentName = 0; // don't release
-    const char * dependent_name = 0;  // don't free
-    OSString * libraryName = 0; // don't release
-    const char * library_name = 0;  // don't free
-    OSCollectionIterator * dependencyIterator = 0; // must 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 = false;
+    char is_kernel_component = 0;
     dgraph_entry_t * dgraph_entry = 0; // don't free
     dgraph_entry_t * dgraph_dependency = 0; // don't free
-    unsigned int graph_depth = 0;
     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);
@@ -464,8 +549,16 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
         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) {
@@ -476,8 +569,7 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
     }
 
     // pass ownership of code to kld patcher
-    if (code)
-    {
+    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;
@@ -490,95 +582,78 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
     code_length = 0;
     code_is_kmem = false;
 
-    workingDependencies = OSDictionary::withCapacity(5);
-    if (!workingDependencies) {
-        IOLog("memory allocation failure\n");
-        result = false;
-        goto finish;
-    }
-
-    pendingDependencies = OSDictionary::withCapacity(5);
-    if (!pendingDependencies) {
+   /*****
+    * Now handle all the dependencies.
+    */
+    dependencyList = OSArray::withCapacity(5);
+    if (!dependencyList) {
         IOLog("memory allocation failure\n");
         result = false;
         goto finish;
     }
 
-    if (!figureDependenciesForKext(kextPlist, workingDependencies, NULL)) {
+    index = 0;
+    if (!addDependenciesForKext(kextPlist, dependencyList, NULL, false)) {
         IOLog("can't determine immediate dependencies for extension %s\n",
             kmod_name);
         result = false;
         goto finish;
     }
 
-    graph_depth = 0;
-    while (workingDependencies->getCount()) {
-        if (graph_depth > 255) {
+   /* 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;
         }
 
-        if (dependencyIterator) {
-            dependencyIterator->release();
-            dependencyIterator = 0;
-        }
+        dependentName = OSDynamicCast(OSString,
+            dependencyList->getObject(index));
+        libraryName = OSDynamicCast(OSString,
+            dependencyList->getObject(index + 1));
 
-        dependencyIterator = OSCollectionIterator::withCollection(
-            workingDependencies);
-        if (!dependencyIterator) {
-            IOLog("memory allocation failure\n");
+        if (!dependentName || !libraryName) {
+            IOLog("malformed dependency list\n");
             result = false;
             goto finish;
         }
 
-        while ( (libraryName =
-                 OSDynamicCast(OSString, dependencyIterator->getNextObject())) ) {
-
-            library_name = libraryName->getCStringNoCopy();
+        dependent_name = dependentName->getCStringNoCopy();
+        library_name = libraryName->getCStringNoCopy();
 
-            dependentName = OSDynamicCast(OSString,
-                workingDependencies->getObject(libraryName));
+        if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
 
-            dependent_name = dependentName->getCStringNoCopy();
+            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;
             }
+        }
 
-           OSString * string;
-           if ((string = OSDynamicCast(OSString,
-                           kextPlist->getObject("OSBundleSharedExecutableIdentifier"))))
-           {
-               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) {
-
-               /* For binaryless kexts, add a new pending dependency from the
-                * original dependent onto the dependencies of the current,
-                * binaryless, dependency.
-                */
-                if (!figureDependenciesForKext(kextPlist, pendingDependencies,
-                    dependentName)) {
+        kext_is_dependency = kextIsDependency(library_name,
+            &is_kernel_component);
 
-                    IOLog("can't determine immediate dependencies for extension %s\n",
-                        library_name);
-                    result = false;
-                    goto finish;
-                }
-                continue;
-            } else {
+        if (kext_is_dependency) {
                 dgraph_entry = dgraph_find_dependent(dgraph, dependent_name);
                 if (!dgraph_entry) {
                     IOLog("internal error with dependency graph\n");
@@ -603,8 +678,16 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
                     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);
 
@@ -633,8 +716,8 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
 
            /* Now put the library's dependencies onto the pending set.
             */
-            if (!figureDependenciesForKext(kextPlist, pendingDependencies,
-                NULL)) {
+            if (!addDependenciesForKext(kextPlist, dependencyList,
+                kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) {
 
                 IOLog("can't determine immediate dependencies for extension %s\n",
                     library_name);
@@ -643,23 +726,18 @@ bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
             }
         }
 
-        dependencyIterator->release();
-        dependencyIterator = 0;
-
-        workingDependencies->flushCollection();
-        swapDict = workingDependencies;
-        workingDependencies = pendingDependencies;
-        pendingDependencies = swapDict;
-        graph_depth++;
-    }
-
 finish:
     if (code && code_is_kmem) {
         kmem_free(kernel_map, (unsigned int)code, code_length);
     }
-    if (workingDependencies)  workingDependencies->release();
-    if (pendingDependencies)  pendingDependencies->release();
-    if (dependencyIterator)   dependencyIterator->release();
+    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;
 }
 
@@ -687,7 +765,7 @@ kern_return_t load_kernel_extension(char * kmod_name)
    /* See if the kmod is already loaded.
     */
     if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) {
-       kfree((vm_offset_t) kmod_info, sizeof(kmod_info_t));
+        kfree(kmod_info, sizeof(kmod_info_t));
         return KERN_SUCCESS;
     }
 
@@ -741,3 +819,71 @@ finish:
     }
     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;
+}