/*
- * 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>
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)
#define VTRESET
#endif /* DEBUG */
+
+#define KERNEL_PREFIX "com.apple.kernel"
+#define KPI_PREFIX "com.apple.kpi"
+
+
/*********************************************************************
*
*********************************************************************/
*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;
if (!uncompressModule(compressedCode, &driverCode)) {
IOLog("extension \"%s\": couldn't uncompress code\n",
bundleid);
- LOG_DELAY(1);
result = false;
goto finish;
}
OSData * compressedCode = 0; // don't release
if (is_kernel) {
- *is_kernel = false;
+ *is_kernel = 0;
}
/* Get the dictionary of startup extensions.
extPlist->getObject("OSKernelResource"));
if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
if (is_kernel) {
- *is_kernel = true;
+ *is_kernel = 1;
}
}
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) {
/*********************************************************************
*********************************************************************/
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"));
goto finish;
}
+ dependentName = trueParent ? trueParent : kextName;
+
while ( (libraryName = OSDynamicCast(OSString,
keyIterator->getNextObject())) ) {
} 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:
{
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);
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) {
}
// 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;
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())) ) {
-
- 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, 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");
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);
/* 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);
}
}
- 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;
}
/* 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;
}
}
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;
+}