#include <mach/mach.h>
#include <TargetConditionals.h>
#include <mach/kmod.h>
#include <sys/param.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include <bootstrap_priv.h>
#include <syslog.h>
#include <stdarg.h>
#include "OSKext.h"
#include "misc_util.h"
#include "KextManager.h"
#include "KextManagerPriv.h"
#include "kextmanager_mig.h"
static kern_return_t get_kextd_port(mach_port_t *kextd_port);
CFURLRef KextManagerCreateURLForBundleIdentifier(
CFAllocatorRef allocator,
CFStringRef bundleIdentifier)
{
CFURLRef bundleURL = NULL;
kern_return_t kern_result = kOSReturnError;
char bundle_id[KMOD_MAX_NAME] = "";
mach_port_t kextd_port = MACH_PORT_NULL;
char bundle_path[MAXPATHLEN] = "";
CFStringRef bundlePath = NULL; OSReturn kext_result = kOSReturnError;
kext_result_t tmpRes;
if (!bundleIdentifier) {
goto finish;
}
if (!CFStringGetCString(bundleIdentifier,
bundle_id, sizeof(bundle_id) - 1, kCFStringEncodingUTF8)) {
goto finish;
}
kern_result = get_kextd_port(&kextd_port);
if (kern_result != kOSReturnSuccess) {
goto finish;
}
kern_result = kextmanager_path_for_bundle_id(
kextd_port, bundle_id, bundle_path, &tmpRes);
kext_result = tmpRes;
if (kern_result != kOSReturnSuccess) {
goto finish;
}
if (kext_result != kOSReturnSuccess) {
goto finish;
}
bundlePath = CFStringCreateWithCString(kCFAllocatorDefault,
bundle_path, kCFStringEncodingUTF8);
if (!bundlePath) {
goto finish;
}
bundleURL = CFURLCreateWithFileSystemPath(allocator,
bundlePath, kCFURLPOSIXPathStyle, true);
finish:
if (bundlePath) CFRelease(bundlePath);
return bundleURL;
}
OSReturn __KextManagerSendLoadKextRequest(
CFMutableDictionaryRef requestDict,
CFArrayRef dependencyKextAndFolderURLs)
{
OSReturn result = kOSReturnError;
mach_port_t kextd_port = MACH_PORT_NULL;
CFDataRef requestData = NULL; CFMutableArrayRef dependencyPaths = NULL; CFURLRef dependencyAbsURL = NULL; CFStringRef dependencyPath = NULL; CFErrorRef error = NULL;
if (!requestDict) {
result = kOSKextReturnInvalidArgument;
goto finish;
}
result = get_kextd_port(&kextd_port);
if (result != kOSReturnSuccess) {
goto finish;
}
if (dependencyKextAndFolderURLs &&
CFArrayGetCount(dependencyKextAndFolderURLs)) {
CFIndex count, index;
dependencyPaths = CFArrayCreateMutable(kCFAllocatorDefault,
0, &kCFTypeArrayCallBacks);
if (!dependencyPaths) {
result = kOSKextReturnNoMemory;
goto finish;
}
CFDictionarySetValue(requestDict, kKextLoadDependenciesKey,
dependencyPaths);
count = CFArrayGetCount(dependencyKextAndFolderURLs);
for (index = 0; index < count; index++) {
CFURLRef thisURL = (CFURLRef)CFArrayGetValueAtIndex(
dependencyKextAndFolderURLs, index);
SAFE_RELEASE_NULL(dependencyPath);
SAFE_RELEASE_NULL(dependencyAbsURL);
dependencyAbsURL = CFURLCopyAbsoluteURL(thisURL);
if (!dependencyAbsURL) {
result = kOSKextReturnNoMemory;
goto finish;
}
dependencyPath = CFURLCopyFileSystemPath(dependencyAbsURL,
kCFURLPOSIXPathStyle);
if (!dependencyPath) {
result = kOSKextReturnNoMemory;
goto finish;
}
CFArrayAppendValue(dependencyPaths, dependencyPath);
}
}
requestData = CFPropertyListCreateData(kCFAllocatorDefault,
requestDict, kCFPropertyListBinaryFormat_v1_0,
0,
&error);
if (!requestData) {
result = kOSKextReturnSerialization;
goto finish;
}
result = kextmanager_load_kext(kextd_port,
(char *)CFDataGetBytePtr(requestData),
CFDataGetLength(requestData));
finish:
SAFE_RELEASE(requestData);
SAFE_RELEASE(dependencyPaths);
SAFE_RELEASE(dependencyPath);
SAFE_RELEASE(dependencyAbsURL);
SAFE_RELEASE(error);
return result;
}
OSReturn KextManagerLoadKextWithIdentifier(
CFStringRef kextIdentifier,
CFArrayRef dependencyKextAndFolderURLs)
{
OSReturn result = kOSReturnError;
CFMutableDictionaryRef requestDict = NULL;
if (!kextIdentifier) {
result = kOSKextReturnInvalidArgument;
goto finish;
}
requestDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!requestDict) {
result = kOSKextReturnNoMemory;
goto finish;
}
CFDictionarySetValue(requestDict, kKextLoadIdentifierKey,
kextIdentifier);
result = __KextManagerSendLoadKextRequest(requestDict,
dependencyKextAndFolderURLs);
finish:
SAFE_RELEASE(requestDict);
return result;
}
OSReturn KextManagerLoadKextWithURL(
CFURLRef kextURL,
CFArrayRef dependencyKextAndFolderURLs)
{
OSReturn result = kOSReturnError;
CFMutableDictionaryRef requestDict = NULL; CFURLRef absURL = NULL; CFStringRef kextPath = NULL;
if (!kextURL) {
result = kOSKextReturnInvalidArgument;
goto finish;
}
requestDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!requestDict) {
result = kOSKextReturnNoMemory;
goto finish;
}
absURL = CFURLCopyAbsoluteURL(kextURL);
if (!absURL) {
result = kOSKextReturnNoMemory;
goto finish;
}
kextPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
if (!kextPath) {
result = kOSKextReturnSerialization;
goto finish;
}
CFDictionarySetValue(requestDict, kKextLoadPathKey, kextPath);
result = __KextManagerSendLoadKextRequest(requestDict,
dependencyKextAndFolderURLs);
finish:
SAFE_RELEASE(requestDict);
SAFE_RELEASE(absURL);
SAFE_RELEASE(kextPath);
return result;
}
OSReturn KextManagerUnloadKextWithIdentifier(
CFStringRef kextIdentifier)
{
OSReturn result = kOSReturnError;
OSKextLogSpec oldUserLogSpec = OSKextGetLogFilter( false);
OSKextLogSpec oldKernelLogSpec = OSKextGetLogFilter( true);
if (!kextIdentifier) {
result = kOSKextReturnInvalidArgument;
goto finish;
}
OSKextSetLogFilter(kOSKextLogSilentFilter, false);
OSKextSetLogFilter(kOSKextLogSilentFilter, true);
result = OSKextUnloadKextWithIdentifier(kextIdentifier,
TRUE);
finish:
OSKextSetLogFilter(oldUserLogSpec, false);
OSKextSetLogFilter(oldKernelLogSpec, true);
return result;
}
void _removePrivateKextInfo(
const void * vKey __unused,
const void * vValue,
void * vContext __unused)
{
CFMutableDictionaryRef kextInfo = (CFMutableDictionaryRef)vValue;
CFDictionaryRemoveValue(kextInfo, CFSTR("OSBundleMachOHeaders"));
CFDictionaryRemoveValue(kextInfo, CFSTR("OSBundleLogStrings"));
return;
}
CFDictionaryRef KextManagerCopyLoadedKextInfo(
CFArrayRef kextIdentifiers,
CFArrayRef infoKeys)
{
CFMutableDictionaryRef result = NULL;
CFDictionaryRef kextResult = NULL;
kextResult = OSKextCopyLoadedKextInfo(kextIdentifiers, infoKeys);
if (!kextResult) {
goto finish;
}
result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, kextResult);
CFDictionaryApplyFunction(result, &_removePrivateKextInfo, NULL);
finish:
SAFE_RELEASE(kextResult);
return (CFDictionaryRef)result;
}
CFArrayRef _KextManagerCreatePropertyValueArray(
CFAllocatorRef allocator __unused,
CFStringRef propertyKey)
{
CFMutableArrayRef valueArray = NULL; CFDataRef xmlData = NULL; CFTypeRef cfObj;
kern_return_t kern_result = kOSReturnError;
property_key_t property_key = "";
mach_port_t kextd_port = MACH_PORT_NULL;
char * xml_data = NULL; natural_t xml_data_length = 0;
CFErrorRef error = NULL;
if (!propertyKey || PROPERTYKEY_LEN <
(CFStringGetMaximumSizeForEncoding(CFStringGetLength(propertyKey),
kCFStringEncodingUTF8))) {
goto finish;
}
if (!CFStringGetCString(propertyKey,
property_key, sizeof(property_key) - 1, kCFStringEncodingUTF8)) {
goto finish;
}
kern_result = get_kextd_port(&kextd_port);
if (kern_result != kOSReturnSuccess) {
goto finish;
}
kern_result = kextmanager_create_property_value_array(kextd_port,
property_key, &xml_data, &xml_data_length);
if (kern_result != kOSReturnSuccess) {
goto finish;
}
xmlData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)xml_data,
xml_data_length, kCFAllocatorNull);
if (!xmlData) {
goto finish;
}
cfObj = CFPropertyListCreateWithData(kCFAllocatorDefault,
xmlData, 0, NULL, &error);
if (!cfObj) {
goto finish;
}
if (CFGetTypeID(cfObj) != CFArrayGetTypeID()) {
CFRelease(cfObj);
goto finish;
}
valueArray = (CFMutableArrayRef) cfObj;
finish:
SAFE_RELEASE(error);
SAFE_RELEASE(xmlData);
if (xml_data) {
vm_deallocate(mach_task_self(), (vm_address_t)xml_data,
xml_data_length);
}
return valueArray;
}
static kern_return_t get_kextd_port(mach_port_t * kextd_port)
{
kern_return_t kern_result = kOSReturnError;
mach_port_t bootstrap_port = MACH_PORT_NULL;
kern_result = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (kern_result == kOSReturnSuccess) {
kern_result = bootstrap_look_up2(bootstrap_port,
(char *)KEXTD_SERVER_NAME,
kextd_port,
0,
BOOTSTRAP_PRIVILEGED_SERVER);
}
return kern_result;
}