#include <libsa/kmod.h>
#include <libkern/c++/OSContainers.h>
#include <IOKit/IOCatalogue.h>
#include <IOKit/IOLib.h>
#include <libsa/kmod.h>
#include <libsa/catalogue.h>
extern "C" {
#include <mach-o/kld.h>
#include <libsa/vers_rsrc.h>
#include <libsa/stdlib.h>
#include <mach/kmod.h>
#include <vm/vm_kern.h>
#include <mach/kern_return.h>
#include <mach-o/fat.h>
#include <mach_loader.h>
};
extern "C" {
extern load_return_t fatfile_getarch(
void * vp, vm_offset_t data_ptr,
struct fat_arch * archret);
extern kern_return_t
kmod_create_internal(
kmod_info_t *info,
kmod_t *id);
extern kern_return_t
kmod_destroy_internal(kmod_t id);
extern kern_return_t
kmod_start_or_stop(
kmod_t id,
int start,
kmod_args_t *data,
mach_msg_type_number_t *dataCount);
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);
};
IOLock * kld_lock;
#define LOG_DELAY()
#define VTYELLOW "\033[33m"
#define VTRESET "\033[0m"
static
OSArray * getDependencyListForKmod(char * kmod_name) {
int error = 0;
OSDictionary * extensionsDict; OSDictionary * extDict; OSDictionary * extPlist; OSString * extName; OSArray * dependencyList = NULL; unsigned int i;
OSArray * originalList = NULL; OSDictionary * encounteredNames = NULL;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("getDependencyListForKmod(): No extensions dictionary.\n");
LOG_DELAY();
error = 1;
goto finish;
}
extDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(kmod_name));
if (!extDict) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" cannot be found.\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
if (!extPlist) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" has no property list.\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
extName = OSDynamicCast(OSString,
extPlist->getObject("CFBundleIdentifier"));
if (!extName) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\" has no \"CFBundleIdentifier\" property.\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
dependencyList = OSArray::withCapacity(10);
if (!dependencyList) {
IOLog("getDependencyListForKmod(): "
"Couldn't allocate dependency array for extension \"%s\".\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
dependencyList->setObject(extName);
for (i = 0; i < dependencyList->getCount(); i++) {
OSString * curName;
OSDictionary * curExtDict;
OSDictionary * curExtDepDict;
OSDictionary * curExtPlist;
OSString * curDepName;
if (i > 255) {
IOLog("getDependencyListForKmod(): "
"max dependency list length exceeded for "
"extension \"%s\".\n",
kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
curName = OSDynamicCast(OSString, dependencyList->getObject(i));
curExtDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(curName));
if (!curExtDict) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\", required for extension \"%s\", "
"is not available.\n",
curName->getCStringNoCopy(), kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
curExtPlist = OSDynamicCast(OSDictionary,
curExtDict->getObject("plist"));
if (!curExtPlist) {
IOLog("getDependencyListForKmod(): "
"Extension \"%s\", required for extension \"%s\", "
"has no property list.\n",
curName->getCStringNoCopy(), kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
curExtDepDict = OSDynamicCast(OSDictionary,
curExtPlist->getObject("OSBundleLibraries"));
if (curExtDepDict) {
OSCollectionIterator * keyIterator =
OSCollectionIterator::withCollection(curExtDepDict);
if (!keyIterator) {
IOLog("getDependencyListForKmod(): "
"Couldn't allocate iterator for extension "
"\"%s\".\n", kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
while ( (curDepName =
OSDynamicCast(OSString,
keyIterator->getNextObject())) ) {
dependencyList->setObject(curDepName);
}
keyIterator->release();
}
}
originalList = dependencyList;
dependencyList = OSArray::withCapacity(originalList->getCount());
if (!dependencyList) {
IOLog("getDependenciesForKmod(): "
"Couldn't allocate reversal dependency list for extension "
"\"%s\".\n", kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
encounteredNames = OSDictionary::withCapacity(originalList->getCount());
if (!encounteredNames) {
IOLog("getDependenciesForKmod(): "
"Couldn't allocate list of encountered names for extension "
"\"%s\".\n", kmod_name);
LOG_DELAY();
error = 1;
goto finish;
}
i = originalList->getCount();
if (i > 0) {
do {
i--;
OSString * item = OSDynamicCast(OSString,
originalList->getObject(i));
if ( ! encounteredNames->getObject(item) ) {
encounteredNames->setObject(item, originalList);
dependencyList->setObject(item);
}
} while (i > 0);
}
finish:
if (originalList) {
originalList->release();
}
if (encounteredNames) {
encounteredNames->release();
}
if (error) {
if (dependencyList) {
dependencyList->release();
dependencyList = NULL;
}
}
return dependencyList;
}
static bool verifyCompatibleVersions(OSArray * dependencyList) {
bool result = true;
OSString * requestedModuleName = NULL;
OSDictionary * extensionsDict = NULL;
int count, i;
OSString * curName = NULL;
OSDictionary * curExt = NULL;
OSDictionary * curExtPlist = NULL;
OSBoolean * isKernelResource = NULL;
OSDictionary * dependencies = NULL;
OSCollectionIterator * dependencyIterator = NULL; OSString * dependencyName = NULL;
OSString * curExtDependencyVersion = NULL;
UInt32 cur_ext_required_dependency_vers;
OSDictionary * dependency = NULL;
OSDictionary * dependencyPlist = NULL;
OSString * dependencyVersion = NULL;
OSString * dependencyCompatibleVersion = NULL;
UInt32 dependency_vers;
UInt32 dependency_compat_vers;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("verifyCompatibleVersions(): No extensions dictionary.\n");
LOG_DELAY();
result = false;
goto finish;
}
count = dependencyList->getCount();
if (!count) {
IOLog("verifyCompatibleVersions(): "
"Invoked with no dependency list.\n");
LOG_DELAY();
result = false;
goto finish;
}
requestedModuleName = OSDynamicCast(OSString,
dependencyList->getObject(count - 1));
for (i = count - 1; i >= 0; i--) {
if (dependencyIterator) {
dependencyIterator->release();
dependencyIterator = NULL;
}
curName = OSDynamicCast(OSString, dependencyList->getObject(i));
if (!curName) {
IOLog("verifyCompatibleVersions(): Internal error (1).\n");
LOG_DELAY();
result = false;
goto finish;
}
curExt = OSDynamicCast(OSDictionary,
extensionsDict->getObject(curName));
if (!curExt) {
IOLog("verifyCompatibleVersions(): Internal error (2).\n");
LOG_DELAY();
result = false;
goto finish;
}
curExtPlist = OSDynamicCast(OSDictionary,
curExt->getObject("plist"));
if (!curExtPlist) {
IOLog("verifyCompatibleVersions(): Internal error (3).\n");
LOG_DELAY();
result = false;
goto finish;
}
isKernelResource = OSDynamicCast(OSBoolean,
curExtPlist->getObject("OSKernelResource"));
if (isKernelResource && isKernelResource->isTrue()) {
continue;
}
dependencies = OSDynamicCast(OSDictionary,
curExtPlist->getObject("OSBundleLibraries"));
if (!dependencies || dependencies->getCount() < 1) {
IOLog(VTYELLOW "verifyCompatibleVersions(): Extension \"%s\" "
"declares no dependencies.\n" VTRESET,
curName->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
dependencyIterator =
OSCollectionIterator::withCollection(dependencies);
if (!curExtPlist) {
IOLog("verifyCompatibleVersions(): Internal error (4).\n");
LOG_DELAY();
result = false;
goto finish;
}
while ((dependencyName = OSDynamicCast(OSString,
dependencyIterator->getNextObject()))) {
curExtDependencyVersion = OSDynamicCast(OSString,
dependencies->getObject(dependencyName));
if (!curExtDependencyVersion) {
IOLog("verifyCompatibleVersions(): Internal error (5).\n");
LOG_DELAY();
result = false;
goto finish;
}
dependency = OSDynamicCast(OSDictionary,
extensionsDict->getObject(dependencyName));
if (!dependency) {
IOLog("verifyCompatibleVersions(): Internal error (6).\n");
LOG_DELAY();
result = false;
goto finish;
}
dependencyPlist = OSDynamicCast(OSDictionary,
dependency->getObject("plist"));
if (!dependencyPlist) {
IOLog("verifyCompatibleVersions(): Internal error (7).\n");
LOG_DELAY();
result = false;
goto finish;
}
dependencyVersion = OSDynamicCast(OSString,
dependencyPlist->getObject("CFBundleVersion"));
if (!curExtDependencyVersion) {
IOLog(VTYELLOW "Dependency extension \"%s\" doesn't declare a "
"version.\n" VTRESET,
dependencyName->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
dependencyCompatibleVersion = OSDynamicCast(OSString,
dependencyPlist->getObject("OSBundleCompatibleVersion"));
if (!dependencyCompatibleVersion) {
IOLog(VTYELLOW "Dependency extension \"%s\" doesn't declare a "
"compatible version.\n" VTRESET,
dependencyName->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
IOLog("\033[33m %s (needs %s, compat-current is %s-%s).\n" VTRESET,
dependencyName->getCStringNoCopy(),
curExtDependencyVersion->getCStringNoCopy(),
dependencyCompatibleVersion->getCStringNoCopy(),
dependencyVersion->getCStringNoCopy());
LOG_DELAY();
if (!VERS_parse_string(curExtDependencyVersion->getCStringNoCopy(),
&cur_ext_required_dependency_vers)) {
}
if (!VERS_parse_string(dependencyVersion->getCStringNoCopy(),
&dependency_vers)) {
}
if (!VERS_parse_string(dependencyCompatibleVersion->getCStringNoCopy(),
&dependency_compat_vers)) {
}
if (cur_ext_required_dependency_vers > dependency_vers ||
cur_ext_required_dependency_vers < dependency_compat_vers) {
IOLog(VTYELLOW "Cannot load extension \"%s\": dependencies "
"\"%s\" and \"%s\" are not of compatible versions.\n" VTRESET,
requestedModuleName->getCStringNoCopy(),
curName->getCStringNoCopy(),
dependencyName->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
}
}
finish:
return result;
}
static kmod_info_t * g_current_kmod_info = NULL;
static const char * g_current_kmod_name = NULL;
static unsigned long link_load_address = 0;
static unsigned long link_load_size = 0;
static unsigned long link_buffer_size = 0;
static unsigned long link_header_size = 0;
static unsigned long link_buffer_address = 0;
static
unsigned long address_for_loaded_kmod(
unsigned long size,
unsigned long headers_size) {
unsigned long round_headers_size;
unsigned long headers_pad;
if (!g_current_kmod_info) {
IOLog("address_for_loaded_kmod(): No current kmod.\n");
LOG_DELAY();
link_load_address = 0; return 0;
}
round_headers_size = round_page(headers_size);
headers_pad = round_headers_size - headers_size;
link_load_address = (unsigned long)g_current_kmod_info->address +
headers_pad;
return link_load_address;
}
static
unsigned long alloc_for_kmod(
unsigned long size,
unsigned long headers_size) {
vm_address_t buffer = 0;
kern_return_t k_result;
unsigned long round_headers_size;
unsigned long round_segments_size;
unsigned long round_size;
unsigned long headers_pad;
round_headers_size = round_page(headers_size);
round_segments_size = round_page(size - headers_size);
round_size = round_headers_size + round_segments_size;
headers_pad = round_headers_size - headers_size;
k_result = vm_allocate(kernel_map, (vm_offset_t *)&buffer,
round_size, TRUE);
if (k_result != KERN_SUCCESS) {
IOLog("alloc_for_kmod(): Can't allocate memory.\n");
LOG_DELAY();
link_buffer_address = 0; link_load_address = 0; return 0;
}
link_load_size = size;
link_buffer_address = buffer;
link_buffer_size = round_size;
link_header_size = headers_size;
link_load_address = link_buffer_address + headers_pad;
return link_load_address;
}
static
int get_text_info_for_kmod(const char * kmod_name,
char ** text_address,
unsigned long * text_size) {
OSDictionary * extensionsDict;
OSDictionary * kmodDict;
OSData * driverCode;
vm_offset_t kmod_address;
typedef union {
struct mach_header mach_header;
struct fat_header fat_header;
} kmod_header_composite;
kmod_header_composite * kmod_headers;
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("text_address_for_kmod(): No extensions dictionary.\n");
LOG_DELAY();
return 0;
}
kmodDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(kmod_name));
if (!kmodDict) {
IOLog("text_address_for_kmod(): "
"Extension \"%s\" cannot be found.\n", kmod_name);
LOG_DELAY();
return 0;
}
driverCode = OSDynamicCast(OSData, kmodDict->getObject("code"));
if (!driverCode) {
IOLog("text_address_for_kmod(): "
"Extension \"%s\" has no \"code\" property.\n",
kmod_name);
LOG_DELAY();
return 0;
}
kmod_address = (vm_offset_t)driverCode->getBytesNoCopy();
kmod_headers = (kmod_header_composite *)kmod_address;
if (kmod_headers->mach_header.magic == MH_MAGIC) {
*text_address = (char *)kmod_address;
*text_size = driverCode->getLength();
return 1;
} else if (kmod_headers->fat_header.magic == FAT_MAGIC ||
kmod_headers->fat_header.magic == FAT_CIGAM) {
load_return_t load_return;
struct fat_arch fatinfo;
load_return = fatfile_getarch(NULL, kmod_address, &fatinfo);
if (load_return != LOAD_SUCCESS) {
IOLog("text_address_for_kmod(): Extension \"%s\" "
"doesn't contain code for this computer.\n", kmod_name);
LOG_DELAY();
return 0;
}
*text_address = (char *)(kmod_address + fatinfo.offset);
*text_size = fatinfo.size;
return 1;
} else {
IOLog("text_address_for_kmod(): Extension \"%s\" either "
"isn't code or doesn't contain code for this computer.\n",
kmod_name);
LOG_DELAY();
return 0;
}
return 1;
}
bool verify_kmod(const char * kmod_name, kmod_info_t * kmod_info) {
bool result = false;
OSDictionary * extensionsDict = NULL; OSDictionary * kmodDict = NULL; OSDictionary * plist = NULL; OSString * versionString = NULL; UInt32 plist_vers;
UInt32 kmod_vers;
if (strncmp(kmod_name, kmod_info->name, sizeof(kmod_info->name))) {
IOLog("verify_kmod(): kmod loaded as \"%s\" has different "
"identifier \"%s\".\n", kmod_name, kmod_info->name);
LOG_DELAY();
result = false;
goto finish;
}
if (!VERS_parse_string(kmod_info->version,
&kmod_vers)) {
IOLog(VTYELLOW "verify_kmod(): kmod \"%s\" has an invalid "
"version.\n" VTRESET, kmod_info->name);
LOG_DELAY();
result = false;
goto finish;
}
extensionsDict = getStartupExtensions();
if (!extensionsDict) {
IOLog("verify_kmod(): No extensions dictionary.\n");
LOG_DELAY();
result = false;
goto finish;
}
kmodDict = OSDynamicCast(OSDictionary,
extensionsDict->getObject(kmod_name));
if (!kmodDict) {
IOLog("verify_kmod(): Can't find record for kmod \"%s\".\n",
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
plist = OSDynamicCast(OSDictionary,
extensionsDict->getObject("plist"));
if (!kmodDict) {
IOLog("verify_kmod(): Kmod \"%s\" has no property list.\n",
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
versionString = OSDynamicCast(OSString,
extensionsDict->getObject("CFBundleVersion"));
if (!versionString) {
IOLog(VTYELLOW "verify_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" "
"property.\n" VTRESET,
kmod_name);
LOG_DELAY();
result = false;
goto finish;
}
if (!VERS_parse_string(versionString->getCStringNoCopy(),
&plist_vers)) {
IOLog(VTYELLOW "verify_kmod(): Property list for kmod \"%s\" has "
"an invalid version.\n" VTRESET, kmod_info->name);
LOG_DELAY();
result = false;
goto finish;
}
if (kmod_vers != plist_vers) {
IOLog(VTYELLOW "verify_kmod(): Kmod \"%s\" and its property list "
"claim different versions (%s & %s).\n" VTRESET,
kmod_info->name,
kmod_info->version,
versionString->getCStringNoCopy());
LOG_DELAY();
result = false;
goto finish;
}
finish:
return true;
return result;
}
static
kern_return_t load_kmod(OSArray * dependencyList) {
kern_return_t result = KERN_SUCCESS;
unsigned int num_dependencies = 0;
kmod_info_t ** kmod_dependencies = NULL;
unsigned int i;
OSString * requestedKmodName; const char * requested_kmod_name;
OSString * currentKmodName; char * kmod_address;
unsigned long kmod_size;
struct mach_header * kmod_header;
unsigned long kld_result;
int do_kld_unload = 0;
kmod_info_t * kmod_info;
kmod_t kmod_id;
i = dependencyList->getCount();
if (i == 0) {
IOLog("load_kmod(): Called with empty list.\n");
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
} else {
i--; }
requestedKmodName = OSDynamicCast(OSString, dependencyList->getObject(i));
if (!requestedKmodName) {
IOLog("load_kmod(): Called with invalid list of kmod names.\n");
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
requested_kmod_name = requestedKmodName->getCStringNoCopy();
dependencyList->removeObject(i);
kmod_info = kmod_lookupbyname(requested_kmod_name);
if (kmod_info) {
result = KERN_SUCCESS;
goto finish;
}
kld_address_func(&address_for_loaded_kmod);
num_dependencies = dependencyList->getCount();
kmod_dependencies = (kmod_info_t **)kalloc(num_dependencies *
sizeof(kmod_info_t *));
if (!kmod_dependencies) {
IOLog("load_kmod(): Failed to allocate memory for dependency array "
"during load of kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
for (i = 0; i < num_dependencies; i++) {
currentKmodName = OSDynamicCast(OSString,
dependencyList->getObject(i));
if (!currentKmodName) {
IOLog("load_kmod(): Invalid dependency name at index %d for "
"kmod \"%s\".\n", i, requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
const char * current_kmod_name = currentKmodName->getCStringNoCopy();
g_current_kmod_info = kmod_lookupbyname(current_kmod_name);
g_current_kmod_name = current_kmod_name;
if (!g_current_kmod_info) {
IOLog("load_kmod(): Missing dependency \"%s\".\n",
current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kmod_dependencies[i] = g_current_kmod_info;
if (!g_current_kmod_info->size)
continue;
if (!get_text_info_for_kmod(current_kmod_name,
&kmod_address, &kmod_size)) {
IOLog("get_text_info_for_kmod() failed for dependency kmod "
"\"%s\".\n", current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kld_result = kld_load_from_memory(&kmod_header,
current_kmod_name,
(char *)kmod_address,
kmod_size);
if (kld_result) {
do_kld_unload = 1;
}
if (!kld_result || !link_load_address) {
IOLog("kld_load_from_memory() failed for dependency kmod "
"\"%s\".\n", current_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kld_forget_symbol("_kmod_info");
}
kld_address_func(&alloc_for_kmod);
g_current_kmod_name = requested_kmod_name;
g_current_kmod_info = 0;
if (!get_text_info_for_kmod(requested_kmod_name,
&kmod_address, &kmod_size)) {
IOLog("load_kmod: get_text_info_for_kmod() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
kld_result = kld_load_from_memory(&kmod_header,
requested_kmod_name,
(char *)kmod_address,
kmod_size);
if (kld_result) {
do_kld_unload = 1;
}
if (!kld_result || !link_load_address) {
IOLog("load_kmod(): kld_load_from_memory() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
bzero((char *)link_buffer_address, link_buffer_size);
bcopy((char *)kmod_header, (char *)link_buffer_address, link_header_size);
bcopy((char *)kmod_header + link_header_size,
(char *)link_buffer_address + round_page(link_header_size),
link_load_size - link_header_size);
if (!kld_lookup("_kmod_info", (unsigned long *)&kmod_info)) {
IOLog("kld_lookup() of \"_kmod_info\" failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
if (!verify_kmod(requested_kmod_name, kmod_info)) {
result = KERN_FAILURE;
goto finish;
}
kmod_info->address = link_buffer_address;
kmod_info->size = link_buffer_size;
kmod_info->hdr_size = round_page(link_header_size);
flush_dcache(link_buffer_address, link_buffer_size, false);
invalidate_icache(link_buffer_address, link_buffer_size, false);
if (kmod_create_internal(kmod_info, &kmod_id) != KERN_SUCCESS) {
IOLog("load_kmod(): kmod_create() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
IOLog("kmod id %d successfully created at 0x%lx, size %ld.\n",
(unsigned int)kmod_id, link_buffer_address, link_buffer_size);
LOG_DELAY();
for (i = 0; i < num_dependencies; i++) {
kmod_info_t * cur_dependency_info;
kmod_t packed_id;
cur_dependency_info = kmod_dependencies[i];
packed_id = KMOD_PACK_IDS(kmod_id, cur_dependency_info->id);
if (kmod_retain(packed_id) != KERN_SUCCESS) {
IOLog("load_kmod(): kmod_retain() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
kmod_destroy_internal(kmod_id);
result = KERN_FAILURE;
goto finish;
}
}
if (kmod_start_or_stop(kmod_id, 1, 0, 0) != KERN_SUCCESS) {
IOLog("load_kmod(): kmod_start_or_stop() failed for "
"kmod \"%s\".\n", requested_kmod_name);
LOG_DELAY();
kmod_destroy_internal(kmod_id);
result = KERN_FAILURE;
goto finish;
}
finish:
if (do_kld_unload) {
kld_unload_all( 1);
}
if (result != KERN_SUCCESS && link_buffer_address) {
vm_deallocate(kernel_map, link_buffer_address, link_buffer_size);
}
if (kmod_dependencies) {
kfree((unsigned int)kmod_dependencies,
num_dependencies * sizeof(kmod_info_t *));
}
g_current_kmod_name = NULL;
g_current_kmod_info = NULL;
link_buffer_address = 0;
link_load_address = 0;
link_load_size = 0;
link_buffer_size = 0;
link_header_size = 0;
return result;
}
__private_extern__
kern_return_t load_kernel_extension(char * kmod_name) {
kern_return_t result = KERN_SUCCESS;
kmod_info_t * kmod_info;
OSArray * dependencyList = NULL; OSArray * curDependencyList = NULL;
IOLockLock(kld_lock);
kmod_info = kmod_lookupbyname(kmod_name);
if (kmod_info) { result = KERN_SUCCESS;
goto finish;
}
unsigned int count;
unsigned int i;
dependencyList = getDependencyListForKmod(kmod_name);
if (!dependencyList) {
IOLog("load_kernel_extension(): "
"Can't get dependencies for kernel extension \"%s\".\n",
kmod_name);
LOG_DELAY();
result = KERN_FAILURE;
goto finish;
}
if (!verifyCompatibleVersions(dependencyList)) {
IOLog(VTYELLOW "load_kernel_extension(): "
"Version mismatch for kernel extension \"%s\".\n" VTRESET,
kmod_name);
LOG_DELAY();
#if 0
result = KERN_FAILURE;
goto finish;
#else
IOLog(VTYELLOW "Loading anyway.\n" VTRESET);
#endif 0
}
count = dependencyList->getCount();
for (i = 0; i < count; i++) {
kern_return_t load_result;
OSString * curKmodName; const char * cur_kmod_name;
curKmodName = OSDynamicCast(OSString,
dependencyList->getObject(i));
cur_kmod_name = curKmodName->getCStringNoCopy();
curDependencyList = getDependencyListForKmod(cur_kmod_name);
load_result = load_kmod(curDependencyList);
if (load_result != KERN_SUCCESS) {
IOLog("load_kernel_extension(): "
"load_kmod() failed for kmod \"%s\".\n",
cur_kmod_name);
LOG_DELAY();
result = load_result;
goto finish;
}
curDependencyList->release();
curDependencyList = NULL;
}
finish:
if (dependencyList) {
dependencyList->release();
dependencyList = NULL;
}
if (curDependencyList) {
curDependencyList->release();
curDependencyList = NULL;
}
IOLockUnlock(kld_lock);
return result;
}