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 29extern "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 39extern "C" { 40 41#if PRAGMA_MARK 42#pragma mark C-based kext interface (loading/loaded kexts only) 43#endif 44/********************************************************************* 45*********************************************************************/ 46kern_return_t OSKextLoadKextWithIdentifier(const char * bundle_id) 47{ 48 return OSKext::loadKextWithIdentifier(bundle_id); 49} 50 51/********************************************************************* 52*********************************************************************/ 53uint32_t 54OSKextGetLoadTagForIdentifier(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 } 67finish: 68 if (theKext) theKext->release(); 69 return result; 70} 71 72/********************************************************************* 73*********************************************************************/ 74OSReturn 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 } 104finish: 105 return result; 106} 107 108/********************************************************************* 109*********************************************************************/ 110OSReturn 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()? 141finish: 142 return result; 143} 144 145/********************************************************************* 146* Not to be called by the kext being unloaded! 147*********************************************************************/ 148OSReturn 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*********************************************************************/ 161OSReturn 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*********************************************************************/ 174OSReturn 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*********************************************************************/ 189kern_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 337finish: 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*********************************************************************/ 356extern vm_offset_t segPRELINKB; 357extern unsigned long segSizePRELINK; 358extern int kth_started; 359extern vm_map_t g_kext_map; 360 361vm_map_t 362kext_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 384void 385kext_weak_symbol_referenced(void) 386{ 387 panic("A kext referenced an unresolved weak symbol\n"); 388} 389 390const 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*********************************************************************/ 398void OSKextRemoveKextBootstrap(void) 399{ 400 OSKext::removeKextBootstrap(); 401 return; 402} 403 404#if CONFIG_DTRACE 405/********************************************************************* 406*********************************************************************/ 407void OSKextRegisterKextsWithDTrace(void) 408{ 409 OSKext::registerKextsWithDTrace(); 410 return; 411} 412#endif /* CONFIG_DTRACE */ 413 414/********************************************************************* 415*********************************************************************/ 416void 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*********************************************************************/ 438void 439kmod_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/********************************************************************/ 449void kmod_dump_log(vm_offset_t *addr, unsigned int cnt, boolean_t doUnslide); 450 451void 452kmod_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 469void 470OSKextLoadedKextSummariesUpdated(void) 471{ 472 // Do nothing. 473} 474 475}; 476