1/* 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <mach/mach.h> 29#include <TargetConditionals.h> 30#include <mach/kmod.h> 31#include <sys/param.h> 32#include <mach/mach_error.h> 33#include <servers/bootstrap.h> 34#include <bootstrap_priv.h> 35#include <syslog.h> 36#include <stdarg.h> 37 38#include "OSKext.h" 39#include "misc_util.h" 40#include "KextManager.h" 41#include "KextManagerPriv.h" 42#include "kextmanager_mig.h" 43 44/********************************************************************* 45* IMPORTANT: All calls in this module should be simple RPCs to kextd 46* or use the OSKext library *without* creating any OSKext objects. 47*********************************************************************/ 48 49static kern_return_t get_kextd_port(mach_port_t *kextd_port); // internal convenience function 50 51/********************************************************************* 52*********************************************************************/ 53CFURLRef KextManagerCreateURLForBundleIdentifier( 54 CFAllocatorRef allocator, 55 CFStringRef bundleIdentifier) 56{ 57 CFURLRef bundleURL = NULL; // returned 58 59 kern_return_t kern_result = kOSReturnError; 60 char bundle_id[KMOD_MAX_NAME] = ""; 61 62 mach_port_t kextd_port = MACH_PORT_NULL; 63 64 char bundle_path[MAXPATHLEN] = ""; 65 CFStringRef bundlePath = NULL; // must free 66 OSReturn kext_result = kOSReturnError; 67 kext_result_t tmpRes; 68 69 if (!bundleIdentifier) { 70 goto finish; 71 } 72 73 if (!CFStringGetCString(bundleIdentifier, 74 bundle_id, sizeof(bundle_id) - 1, kCFStringEncodingUTF8)) { 75 goto finish; 76 } 77 78 kern_result = get_kextd_port(&kextd_port); 79 if (kern_result != kOSReturnSuccess) { 80 goto finish; 81 } 82 83 kern_result = kextmanager_path_for_bundle_id( 84 kextd_port, bundle_id, bundle_path, &tmpRes); 85 kext_result = tmpRes; 86 if (kern_result != kOSReturnSuccess) { 87 goto finish; 88 } 89 90 if (kext_result != kOSReturnSuccess) { 91 goto finish; 92 } 93 94 bundlePath = CFStringCreateWithCString(kCFAllocatorDefault, 95 bundle_path, kCFStringEncodingUTF8); 96 if (!bundlePath) { 97 goto finish; 98 } 99 100 bundleURL = CFURLCreateWithFileSystemPath(allocator, 101 bundlePath, kCFURLPOSIXPathStyle, true); 102 103finish: 104 105 if (bundlePath) CFRelease(bundlePath); 106 107 return bundleURL; 108} 109 110/********************************************************************* 111* Internal function for use by KextManagerLoadKextWithIdentifier() 112* and KextManagerLoadKextWithURL(). 113*********************************************************************/ 114OSReturn __KextManagerSendLoadKextRequest( 115 CFMutableDictionaryRef requestDict, 116 CFArrayRef dependencyKextAndFolderURLs) 117{ 118 OSReturn result = kOSReturnError; 119 mach_port_t kextd_port = MACH_PORT_NULL; 120 CFDataRef requestData = NULL; // must release 121 CFMutableArrayRef dependencyPaths = NULL; // must release 122 CFURLRef dependencyAbsURL = NULL; // must release 123 CFStringRef dependencyPath = NULL; // must release 124 CFErrorRef error = NULL; // must release 125 126 if (!requestDict) { 127 result = kOSKextReturnInvalidArgument; 128 goto finish; 129 } 130 131 result = get_kextd_port(&kextd_port); 132 if (result != kOSReturnSuccess) { 133 goto finish; 134 } 135 136 if (dependencyKextAndFolderURLs && 137 CFArrayGetCount(dependencyKextAndFolderURLs)) { 138 139 CFIndex count, index; 140 141 dependencyPaths = CFArrayCreateMutable(kCFAllocatorDefault, 142 /* capacity */ 0, &kCFTypeArrayCallBacks); 143 if (!dependencyPaths) { 144 result = kOSKextReturnNoMemory; 145 goto finish; 146 } 147 CFDictionarySetValue(requestDict, kKextLoadDependenciesKey, 148 dependencyPaths); 149 150 count = CFArrayGetCount(dependencyKextAndFolderURLs); 151 for (index = 0; index < count; index++) { 152 CFURLRef thisURL = (CFURLRef)CFArrayGetValueAtIndex( 153 dependencyKextAndFolderURLs, index); 154 155 SAFE_RELEASE_NULL(dependencyPath); 156 SAFE_RELEASE_NULL(dependencyAbsURL); 157 158 dependencyAbsURL = CFURLCopyAbsoluteURL(thisURL); 159 if (!dependencyAbsURL) { 160 result = kOSKextReturnNoMemory; 161 goto finish; 162 } 163 dependencyPath = CFURLCopyFileSystemPath(dependencyAbsURL, 164 kCFURLPOSIXPathStyle); 165 if (!dependencyPath) { 166 result = kOSKextReturnNoMemory; 167 goto finish; 168 } 169 170 CFArrayAppendValue(dependencyPaths, dependencyPath); 171 } 172 } 173 174 requestData = CFPropertyListCreateData(kCFAllocatorDefault, 175 requestDict, kCFPropertyListBinaryFormat_v1_0, 176 /* options */ 0, 177 &error); 178 if (!requestData) { 179 // any point in logging error reason here? nothing caller can do.... 180 result = kOSKextReturnSerialization; 181 goto finish; 182 } 183 184 result = kextmanager_load_kext(kextd_port, 185 (char *)CFDataGetBytePtr(requestData), 186 CFDataGetLength(requestData)); 187 188finish: 189 SAFE_RELEASE(requestData); 190 SAFE_RELEASE(dependencyPaths); 191 SAFE_RELEASE(dependencyPath); 192 SAFE_RELEASE(dependencyAbsURL); 193 SAFE_RELEASE(error); 194 195 return result; 196} 197 198/********************************************************************* 199*********************************************************************/ 200OSReturn KextManagerLoadKextWithIdentifier( 201 CFStringRef kextIdentifier, 202 CFArrayRef dependencyKextAndFolderURLs) 203{ 204 OSReturn result = kOSReturnError; 205 CFMutableDictionaryRef requestDict = NULL; // must release 206 207 if (!kextIdentifier) { 208 result = kOSKextReturnInvalidArgument; 209 goto finish; 210 } 211 212 requestDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 213 /* capacity */ 0, &kCFTypeDictionaryKeyCallBacks, 214 &kCFTypeDictionaryValueCallBacks); 215 if (!requestDict) { 216 result = kOSKextReturnNoMemory; 217 goto finish; 218 } 219 220 CFDictionarySetValue(requestDict, kKextLoadIdentifierKey, 221 kextIdentifier); 222 223 result = __KextManagerSendLoadKextRequest(requestDict, 224 dependencyKextAndFolderURLs); 225 226finish: 227 SAFE_RELEASE(requestDict); 228 return result; 229} 230 231/********************************************************************* 232*********************************************************************/ 233OSReturn KextManagerLoadKextWithURL( 234 CFURLRef kextURL, 235 CFArrayRef dependencyKextAndFolderURLs) 236{ 237 OSReturn result = kOSReturnError; 238 CFMutableDictionaryRef requestDict = NULL; // must release 239 CFURLRef absURL = NULL; // must release 240 CFStringRef kextPath = NULL; // must release 241 242 if (!kextURL) { 243 result = kOSKextReturnInvalidArgument; 244 goto finish; 245 } 246 247 requestDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 248 /* capacity */ 0, &kCFTypeDictionaryKeyCallBacks, 249 &kCFTypeDictionaryValueCallBacks); 250 if (!requestDict) { 251 result = kOSKextReturnNoMemory; 252 goto finish; 253 } 254 255 absURL = CFURLCopyAbsoluteURL(kextURL); 256 if (!absURL) { 257 result = kOSKextReturnNoMemory; 258 goto finish; 259 } 260 261 kextPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); 262 if (!kextPath) { 263 result = kOSKextReturnSerialization; 264 goto finish; 265 } 266 CFDictionarySetValue(requestDict, kKextLoadPathKey, kextPath); 267 268 result = __KextManagerSendLoadKextRequest(requestDict, 269 dependencyKextAndFolderURLs); 270 271finish: 272 SAFE_RELEASE(requestDict); 273 SAFE_RELEASE(absURL); 274 SAFE_RELEASE(kextPath); 275 return result; 276} 277 278/********************************************************************* 279*********************************************************************/ 280OSReturn KextManagerUnloadKextWithIdentifier( 281 CFStringRef kextIdentifier) 282{ 283 OSReturn result = kOSReturnError; 284 OSKextLogSpec oldUserLogSpec = OSKextGetLogFilter(/* kernel? */ false); 285 OSKextLogSpec oldKernelLogSpec = OSKextGetLogFilter(/* kernel? */ true); 286 287 if (!kextIdentifier) { 288 result = kOSKextReturnInvalidArgument; 289 goto finish; 290 } 291 292 OSKextSetLogFilter(kOSKextLogSilentFilter, /* kernelFlag */ false); 293 OSKextSetLogFilter(kOSKextLogSilentFilter, /* kernelFlag */ true); 294 295 result = OSKextUnloadKextWithIdentifier(kextIdentifier, 296 /* terminateServicesAndRemovePersonalities */ TRUE); 297 298finish: 299 300 OSKextSetLogFilter(oldUserLogSpec, /* kernelFlag */ false); 301 OSKextSetLogFilter(oldKernelLogSpec, /* kernelFlag */ true); 302 return result; 303} 304 305/********************************************************************* 306* Use this applier function to strip out any info from the kernel 307* we don't want to expose in public API. 308*********************************************************************/ 309void _removePrivateKextInfo( 310 const void * vKey __unused, 311 const void * vValue, 312 void * vContext __unused) 313{ 314 CFMutableDictionaryRef kextInfo = (CFMutableDictionaryRef)vValue; 315 CFDictionaryRemoveValue(kextInfo, CFSTR("OSBundleMachOHeaders")); 316 return; 317} 318 319/********************************************************************* 320*********************************************************************/ 321CFDictionaryRef KextManagerCopyLoadedKextInfo( 322 CFArrayRef kextIdentifiers, 323 CFArrayRef infoKeys) 324{ 325 CFMutableDictionaryRef result = NULL; 326 CFDictionaryRef kextResult = NULL; // must release 327 328 kextResult = OSKextCopyLoadedKextInfo(kextIdentifiers, infoKeys); 329 if (!kextResult) { 330 goto finish; 331 } 332 333 /* Copy and remove properties we don't want people to use. 334 */ 335 result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, kextResult); 336 CFDictionaryApplyFunction(result, &_removePrivateKextInfo, /* context */ NULL); 337 338finish: 339 SAFE_RELEASE(kextResult); 340 return (CFDictionaryRef)result; 341} 342 343/********************************************************************* 344*********************************************************************/ 345CFArrayRef _KextManagerCreatePropertyValueArray( 346 CFAllocatorRef allocator __unused, 347 CFStringRef propertyKey) 348{ 349 CFMutableArrayRef valueArray = NULL; // returned 350 CFDataRef xmlData = NULL; // must release 351 CFTypeRef cfObj; 352 353 kern_return_t kern_result = kOSReturnError; 354 property_key_t property_key = ""; // matches prop_key_t in .defs file 355 356 mach_port_t kextd_port = MACH_PORT_NULL; 357 358 char * xml_data = NULL; // must vm_deallocate() 359 natural_t xml_data_length = 0; 360 361 CFErrorRef error = NULL; // must release 362 363 if (!propertyKey || PROPERTYKEY_LEN < 364 (CFStringGetMaximumSizeForEncoding(CFStringGetLength(propertyKey), 365 kCFStringEncodingUTF8))) { 366 goto finish; 367 } 368 369 if (!CFStringGetCString(propertyKey, 370 property_key, sizeof(property_key) - 1, kCFStringEncodingUTF8)) { 371 goto finish; 372 } 373 374 kern_result = get_kextd_port(&kextd_port); 375 if (kern_result != kOSReturnSuccess) { 376 goto finish; 377 } 378 379 kern_result = kextmanager_create_property_value_array(kextd_port, 380 property_key, &xml_data, &xml_data_length); 381 if (kern_result != kOSReturnSuccess) { 382 goto finish; 383 } 384 385 xmlData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)xml_data, 386 xml_data_length, kCFAllocatorNull); 387 if (!xmlData) { 388 goto finish; 389 } 390 391 cfObj = CFPropertyListCreateWithData(kCFAllocatorDefault, 392 xmlData, /* options */ 0, /* format */ NULL, &error); 393 if (!cfObj) { 394 // any point in logging error reason here? nothing caller can do.... 395 goto finish; 396 } 397 398 if (CFGetTypeID(cfObj) != CFArrayGetTypeID()) { 399 CFRelease(cfObj); 400 goto finish; 401 } 402 valueArray = (CFMutableArrayRef) cfObj; 403 404finish: 405 406 SAFE_RELEASE(error); 407 SAFE_RELEASE(xmlData); 408 409 if (xml_data) { 410 vm_deallocate(mach_task_self(), (vm_address_t)xml_data, 411 xml_data_length); 412 } 413 return valueArray; 414} 415 416/********************************************************************* 417*********************************************************************/ 418static kern_return_t get_kextd_port(mach_port_t * kextd_port) 419{ 420 kern_return_t kern_result = kOSReturnError; 421 mach_port_t bootstrap_port = MACH_PORT_NULL; 422 423 kern_result = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); 424 if (kern_result == kOSReturnSuccess) { 425 kern_result = bootstrap_look_up2(bootstrap_port, 426 (char *)KEXTD_SERVER_NAME, 427 kextd_port, 428 0, 429 BOOTSTRAP_PRIVILEGED_SERVER); 430 } 431 432 return kern_result; 433} 434