X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/21362eb3e66fd2c787aee132bce100a44d71a99c..ca66cea69e6e866fd781ae2260d9474bdd48f2ca:/libsa/kext.cpp diff --git a/libsa/kext.cpp b/libsa/kext.cpp index 3a4556454..48ef63d16 100644 --- a/libsa/kext.cpp +++ b/libsa/kext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -25,6 +25,14 @@ * * @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 #include #include @@ -66,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) @@ -81,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" + + /********************************************************************* * *********************************************************************/ @@ -150,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; @@ -172,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; } @@ -273,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. @@ -314,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; } } @@ -322,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) { @@ -339,17 +357,20 @@ finish: /********************************************************************* *********************************************************************/ static bool -figureDependenciesForKext(OSDictionary * kextPlist, - OSDictionary * dependencies, +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")); @@ -373,6 +394,8 @@ figureDependenciesForKext(OSDictionary * kextPlist, goto finish; } + dependentName = trueParent ? trueParent : kextName; + while ( (libraryName = OSDynamicCast(OSString, keyIterator->getNextObject())) ) { @@ -389,24 +412,60 @@ figureDependenciesForKext(OSDictionary * kextPlist, } else { char is_kernel_component; - if (!kextIsDependency(libraryName->getCStringNoCopy(), &is_kernel_component)) - is_kernel_component = false; + if (!kextIsDependency(libraryName->getCStringNoCopy(), + &is_kernel_component)) { + + is_kernel_component = 0; + } if (!skipKernelDependencies || !is_kernel_component) { - dependencies->setObject(libraryName, - trueParent ? trueParent : kextName); + 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 */ - dependencies->setObject("com.apple.kernel.libkern", - trueParent ? trueParent : kextName); - IOLog("Extension \"%s\" has no kernel dependency.\n", - kextName->getCStringNoCopy()); + 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: @@ -452,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); @@ -489,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) { @@ -501,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; @@ -515,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, false)) { + 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())) ) { + dependent_name = dependentName->getCStringNoCopy(); + library_name = libraryName->getCStringNoCopy(); - library_name = libraryName->getCStringNoCopy(); + if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) { - dependentName = OSDynamicCast(OSString, - workingDependencies->getObject(libraryName)); - - 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, true)) { + 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"); @@ -628,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); @@ -658,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, false)) { + if (!addDependenciesForKext(kextPlist, dependencyList, + kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) { IOLog("can't determine immediate dependencies for extension %s\n", library_name); @@ -668,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; } @@ -712,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; } @@ -766,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; +}