1 /* 2 * Copyright (c) 2008-2012 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 29 extern "C" { 30 #include <libkern/OSKextLibPrivate.h> 31 #include <libkern/mkext.h> 32 }; 33 34 #include <libkern/c++/OSContainers.h> 35 #include <libkern/c++/OSKext.h> 36 #include <libkern/OSKextLib.h> 37 #include <libkern/OSKextLibPrivate.h> 38 39 extern "C" { 40 41 #if PRAGMA_MARK 42 #pragma mark C-based kext interface (loading/loaded kexts only) 43 #endif 44 /********************************************************************* 45 *********************************************************************/ 46 kern_return_t OSKextLoadKextWithIdentifier(const char * bundle_id) 47 { 48 return OSKext::loadKextWithIdentifier(bundle_id); 49 } 50 51 /********************************************************************* 52 *********************************************************************/ 53 uint32_t 54 OSKextGetLoadTagForIdentifier(const char * kextIdentifier) 55 { 56 uint32_t result = kOSKextInvalidLoadTag; 57 OSKext * theKext = NULL; // must release 58 59 if (!kextIdentifier) { 60 goto finish; 61 } 62 63 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier); 64 if (theKext && theKext->isLoaded()) { 65 result = theKext->getLoadTag(); 66 } 67 finish: 68 if (theKext) theKext->release(); 69 return result; 70 } 71 72 /********************************************************************* 73 *********************************************************************/ 74 OSReturn OSKextRetainKextWithLoadTag(uint32_t loadTag) 75 { 76 OSReturn result = kOSKextReturnNotFound; 77 OSKext * theKext = NULL; // do not release; as this function is a retain 78 79 if (loadTag == kOSKextInvalidLoadTag) { 80 result = kOSKextReturnInvalidArgument; 81 goto finish; 82 } 83 theKext = OSKext::lookupKextWithLoadTag(loadTag); 84 if (theKext) { 85 result = kOSReturnSuccess; 86 87 OSKextLog(theKext, 88 kOSKextLogDebugLevel | 89 kOSKextLogKextBookkeepingFlag, 90 "Kext %s (load tag %d) has been retained.", 91 theKext->getIdentifierCString(), 92 loadTag); 93 94 /* Call this after so a log message about autounload comes second. 95 */ 96 theKext->setAutounloadEnabled(true); 97 } else { 98 OSKextLog(theKext, 99 kOSKextLogErrorLevel | 100 kOSKextLogKextBookkeepingFlag, 101 "Can't retain kext with load tag %d - no such kext is loaded.", 102 loadTag); 103 } 104 finish: 105 return result; 106 } 107 108 /********************************************************************* 109 *********************************************************************/ 110 OSReturn OSKextReleaseKextWithLoadTag(uint32_t loadTag) 111 { 112 OSReturn result = kOSKextReturnNotFound; 113 OSKext * theKext = NULL; // must release twice! 114 115 if (loadTag == kOSKextInvalidLoadTag) { 116 result = kOSKextReturnInvalidArgument; 117 goto finish; 118 } 119 theKext = OSKext::lookupKextWithLoadTag(loadTag); 120 if (theKext) { 121 result = kOSReturnSuccess; 122 OSKext::considerUnloads(); // schedule autounload pass 123 theKext->release(); // do the release the caller wants 124 theKext->release(); // now do the release on the lookup 125 OSKextLog(theKext, 126 kOSKextLogDebugLevel | 127 kOSKextLogKextBookkeepingFlag, 128 "Kext %s (load tag %d) has been released.", 129 theKext->getIdentifierCString(), 130 loadTag); 131 } else { 132 OSKextLog(theKext, 133 kOSKextLogErrorLevel | 134 kOSKextLogKextBookkeepingFlag, 135 "Can't release kext with load tag %d - no such kext is loaded.", 136 loadTag); 137 } 138 139 // xxx - should I check that the refcount of the OSKext is above the lower bound? 140 // xxx - do we want a OSKextGetRetainCountOfKextWithLoadTag()? 141 finish: 142 return result; 143 } 144 145 /********************************************************************* 146 * Not to be called by the kext being unloaded! 147 *********************************************************************/ 148 OSReturn OSKextUnloadKextWithLoadTag(uint32_t loadTag) 149 { 150 return OSKext::removeKextWithLoadTag(loadTag, 151 /* terminateServicesAndRemovePersonalitiesFlag */ false); 152 } 153 154 155 #if PRAGMA_MARK 156 #pragma mark Kext Requests 157 #endif 158 /********************************************************************* 159 * Kext Requests 160 *********************************************************************/ 161 OSReturn OSKextRequestResource( 162 const char * kextIdentifier, 163 const char * resourceName, 164 OSKextRequestResourceCallback callback, 165 void * context, 166 OSKextRequestTag * requestTagOut) 167 { 168 return OSKext::requestResource(kextIdentifier, resourceName, 169 callback, context, requestTagOut); 170 } 171 172 /********************************************************************* 173 *********************************************************************/ 174 OSReturn OSKextCancelRequest( 175 OSKextRequestTag requestTag, 176 void ** contextOut) 177 { 178 return OSKext::cancelRequest(requestTag, contextOut); 179 } 180 181 #if PRAGMA_MARK 182 #pragma mark MIG Functions & Wrappers 183 #endif 184 /********************************************************************* 185 * IMPORTANT: Once we have done the vm_map_copyout(), we *must* return 186 * KERN_SUCCESS or the kernel map gets messed up (reason as yet 187 * unknown). We use op_result to return the real result of our work. 188 *********************************************************************/ 189 kern_return_t kext_request( 190 host_priv_t hostPriv, 191 /* in only */ uint32_t clientLogSpec, 192 /* in only */ vm_offset_t requestIn, 193 /* in only */ mach_msg_type_number_t requestLengthIn, 194 /* out only */ vm_offset_t * responseOut, 195 /* out only */ mach_msg_type_number_t * responseLengthOut, 196 /* out only */ vm_offset_t * logDataOut, 197 /* out only */ mach_msg_type_number_t * logDataLengthOut, 198 /* out only */ kern_return_t * op_result) 199 { 200 kern_return_t result = KERN_FAILURE; 201 vm_map_address_t map_addr = 0; // do not free/deallocate 202 char * request = NULL; // must vm_deallocate 203 204 mkext2_header * mkextHeader = NULL; // do not release 205 bool isMkext = false; 206 207 char * response = NULL; // must kmem_free 208 uint32_t responseLength = 0; 209 char * logData = NULL; // must kmem_free 210 uint32_t logDataLength = 0; 211 212 /* MIG doesn't pass "out" parameters as empty, so clear them immediately 213 * just in case, or MIG will try to copy out bogus data. 214 */ 215 *op_result = KERN_FAILURE; 216 *responseOut = NULL; 217 *responseLengthOut = 0; 218 *logDataOut = NULL; 219 *logDataLengthOut = 0; 220 221 /* Check for input. Don't discard what isn't there, though. 222 */ 223 if (!requestLengthIn || !requestIn) { 224 OSKextLog(/* kext */ NULL, 225 kOSKextLogErrorLevel | 226 kOSKextLogIPCFlag, 227 "Invalid request from user space (no data)."); 228 *op_result = KERN_INVALID_ARGUMENT; 229 goto finish; 230 } 231 232 /* Once we have done the vm_map_copyout(), we *must* return KERN_SUCCESS 233 * or the kernel map gets messed up (reason as yet unknown). We will use 234 * op_result to return the real result of our work. 235 */ 236 result = vm_map_copyout(kernel_map, &map_addr, (vm_map_copy_t)requestIn); 237 if (result != KERN_SUCCESS) { 238 OSKextLog(/* kext */ NULL, 239 kOSKextLogErrorLevel | 240 kOSKextLogIPCFlag, 241 "vm_map_copyout() failed for request from user space."); 242 vm_map_copy_discard((vm_map_copy_t)requestIn); 243 goto finish; 244 } 245 request = CAST_DOWN(char *, map_addr); 246 247 /* Check if request is an mkext; this is always a load request 248 * and requires root access. If it isn't an mkext, see if it's 249 * an XML request, and check the request to see if that requires 250 * root access. 251 */ 252 if (requestLengthIn > sizeof(mkext2_header)) { 253 mkextHeader = (mkext2_header *)request; 254 if (MKEXT_GET_MAGIC(mkextHeader) == MKEXT_MAGIC && 255 MKEXT_GET_SIGNATURE(mkextHeader) == MKEXT_SIGN) { 256 257 isMkext = true; 258 } 259 } 260 261 if (isMkext) { 262 #ifdef SECURE_KERNEL 263 // xxx - something tells me if we have a secure kernel we don't even 264 // xxx - want to log a message here. :-) 265 *op_result = KERN_NOT_SUPPORTED; 266 goto finish; 267 #else 268 // xxx - can we find out if calling task is kextd? 269 // xxx - can we find the name of the calling task? 270 if (hostPriv == HOST_PRIV_NULL) { 271 OSKextLog(/* kext */ NULL, 272 kOSKextLogErrorLevel | 273 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 274 "Attempt by non-root process to load a kext."); 275 *op_result = kOSKextReturnNotPrivileged; 276 goto finish; 277 } 278 279 *op_result = OSKext::loadFromMkext((OSKextLogSpec)clientLogSpec, 280 request, requestLengthIn, 281 &logData, &logDataLength); 282 283 #endif /* defined(SECURE_KERNEL) */ 284 285 } else { 286 287 /* If the request isn't an mkext, then is should be XML. Parse it 288 * if possible and hand the request over to OSKext. 289 */ 290 *op_result = OSKext::handleRequest(hostPriv, 291 (OSKextLogSpec)clientLogSpec, 292 request, requestLengthIn, 293 &response, &responseLength, 294 &logData, &logDataLength); 295 } 296 297 if (response && responseLength > 0) { 298 kern_return_t copyin_result; 299 300 copyin_result = vm_map_copyin(kernel_map, 301 CAST_USER_ADDR_T(response), responseLength, 302 /* src_destroy */ false, (vm_map_copy_t *)responseOut); 303 if (copyin_result == KERN_SUCCESS) { 304 *responseLengthOut = responseLength; 305 } else { 306 OSKextLog(/* kext */ NULL, 307 kOSKextLogErrorLevel | 308 kOSKextLogIPCFlag, 309 "Failed to copy response to request from user space."); 310 *op_result = copyin_result; // xxx - should we map to our own code? 311 *responseOut = NULL; 312 *responseLengthOut = 0; 313 goto finish; 314 } 315 } 316 317 if (logData && logDataLength > 0) { 318 kern_return_t copyin_result; 319 320 copyin_result = vm_map_copyin(kernel_map, 321 CAST_USER_ADDR_T(logData), logDataLength, 322 /* src_destroy */ false, (vm_map_copy_t *)logDataOut); 323 if (copyin_result == KERN_SUCCESS) { 324 *logDataLengthOut = logDataLength; 325 } else { 326 OSKextLog(/* kext */ NULL, 327 kOSKextLogErrorLevel | 328 kOSKextLogIPCFlag, 329 "Failed to copy log data for request from user space."); 330 *op_result = copyin_result; // xxx - should we map to our own code? 331 *logDataOut = NULL; 332 *logDataLengthOut = 0; 333 goto finish; 334 } 335 } 336 337 finish: 338 if (request) { 339 (void)vm_deallocate(kernel_map, (vm_offset_t)request, requestLengthIn); 340 } 341 if (response) { 342 /* 11981737 - clear uninitialized data in last page */ 343 kmem_free(kernel_map, (vm_offset_t)response, round_page(responseLength)); 344 } 345 if (logData) { 346 /* 11981737 - clear uninitialized data in last page */ 347 kmem_free(kernel_map, (vm_offset_t)logData, round_page(logDataLength)); 348 } 349 350 return result; 351 } 352 353 /********************************************************************* 354 * Gets the vm_map for the current kext 355 *********************************************************************/ 356 extern vm_offset_t segPRELINKB; 357 extern unsigned long segSizePRELINK; 358 extern int kth_started; 359 extern vm_map_t g_kext_map; 360 361 vm_map_t 362 kext_get_vm_map(kmod_info_t *info) 363 { 364 vm_map_t kext_map = NULL; 365 366 /* Set the vm map */ 367 if ((info->address >= segPRELINKB) && 368 (info->address < (segPRELINKB + segSizePRELINK))) 369 { 370 kext_map = kernel_map; 371 } else { 372 kext_map = g_kext_map; 373 } 374 375 return kext_map; 376 } 377 378 379 #if PRAGMA_MARK 380 /********************************************************************/ 381 #pragma mark Weak linking support 382 /********************************************************************/ 383 #endif 384 void 385 kext_weak_symbol_referenced(void) 386 { 387 panic("A kext referenced an unresolved weak symbol\n"); 388 } 389 390 const void *gOSKextUnresolved = (const void *)&kext_weak_symbol_referenced; 391 392 #if PRAGMA_MARK 393 #pragma mark Kernel-Internal C Functions 394 #endif 395 /********************************************************************* 396 * Called from startup.c. 397 *********************************************************************/ 398 void OSKextRemoveKextBootstrap(void) 399 { 400 OSKext::removeKextBootstrap(); 401 return; 402 } 403 404 #if CONFIG_DTRACE 405 /********************************************************************* 406 *********************************************************************/ 407 void OSKextRegisterKextsWithDTrace(void) 408 { 409 OSKext::registerKextsWithDTrace(); 410 return; 411 } 412 #endif /* CONFIG_DTRACE */ 413 414 /********************************************************************* 415 *********************************************************************/ 416 void kext_dump_panic_lists(int (*printf_func)(const char * fmt, ...)) 417 { 418 OSKext::printKextPanicLists(printf_func); 419 return; 420 } 421 422 #if PRAGMA_MARK 423 #pragma mark Kmod Compatibility Functions 424 #endif 425 /********************************************************************* 426 ********************************************************************** 427 * KMOD COMPATIBILITY FUNCTIONS * 428 * (formerly in kmod.c, or C++ bridges from) * 429 ********************************************************************** 430 ********************************************************************** 431 * These two functions are used in various places in the kernel, but 432 * are not exported. We might rename them at some point to start with 433 * kext_ or OSKext. 434 * 435 * kmod_panic_dump() must not be called outside of a panic context. 436 * kmod_dump_log() must not be called in a panic context. 437 *********************************************************************/ 438 void 439 kmod_panic_dump(vm_offset_t * addr, unsigned int cnt) 440 { 441 extern int kdb_printf(const char *format, ...) __printflike(1,2); 442 443 OSKext::printKextsInBacktrace(addr, cnt, &kdb_printf, 444 /* takeLock? */ false, false); 445 return; 446 } 447 448 /********************************************************************/ 449 void kmod_dump_log(vm_offset_t *addr, unsigned int cnt, boolean_t doUnslide); 450 451 void 452 kmod_dump_log( 453 vm_offset_t * addr, 454 unsigned int cnt, 455 boolean_t doUnslide) 456 { 457 OSKext::printKextsInBacktrace(addr, cnt, &printf, /* lock? */ true, doUnslide); 458 } 459 460 /********************************************************************* 461 * Compatibility implementation for kmod_get_info() host_priv routine. 462 * Only supported on old 32-bit architectures. 463 *********************************************************************/ 464 465 #if PRAGMA_MARK 466 #pragma mark Loaded Kext Summary 467 #endif 468 469 void 470 OSKextLoadedKextSummariesUpdated(void) 471 { 472 // Do nothing. 473 } 474 475 }; 476