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