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