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