1/* 2 * Copyright (c) 2000-2008 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include <CoreFoundation/CoreFoundation.h> 24#include <Security/Authorization.h> 25#include <IOKit/IOKitLib.h> 26#include <IOKit/IOKitServer.h> 27#include <libc.h> 28#include <mach/mach.h> 29#include <mach/mach_host.h> 30#include <mach/bootstrap.h> 31#include <mach/kmod.h> 32#include <notify.h> 33#include <sys/proc_info.h> 34#include <libproc.h> 35#include <libgen.h> 36#include <bsm/libbsm.h> 37#include <servers/bootstrap.h> // bootstrap mach ports 38#include <sandbox.h> 39#include <esp.h> 40 41#include <IOKit/kext/kextmanager_types.h> 42#include <IOKit/kext/OSKext.h> 43#include <IOKit/kext/OSKextPrivate.h> 44#include <IOKit/kext/KextManagerPriv.h> 45#include <System/libkern/kext_request_keys.h> 46 47#include "kext_tools_util.h" 48#include <bootfiles.h> 49#include "fork_program.h" 50#include "kextd_globals.h" 51#include "paths.h" 52#include "kextd_request.h" 53#include "kextd_main.h" 54#include "kextd_usernotification.h" 55 56#include "kextd_mach.h" // mig-generated, not in project 57 58#include "bootcaches.h" 59#include "security.h" 60 61 62#define setCrashLogMessage(m) 63 64 65#define CRASH_INFO_KERNEL_KEXT_LOAD "kernel kext load request: id %s" 66#define CRASH_INFO_KERNEL_KEXT_RESOURCE "kext resource request: %s from id %s" 67#define CRASH_INFO_USER_KEXT_LOAD "user kext load request: %s" 68#define CRASH_INFO_USER_KEXT_PATH "user kext path request: %s" 69#define CRASH_INFO_USER_PROPERTY "user kext property request: %s" 70 71kern_return_t sendPropertyValueResponse( 72 CFArrayRef propertyValues, 73 char ** xml_data_out, 74 int * xml_data_length); 75void kextdProcessKernelLoadRequest( 76 CFDictionaryRef request); 77void kextdProcessKernelResourceRequest( 78 CFDictionaryRef request); 79kern_return_t kextdProcessUserLoadRequest( 80 CFDictionaryRef request, 81 uid_t remote_euid, 82 pid_t remote_pid); 83static OSReturn checkNonrootLoadAllowed( 84 OSKextRef kext, 85 uid_t remote_euid, 86 pid_t remote_pid); 87 88#pragma mark KextManager RPC routines & support 89/******************************************************************************* 90*******************************************************************************/ 91kern_return_t _kextmanager_path_for_bundle_id( 92 mach_port_t server, 93 kext_bundle_id_t bundle_id, 94 posix_path_t path, // PATH_MAX 95 OSReturn * kext_result) 96{ 97 kern_return_t result = kOSReturnSuccess; 98 CFStringRef kextID = NULL; // must release 99 OSKextRef theKext = NULL; // must release 100 CFURLRef kextURL = NULL; // do not release 101 CFURLRef absURL = NULL; // must release 102 char crashInfo[sizeof(CRASH_INFO_USER_KEXT_PATH) + 103 KMOD_MAX_NAME + PATH_MAX]; 104 105 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_KEXT_PATH, 106 bundle_id); 107 108 setCrashLogMessage(crashInfo); 109 110 *kext_result = kOSReturnError; 111 path[0] = '\0'; 112 113 OSKextLog(/* kext */ NULL, 114 kOSKextLogDebugLevel | kOSKextLogIPCFlag, 115 "Received client request for path to bundle %s.", 116 bundle_id); 117 118 kextID = CFStringCreateWithCString(kCFAllocatorDefault, bundle_id, 119 kCFStringEncodingUTF8); 120 if (!kextID) { 121 OSKextLogMemError(); 122 *kext_result = kOSKextReturnNoMemory; 123 goto finish; 124 } 125 126 theKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, kextID); 127 if (!theKext) { 128 OSKextLog(/* kext */ NULL, 129 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 130 "Kext %s not found for client path request.", bundle_id); 131 *kext_result = kOSKextReturnNotFound; 132 goto finish; 133 } 134 kextURL = OSKextGetURL(theKext); 135 if (!kextURL) { 136 OSKextLog(/* kext */ NULL, 137 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 138 "Kext %s found for client path request, but has no URL.", bundle_id); 139 goto finish; 140 } 141 absURL = CFURLCopyAbsoluteURL(kextURL); 142 if (!absURL) { 143 OSKextLogMemError(); 144 *kext_result = kOSKextReturnNoMemory; 145 goto finish; 146 } 147 if (!CFURLGetFileSystemRepresentation(absURL, /* resolveToBase */ true, 148 (UInt8 *)path, PATH_MAX)) { 149 150 *kext_result = kOSKextReturnSerialization; 151 goto finish; 152 } 153 154 *kext_result = kOSReturnSuccess; 155 156 OSKextLog(/* kext */ NULL, 157 kOSKextLogDebugLevel | kOSKextLogIPCFlag, 158 "Returning path %s for identifier %s.", path, bundle_id); 159 160finish: 161 SAFE_RELEASE(kextID); 162 SAFE_RELEASE(theKext); 163 SAFE_RELEASE(absURL); 164 165 setCrashLogMessage(NULL); 166 167 return result; 168} 169 170#pragma mark Loginwindow RPC routines & support 171/******************************************************************************* 172* This function is executed in the main thread after its run loop gets 173* kicked by a client request. 174*******************************************************************************/ 175kern_return_t _kextmanager_create_property_value_array( 176 mach_port_t server, 177 char * property_key, 178 char ** xml_data_out, 179 int * xml_data_length) 180 181{ 182 kern_return_t result = kOSReturnError; 183 184 CFStringRef propertyKey = NULL; // must release 185 CFArrayRef propertyValues = NULL; // must release 186 char crashInfo[sizeof(CRASH_INFO_USER_PROPERTY) + 187 KMOD_MAX_NAME + PATH_MAX]; 188 189 OSKextLog(/* kext */ NULL, 190 kOSKextLogProgressLevel | kOSKextLogGeneralFlag, 191 "Received client request for property value array."); 192 193 if (!xml_data_out || !xml_data_length) { 194 result = kOSKextReturnInvalidArgument; 195 goto finish; 196 } 197 198 *xml_data_length = 0; 199 *xml_data_out = NULL; 200 201 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_PROPERTY, 202 property_key); 203 204 setCrashLogMessage(crashInfo); 205 206 propertyKey = CFStringCreateWithCString(kCFAllocatorDefault, property_key, 207 kCFStringEncodingUTF8); 208 if (!propertyKey) { 209 OSKextLogMemError(); 210 goto finish; 211 } 212 213 if (readSystemKextPropertyValues(propertyKey, gKernelArchInfo, 214 /* forceUpdate? */ FALSE, &propertyValues)) { 215 216 result = sendPropertyValueResponse(propertyValues, 217 xml_data_out, xml_data_length); 218 goto finish; 219 } 220 221finish: 222 SAFE_RELEASE(propertyKey); 223 SAFE_RELEASE(propertyValues); 224 225 setCrashLogMessage(NULL); 226 227 OSKextFlushInfoDictionary(NULL /* all kexts */); 228 OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true); 229 230 return result; 231} 232 233/******************************************************************************* 234*******************************************************************************/ 235kern_return_t sendPropertyValueResponse( 236 CFArrayRef propertyValues, 237 char ** xml_data_out, 238 int * xml_data_length) 239{ 240 kern_return_t result = kOSReturnError; 241 CFDataRef plistData = NULL; // must release 242 CFErrorRef error = NULL; // must relase 243 244 plistData = CFPropertyListCreateData(kCFAllocatorDefault, 245 propertyValues, kCFPropertyListBinaryFormat_v1_0, 246 /* options */ 0, 247 &error); 248 if (!plistData) { 249 OSKextLog(/* kext */ NULL, 250 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 251 "Can't create plist data for property value response."); 252 log_CFError(/* kext */ NULL, 253 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 254 error); 255 goto finish; 256 } 257 258 *xml_data_length = (int)CFDataGetLength(plistData); 259 260 if (*xml_data_length) { 261 result = vm_allocate(mach_task_self(), (vm_address_t *)xml_data_out, 262 *xml_data_length, VM_FLAGS_ANYWHERE); 263 if (result != kOSReturnSuccess) { 264 OSKextLog(/* kext */ NULL, 265 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 266 "vm_allocate() failed."); 267 goto finish; 268 } 269 memcpy(*xml_data_out, CFDataGetBytePtr(plistData), *xml_data_length); 270 } 271 272finish: 273 SAFE_RELEASE(plistData); 274 SAFE_RELEASE(error); 275 276 return result; 277} 278 279#pragma mark Kernel Kext Requests 280 281#define KEXTD_LOCKED() (_gKextutilLock ? true:false) 282 283/******************************************************************************* 284* Incoming MIG message from kernel to let us know we should fetch requests from 285* it using kextd_process_kernel_requests(). 286*******************************************************************************/ 287kern_return_t svc_kextd_ping(mach_port_t mp __unused) 288{ 289 bool shutdownRequested = false; 290 291 if (KEXTD_LOCKED()) { 292 gKernelRequestsPending = true; 293 return kOSReturnSuccess; 294 } else { 295 shutdownRequested = kextd_process_kernel_requests(); 296 if (shutdownRequested) { 297 CFRunLoopStop(CFRunLoopGetCurrent()); 298 } 299 } 300 return kOSReturnSuccess; 301} 302 303/******************************************************************************* 304*******************************************************************************/ 305bool kextd_process_kernel_requests(void) 306{ 307 CFArrayRef kernelRequests = NULL; // must release 308 Boolean loadNotificationReceived = false; 309 Boolean unloadNotificationReceived = false; 310 Boolean prelinkedKernelRequested = false; 311 Boolean shutdownRequested = false; 312 char * scratchCString = NULL; // must free 313 CFIndex count, i; 314 315 /* Stay in the while loop until _OSKextCopyKernelRequests() returns 316 * no more requests. 317 */ 318 while (1) { 319 SAFE_RELEASE_NULL(kernelRequests); 320 kernelRequests = _OSKextCopyKernelRequests(); 321 if (!kernelRequests || !CFArrayGetCount(kernelRequests)) { 322 break; 323 } 324 325 count = CFArrayGetCount(kernelRequests); 326 for (i = 0; i < count; i++) { 327 CFDictionaryRef request = NULL; // do not release 328 CFStringRef predicate = NULL; // do not release 329 330 SAFE_FREE_NULL(scratchCString); 331 332 request = CFArrayGetValueAtIndex(kernelRequests, i); 333 predicate = request ? CFDictionaryGetValue(request, 334 CFSTR(kKextRequestPredicateKey)) : NULL; 335 336 if (!request) { 337 OSKextLog(/* kext */ NULL, 338 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 339 "Empty kernel request."); 340 continue; 341 } 342 if (!predicate) { 343 OSKextLog(/* kext */ NULL, 344 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 345 "No predicate in kernel request."); 346 continue; 347 } 348 349 /* Check the request predicate and process it or note it needs 350 * to be processed. 351 */ 352 if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestPrelink))) { 353 OSKextLog(/* kext */ NULL, 354 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 355 "Got prelink kernel request."); 356 prelinkedKernelRequested = true; 357 } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestKextdExit))) { 358 OSKextLog(/* kext */ NULL, 359 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 360 "Got exit request from kernel."); 361 shutdownRequested = true; 362 } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestLoad))) { 363 OSKextLog(/* kext */ NULL, 364 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 365 "Got load request from kernel."); 366 kextdProcessKernelLoadRequest(request); 367 } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateLoadNotification))) { 368 /* We don't do anything with the kext identifier because notify(3) 369 * doesn't allow for an argument. 370 */ 371 loadNotificationReceived = true; 372 } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateUnloadNotification))) { 373 /* We don't do anything with the kext identifier because notify(3) 374 * doesn't allow for an argument. 375 */ 376 unloadNotificationReceived = true; 377 } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestResource))) { 378 OSKextLog(/* kext */ NULL, 379 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 380 "Got resource file request from kernel."); 381 kextdProcessKernelResourceRequest(request); 382 } else { 383 scratchCString = createUTF8CStringForCFString(predicate); 384 OSKextLog(/* kext */ NULL, 385 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 386 "Unknown predicate%s%s in kernel request.", 387 scratchCString ? " " : "", 388 scratchCString ? scratchCString : ""); 389 } 390 } /* for (i = 0; i < count; i++) */ 391 } /* while (1) */ 392 393// finish: 394 395 if (prelinkedKernelRequested) { 396 Boolean readOnlyFS = FALSE; 397 struct statfs statfsBuffer; 398 399 /* If the statfs() fails we will forge ahead and try kextcache. 400 * Only if we know for sure it's read-only do we skip. 401 */ 402 if (statfs("/System/Library/Caches", &statfsBuffer) == 0) { 403 if (statfsBuffer.f_flags & MNT_RDONLY) { 404 readOnlyFS = TRUE; 405 406 OSKextLog(/* kext */ NULL, 407 kOSKextLogProgressLevel | kOSKextLogFileAccessFlag, 408 "Skipping prelinked kernel build; read-only filesystem."); 409 } 410 } 411 412 if (!readOnlyFS) { 413 char * const kextcacheArgs[] = { 414 "/usr/sbin/kextcache", 415 "-F", 416 "-system-prelinked-kernel", 417 NULL }; 418 419 OSKextLog(/* kext */ NULL, 420 kOSKextLogProgressLevel | kOSKextLogGeneralFlag, 421 "Building prelinked kernel."); 422 423 (void)fork_program("/usr/sbin/kextcache", 424 kextcacheArgs, 425 /* waitFlag */ false); 426 } 427 } 428 429 if (loadNotificationReceived) { 430 notify_post(kOSKextLoadNotification); 431 } 432 if (unloadNotificationReceived) { 433 notify_post(kOSKextUnloadNotification); 434 } 435 436 gKernelRequestsPending = false; 437 438 SAFE_FREE(scratchCString); 439 SAFE_RELEASE(kernelRequests); 440 441 OSKextFlushInfoDictionary(NULL /* all kexts */); 442 OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true); 443 444 return shutdownRequested; 445} 446 447/******************************************************************************* 448* Kernel load request. 449*******************************************************************************/ 450void 451kextdProcessKernelLoadRequest(CFDictionaryRef request) 452{ 453 CFDictionaryRef requestArgs = NULL; // do not release 454 OSKextRef osKext = NULL; // do not release 455 OSReturn osLoadResult = kOSKextReturnNotFound; 456 457 CFArrayRef loadList = NULL; // must release 458 CFStringRef kextIdentifier = NULL; // do not release 459 char * kext_id = NULL; // must free 460 char crashInfo[sizeof(CRASH_INFO_KERNEL_KEXT_LOAD) + KMOD_MAX_NAME + PATH_MAX]; 461 462 requestArgs = request ? CFDictionaryGetValue(request, 463 CFSTR(kKextRequestArgumentsKey)) : NULL; 464 kextIdentifier = requestArgs ? CFDictionaryGetValue(requestArgs, 465 CFSTR(kKextRequestArgumentBundleIdentifierKey)) : NULL; 466 467 if (!requestArgs) { 468 OSKextLog(/* kext */ NULL, 469 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 470 "No arguments in kernel kext load request."); 471 goto finish; 472 } 473 if (!kextIdentifier) { 474 OSKextLog(/* kext */ NULL, 475 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 476 "No kext ID in kernel kext load request."); 477 goto finish; 478 } 479 kext_id = createUTF8CStringForCFString(kextIdentifier); 480 if (!kext_id) { 481 // xxx - not much we can do here. 482 OSKextLogMemError(); 483 goto finish; 484 } 485 486 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_KERNEL_KEXT_LOAD, 487 kext_id); 488 489 setCrashLogMessage(crashInfo); 490 491 /* Read the extensions if necessary (also resets the release timer). 492 */ 493 readExtensions(); 494 495 OSKextLog(/* kext */ NULL, 496 kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 497 "Kernel requests kext with id %s.", kext_id); 498 499 osKext = OSKextGetKextWithIdentifier(kextIdentifier); 500 if (!osKext) { 501 OSKextLog(/* kext */ NULL, 502 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 503 "Kext id %s not found; removing personalities from kernel.", kext_id); 504 OSKextRemovePersonalitiesForIdentifierFromKernel(kextIdentifier); 505 goto finish; 506 } 507 508 /* xxx - under what circumstances should we remove personalities? 509 * xxx - if the request gets into the kernel and fails, OSKext.cpp 510 * xxx - removes them, but there can be other failures on the way.... 511 */ 512 OSStatus sigResult = checkKextSignature(osKext, true); 513 if ( sigResult != 0 ) { 514 CFMutableDictionaryRef myAlertInfoDict = NULL; // must release 515 OSReturn myResult = kOSReturnSuccess; 516 517 if ( isInLibraryExtensionsFolder(osKext) || 518 sigResult == CSSMERR_TP_CERT_REVOKED ) { 519 /* Do not load if kext has invalid signature and comes from 520 * /Library/Extensions/ 521 */ 522 CFStringRef myBundleID; // do not release 523 524 myBundleID = OSKextGetIdentifier(osKext); 525 myResult = kOSKextReturnNotLoadable; // see 13024670 526 OSKextLogCFString(NULL, 527 kOSKextLogErrorLevel | 528 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 529 CFSTR("ERROR: invalid signature for %@, will not load"), 530 myBundleID ? myBundleID : CFSTR("Unknown")); 531 } 532 533 /* Put up alert if this is the first time we've seen this 534 * kext and it is not an Apple kext. 535 */ 536 addKextToAlertDict(&myAlertInfoDict, osKext); 537 if (myAlertInfoDict) { 538 CFRetain(myAlertInfoDict); // writeKextAlertPlist or sendRevokedCertAlert will release 539 if (sigResult == CSSMERR_TP_CERT_REVOKED) { 540 dispatch_async(dispatch_get_main_queue(), ^ { 541 sendRevokedCertAlert(myAlertInfoDict); 542 }); 543 } 544 else if (myResult == kOSKextReturnNotLoadable) { 545 dispatch_async(dispatch_get_main_queue(), ^ { 546 writeKextAlertPlist(myAlertInfoDict, NO_LOAD_KEXT_ALERT); 547 }); 548 } 549#if 0 // not yet 550 else if (sigResult == errSecCSUnsigned) { 551 dispatch_async(dispatch_get_main_queue(), ^ { 552 writeKextAlertPlist(myAlertInfoDict, UNSIGNED_KEXT_ALERT); 553 }); 554 } 555#endif 556 else { 557 dispatch_async(dispatch_get_main_queue(), ^ { 558 writeKextAlertPlist(myAlertInfoDict, INVALID_SIGNATURE_KEXT_ALERT); 559 }); 560 } 561 SAFE_RELEASE(myAlertInfoDict); 562 } 563 564 if (myResult != kOSReturnSuccess) { 565 OSKextLog(/* kext */ NULL, 566 kOSKextLogErrorLevel | kOSKextLogLoadFlag | 567 kOSKextLogIPCFlag, 568 "Load %s failed; removing personalities from kernel.", 569 kext_id); 570 OSKextRemoveKextPersonalitiesFromKernel(osKext); 571 goto finish; 572 } 573 CFStringRef myKextPath = NULL; // must release 574 myKextPath = copyKextPath(osKext); 575 if ( myKextPath ) { 576 OSKextLogCFString(NULL, 577 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 578 CFSTR("WARNING - Invalid signature %ld 0x%02lX for kext \"%@\""), 579 (long)sigResult, (long)sigResult, myKextPath); 580 SAFE_RELEASE(myKextPath); 581 } 582 } 583 584 osLoadResult = OSKextLoad(osKext); 585 if (osLoadResult != kOSReturnSuccess) { 586 OSKextLog(/* kext */ NULL, 587 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 588 "Load %s failed; removing personalities from kernel.", kext_id); 589 OSKextRemoveKextPersonalitiesFromKernel(osKext); 590 } else { 591 if (kOSReturnSuccess != IOCatalogueModuleLoaded( 592 kIOMasterPortDefault, kext_id)) { 593 594 OSKextLog(/* kext */ NULL, 595 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 596 "Failed to notify IOCatalogue that %s loaded.", 597 kext_id); 598 } else { 599 OSKextLog(/* kext */ NULL, 600 kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 601 "Loaded %s and notified IOCatalogue.", 602 kext_id); 603 } 604 } 605 606 if (osLoadResult == kOSKextReturnAuthentication) { 607 loadList = OSKextCopyLoadList(osKext, /* needAll? */ false); 608 recordNonsecureKexts(loadList); 609 } 610 611finish: 612 SAFE_RELEASE(loadList); 613 SAFE_FREE(kext_id); 614 setCrashLogMessage(NULL); 615 616 return; 617} 618 619/******************************************************************************* 620* Kernel resource file request. 621*******************************************************************************/ 622#define kDSStoreFilename ".DS_Store" 623 624void 625kextdProcessKernelResourceRequest( 626 CFDictionaryRef request) 627{ 628 CFDictionaryRef requestArgs = NULL; // do not release 629 OSKextRef osKext = NULL; // must release 630 CFDataRef resource = NULL; // must release 631 OSReturn requestResult = kOSKextReturnInvalidArgument; 632 633 CFStringRef kextIdentifier = NULL; // do not release 634 CFStringRef resourceName = NULL; // do not release 635 CFURLRef kextURL = NULL; // do not release 636 char * kextIdentifierCString = NULL; // must free 637 char * resourceNameCString = NULL; // must free 638 char kextPathCString[PATH_MAX]; 639 char crashInfo[sizeof(CRASH_INFO_KERNEL_KEXT_RESOURCE) + 640 KMOD_MAX_NAME + PATH_MAX]; 641 642 requestArgs = request ? CFDictionaryGetValue(request, 643 CFSTR(kKextRequestArgumentsKey)) : NULL; 644 kextIdentifier = requestArgs ? CFDictionaryGetValue(requestArgs, 645 CFSTR(kKextRequestArgumentBundleIdentifierKey)) : NULL; 646 resourceName = requestArgs ? CFDictionaryGetValue(requestArgs, 647 CFSTR(kKextRequestArgumentNameKey)) : NULL; 648 649 OSKextLog(/* kext */ NULL, 650 kOSKextLogDebugLevel | kOSKextLogIPCFlag, 651 "Request for resource."); 652 653 if (!requestArgs) { 654 OSKextLog(/* kext */ NULL, 655 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 656 "No arguments in kernel kext resource request."); 657 goto finish; 658 } 659 if (!kextIdentifier) { 660 OSKextLog(/* kext */ NULL, 661 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 662 "No kext ID in kernel kext resource request."); 663 goto finish; 664 } 665 if (!resourceName) { 666 OSKextLog(/* kext */ NULL, 667 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 668 "No resource name in kernel kext resource request."); 669 goto finish; 670 } 671 672 requestResult = kOSKextReturnNoMemory; 673 674 kextIdentifierCString = createUTF8CStringForCFString(kextIdentifier); 675 resourceNameCString = createUTF8CStringForCFString(resourceName); 676 if (!kextIdentifierCString || !resourceNameCString) { 677 // xxx - not much we can do here. 678 OSKextLogMemError(); 679 goto finish; 680 } 681 682 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_KERNEL_KEXT_RESOURCE, 683 resourceNameCString, kextIdentifierCString); 684 685 setCrashLogMessage(crashInfo); 686 687 if (CFEqual(resourceName, CFSTR(kDSStoreFilename))) { 688 requestResult = kOSKextReturnInvalidArgument; 689 OSKextLog(/* kext */ NULL, 690 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogFileAccessFlag, 691 "Request for %s resource by %s - not allowed.", 692 kDSStoreFilename, kextIdentifierCString); 693 goto finish; 694 } 695 696 /* Read the extensions if necessary (also resets the release timer). 697 */ 698 readExtensions(); 699 700 OSKextLog(/* kext */ NULL, 701 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 702 "Kernel requests resource %s from kext id %s.", 703 resourceNameCString, kextIdentifierCString); 704 705 requestResult = kOSKextReturnNotFound; 706 707 osKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, kextIdentifier); 708 if (!osKext) { 709 OSKextLog(/* kext */ NULL, 710 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 711 "Kext id %s not found; can't retrieve requested resource.", 712 kextIdentifierCString); 713 goto finish; 714 } 715 716 kextURL = OSKextGetURL(osKext); 717 if (!kextURL || 718 !CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase? */ TRUE, 719 (UInt8 *)kextPathCString, sizeof(kextPathCString))) { 720 721 strlcpy(kextPathCString, "(unknown)", sizeof("(unknown)")); 722 } 723 724 OSKextLog(/* kext */ NULL, 725 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 726 "Seeking resource %s in %s.", 727 resourceNameCString, kextPathCString); 728 729 if (!OSKextIsValid(osKext)) { 730 OSKextLog(/* kext */ NULL, 731 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogValidationFlag, 732 "%s is not valid; can't retrieve requested resource.", 733 kextPathCString); 734 requestResult = kOSKextReturnValidation; 735 goto finish; 736 } 737 738 739 if (!OSKextIsAuthentic(osKext)) { 740 OSKextLog(/* kext */ NULL, 741 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogAuthenticationFlag, 742 "%s is not authentic; can't retrieve requested resource.", 743 kextPathCString); 744 requestResult = kOSKextReturnAuthentication; 745 goto finish; 746 } 747 748 resource = OSKextCopyResource(osKext, resourceName, 749 /* resourceType */ NULL); 750 if (!resource) { 751 OSKextLog(/* kext */ NULL, 752 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogFileAccessFlag, 753 "Can't find resource %s in %s.", 754 resourceNameCString, kextPathCString); 755 requestResult = kOSKextReturnNotFound; 756 goto finish; 757 } 758 759 requestResult = kOSReturnSuccess; 760 761 OSKextLog(/* kext */ NULL, 762 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogValidationFlag, 763 "Found resource %s in %s; sending to kernel.", 764 resourceNameCString, kextPathCString); 765 766finish: 767 // now we send it to the kernel 768 (void) _OSKextSendResource(request, requestResult, resource); 769 770 SAFE_RELEASE(resource); 771 SAFE_RELEASE(osKext); 772 SAFE_FREE(kextIdentifierCString); 773 SAFE_FREE(resourceNameCString); 774 setCrashLogMessage(NULL); 775 return; 776} 777 778#pragma mark User Space Kext Load Requests 779/******************************************************************************* 780* User space load request. 781*******************************************************************************/ 782kern_return_t 783_kextmanager_load_kext( 784 mach_port_t server, 785 audit_token_t audit_token, 786 char * xml_data_in, 787 int xml_data_length) 788{ 789 OSReturn result = kOSReturnError; 790 CFDataRef requestData = NULL; // must release 791 CFDictionaryRef request = NULL; // must release 792 CFErrorRef error = NULL; // must release 793 pid_t remote_pid = -1; 794 uid_t remote_euid = -1; 795 796 requestData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, 797 (const UInt8 *)xml_data_in, xml_data_length, 798 /* deallocator */ kCFAllocatorNull); 799 if (!requestData) { 800 OSKextLogMemError(); 801 result = kOSKextReturnNoMemory; 802 goto finish; 803 } 804 request = CFPropertyListCreateWithData(kCFAllocatorDefault, 805 requestData, /* options */ 0, /* format */ NULL, 806 &error); 807 if (!request) { 808 OSKextLog(/* kext */ NULL, 809 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 810 "Can't read kext load request."); 811 log_CFError(/* kext */ NULL, 812 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 813 error); 814 result = kOSKextReturnSerialization; 815 goto finish; 816 } 817 if (CFGetTypeID(request) != CFDictionaryGetTypeID()) { 818 result = kOSKextReturnBadData; 819 goto finish; 820 } 821 822 audit_token_to_au32(audit_token, /* audit UID */ NULL, 823 &remote_euid, /* egid */ NULL, /* ruid */ NULL, /* rgid */ NULL, 824 &remote_pid, /* asid */ NULL, /* au_tid_t */ NULL); 825 826 result = kextdProcessUserLoadRequest(request, remote_euid, remote_pid); 827 828finish: 829 SAFE_RELEASE(requestData); 830 SAFE_RELEASE(request); 831 SAFE_RELEASE(error); 832 833 OSKextFlushInfoDictionary(NULL /* all kexts */); 834 OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true); 835 836 /* MIG is consume-on-success 837 * xxx - do we need separate result & op-result? 838 */ 839 if (result == kOSReturnSuccess) { 840 vm_deallocate(mach_task_self(), (vm_address_t)xml_data_in, 841 (vm_size_t)xml_data_length); 842 } 843 return result; 844} 845 846/******************************************************************************* 847*******************************************************************************/ 848const char * nameForPID(pid_t pid) 849{ 850 char * result = NULL; 851 int path_length = 0; 852 char path[PROC_PIDPATHINFO_MAXSIZE]; 853 854 path_length = proc_pidpath(pid, path, 855 sizeof(path)); 856 if (path_length > 0) { 857 result = basename(path); 858 } 859 if (!result) { 860 result = "(unknown)"; 861 } 862 return result; 863} 864 865/******************************************************************************* 866*******************************************************************************/ 867#define UNKNOWN_KEXT "unknown kext" 868#define SYSTEM_FOLDER "/System/" 869 870#define _kSystemExtensionsDirSlash (kSystemExtensionsDir "/") 871#define _kLibraryExtensionsDirSlash (kLibraryExtensionsDir "/") 872#define _kSystemFilesystemsDirSlash ("/System/Library/Filesystems/") 873 874/******************************************************************************* 875*******************************************************************************/ 876static CFURLRef createAbsOrRealURLForURL( 877 CFURLRef anURL, 878 uid_t remote_euid, 879 pid_t remote_pid, 880 OSReturn * error) 881{ 882 CFURLRef result = NULL; 883 OSReturn localError = kOSReturnSuccess; 884 Boolean inLE = FALSE; 885 Boolean inSLE = FALSE; 886 Boolean inSLF = FALSE; 887 char urlPathCString[PATH_MAX]; 888 char realpathCString[PATH_MAX]; 889 890 if (!CFURLGetFileSystemRepresentation(anURL, /* resolveToBase? */ TRUE, 891 (UInt8 *)urlPathCString, sizeof(urlPathCString))) 892 { 893 OSKextLog(/* kext */ NULL, 894 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 895 "Can't get path from URL for kext load request."); 896 localError = kOSKextReturnSerialization; 897 goto finish; 898 } 899 900 if (remote_euid == 0) { 901 result = CFURLCopyAbsoluteURL(anURL); 902 if (!result) { 903 OSKextLogMemError(); 904 goto finish; 905 } 906 goto finish; 907 } else { 908 909 inSLE = (0 == strncmp(urlPathCString, _kSystemExtensionsDirSlash, 910 strlen(_kSystemExtensionsDirSlash))); 911 inLE = (0 == strncmp(urlPathCString, _kLibraryExtensionsDirSlash, 912 strlen(_kLibraryExtensionsDirSlash))); 913 inSLF = (0 == strncmp(urlPathCString, _kSystemFilesystemsDirSlash, 914 strlen(_kSystemFilesystemsDirSlash))); 915 916 /***** 917 * May want to open these checks to use OSKextGetSystemExtensionsFolderURLs(). 918 * For now, keep it tight and just do /System/Library/Extensions & Filesystems. 919 */ 920 if (!inSLE && !inSLF && !inLE) { 921 localError = kOSKextReturnNotPrivileged; 922 if (!inSLE && !inSLF) { 923 OSKextLog(/* kext */ NULL, 924 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 925 "Request from non-root process '%s' (euid %d) to load %s - " 926 "not in extensions dirs or filesystems folder.", 927 nameForPID(remote_pid), remote_euid, urlPathCString); 928 } 929 goto finish; 930 } 931 932 if (!realpath(urlPathCString, realpathCString)) { 933 934 localError = kOSReturnError; // xxx - should we have a filesystem error? 935 OSKextLog(/* kext */ NULL, 936 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 937 "Unable to resolve raw path %s.", urlPathCString); 938 goto finish; 939 } 940 941 /***** 942 * Check the path once more now that we've resolved it with realpath(). 943 */ 944 inSLE = (0 == strncmp(realpathCString, _kSystemExtensionsDirSlash, 945 strlen(_kSystemExtensionsDirSlash))); 946 inLE = (0 == strncmp(urlPathCString, _kLibraryExtensionsDirSlash, 947 strlen(_kLibraryExtensionsDirSlash))); 948 inSLF = (0 == strncmp(realpathCString, _kSystemFilesystemsDirSlash, 949 strlen(_kSystemFilesystemsDirSlash))); 950 951 if (!inSLE && !inSLF && !inLE) { 952 953 localError = kOSKextReturnNotPrivileged; 954 OSKextLog(/* kext */ NULL, 955 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 956 "Request from non-root process '%s' (euid %d) to load %s - " 957 "(real path %s) - not in extensions dirs or filesystems folder.", 958 nameForPID(remote_pid), remote_euid, urlPathCString, 959 realpathCString); 960 goto finish; 961 } 962 } 963 964 result = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 965 (UInt8 *)realpathCString, strlen(realpathCString), /* isDir */ TRUE); 966 if (!result) { 967 OSKextLogMemError(); 968 goto finish; 969 } 970 971finish: 972 if (error) { 973 *error = localError; 974 } 975 return result; 976} 977 978/******************************************************************************* 979*******************************************************************************/ 980static OSReturn 981checkNonrootLoadAllowed( 982 OSKextRef kext, 983 uid_t remote_euid, 984 pid_t remote_pid) 985{ 986 OSReturn result = kOSKextReturnNotPrivileged; 987 CFArrayRef loadList = NULL; // must release 988 CFStringRef kextPath = NULL; // must release 989 Boolean kextAllows = TRUE; 990 char kextPathCString[PATH_MAX]; 991 CFIndex count, index; 992 993 loadList = OSKextCopyLoadList(kext, /* needAll?*/ TRUE); 994 if (!loadList) { 995 OSKextLog(/* kext */ NULL, 996 kOSKextLogErrorLevel | kOSKextLogLoadFlag | 997 kOSKextLogDependenciesFlag | kOSKextLogIPCFlag, 998 "Can't resolve dependencies for kext load request."); 999 result = kOSKextReturnDependencies; 1000 goto finish; 1001 } 1002 1003 count = CFArrayGetCount(loadList); 1004 for (index = count - 1; index >= 0; index--) { 1005 OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex(loadList, index); 1006 CFBooleanRef allowed = (CFBooleanRef)OSKextGetValueForInfoDictionaryKey( 1007 thisKext, CFSTR(kOSBundleAllowUserLoadKey)); 1008 CFURLRef kextURL = OSKextGetURL(thisKext); 1009 1010 SAFE_RELEASE_NULL(kextPath); 1011 1012 kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle); 1013 if (!kextPath) { 1014 OSKextLogMemError(); 1015 result = kOSKextReturnNoMemory; 1016 } 1017 if (!CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase? */ TRUE, 1018 (UInt8 *)kextPathCString, sizeof(kextPathCString))) { 1019 strlcpy(kextPathCString, UNKNOWN_KEXT, sizeof(UNKNOWN_KEXT)); 1020 OSKextLog(/* kext */ NULL, 1021 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1022 "Can't get path from URL for kext load request."); 1023 result = kOSKextReturnSerialization; 1024 goto finish; 1025 } 1026 1027 if (!allowed || 1028 (CFGetTypeID(allowed) != CFBooleanGetTypeID()) || 1029 !CFBooleanGetValue(allowed)) { 1030 1031 kextAllows = FALSE; 1032 goto finish; 1033 } 1034 } 1035 1036 result = kOSReturnSuccess; 1037 1038finish: 1039 SAFE_RELEASE(loadList); 1040 SAFE_RELEASE(kextPath); 1041 1042 if (!kextAllows) { 1043 result = kOSKextReturnNotPrivileged; 1044 1045 OSKextLog(/* kext */ NULL, 1046 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1047 "Request from non-root process '%s' (euid %d) to load %s - not allowed.", 1048 nameForPID(remote_pid), remote_euid, kextPathCString); 1049 } 1050 1051 return result; 1052} 1053 1054/******************************************************************************* 1055*******************************************************************************/ 1056kern_return_t 1057kextdProcessUserLoadRequest( 1058 CFDictionaryRef request, 1059 uid_t remote_euid, 1060 pid_t remote_pid) 1061{ 1062 OSReturn result = kOSReturnSuccess; 1063 CFStringRef kextID = NULL; // do not release 1064 char * kextIDString = NULL; // must free 1065 CFStringRef kextPath = NULL; // do not release 1066 CFArrayRef dependencyPaths = NULL; // do not release 1067 CFURLRef kextURL = NULL; // must release 1068 CFURLRef kextAbsURL = NULL; // must release 1069 OSKextRef theKext = NULL; // must release 1070 CFArrayRef kexts = NULL; // must release 1071 CFMutableArrayRef dependencyURLs = NULL; // must release 1072 CFURLRef dependencyURL = NULL; // must release 1073 CFURLRef dependencyAbsURL = NULL; // must release 1074 CFArrayRef dependencyKexts = NULL; // must release 1075 CFArrayRef loadList = NULL; // must release 1076 1077 char kextPathString[PATH_MAX] = "unknown"; 1078 char crashInfo[sizeof(CRASH_INFO_USER_KEXT_LOAD) + 1079 KMOD_MAX_NAME + PATH_MAX]; 1080 CFIndex count, index; 1081 1082 /* First get the identifier or URL to load, and convert it to a C string 1083 * for logging. 1084 */ 1085 kextID = (CFStringRef)CFDictionaryGetValue(request, kKextLoadIdentifierKey); 1086 if (kextID) { 1087 if (CFGetTypeID(kextID) != CFStringGetTypeID()) { 1088 result = kOSKextReturnInvalidArgument; 1089 goto finish; 1090 } 1091 kextIDString = createUTF8CStringForCFString(kextID); 1092 if (!kextIDString) { 1093 OSKextLogMemError(); 1094 goto finish; 1095 } 1096 } else { 1097 kextPath = (CFStringRef)CFDictionaryGetValue(request, kKextLoadPathKey); 1098 if (!kextPath || CFGetTypeID(kextPath) != CFStringGetTypeID()) { 1099 result = kOSKextReturnInvalidArgument; 1100 goto finish; 1101 } 1102 1103 if (!CFStringHasPrefix(kextPath, CFSTR("/"))) { 1104 OSKextLog(/* kext */ NULL, 1105 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1106 "Error: Request from '%s' (euid %d) to load kext with relative path.", 1107 nameForPID(remote_pid), remote_euid); 1108 result = kOSKextReturnInvalidArgument; 1109 goto finish; 1110 } 1111 1112 kextURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 1113 kextPath, kCFURLPOSIXPathStyle, /* isDir? */ true); 1114 if (!kextURL) { 1115 result = kOSKextReturnSerialization; // xxx - or other? 1116 goto finish; 1117 } 1118 result = kOSReturnError; 1119 kextAbsURL = createAbsOrRealURLForURL(kextURL, 1120 remote_euid, remote_pid, &result); 1121 if (!kextAbsURL) { 1122 goto finish; 1123 } 1124 CFURLGetFileSystemRepresentation(kextAbsURL, /* resolveToBase */ true, 1125 (UInt8 *)kextPathString, 1126 sizeof(kextPathString)); 1127 } 1128 1129 /* Read the extensions if necessary (also resets the release timer). 1130 */ 1131 readExtensions(); 1132 1133 /* Now log before the attempt, then try to look up or create the kext. 1134 */ 1135 if (remote_euid != 0) { 1136 OSKextLog(/* kext */ NULL, 1137 kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1138 "Request from '%s' (euid %d) to load %s.", 1139 nameForPID(remote_pid), remote_euid, 1140 kextIDString ? kextIDString : kextPathString); 1141 } 1142 1143 /* Open any dependencies provided, *before* we create the kext, since 1144 * a request by identifier must be resolvable from the dependencies 1145 * as well as system extensions folders. 1146 */ 1147 dependencyPaths = (CFArrayRef)CFDictionaryGetValue(request, 1148 kKextLoadDependenciesKey); 1149 if (dependencyPaths) { 1150 if (CFGetTypeID(dependencyPaths) != CFArrayGetTypeID()) { 1151 result = kOSKextReturnInvalidArgument; 1152 goto finish; 1153 } 1154 1155 count = CFArrayGetCount(dependencyPaths); 1156 1157 dependencyURLs = CFArrayCreateMutable(kCFAllocatorDefault, 1158 /* capacity */ count, 1159 &kCFTypeArrayCallBacks); 1160 if (!dependencyURLs) { 1161 result = kOSKextReturnNoMemory; 1162 goto finish; 1163 } 1164 1165 for (index = 0; index < count; index++) { 1166 CFStringRef thisPath = (CFStringRef)CFArrayGetValueAtIndex( 1167 dependencyPaths, index); 1168 1169 SAFE_RELEASE_NULL(dependencyURL); 1170 SAFE_RELEASE_NULL(dependencyAbsURL); 1171 if (CFGetTypeID(thisPath) != CFStringGetTypeID()) { 1172 result = kOSKextReturnInvalidArgument; 1173 goto finish; 1174 } 1175 if (!CFStringHasPrefix(thisPath, CFSTR("/"))) { 1176 OSKextLog(/* kext */ NULL, 1177 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1178 "Error: Request to load kext using dependency with relative path."); 1179 result = kOSKextReturnInvalidArgument; 1180 goto finish; 1181 } 1182 1183 dependencyURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 1184 thisPath, kCFURLPOSIXPathStyle, /* isDir? */ true); 1185 if (!dependencyURL) { 1186 result = kOSKextReturnSerialization; // xxx - or other? 1187 goto finish; 1188 } 1189 result = kOSReturnError; 1190 dependencyAbsURL = createAbsOrRealURLForURL(dependencyURL, 1191 remote_euid, remote_pid, &result); 1192 if (!dependencyAbsURL) { 1193 goto finish; 1194 } 1195 CFArrayAppendValue(dependencyURLs, dependencyAbsURL); 1196 } 1197 dependencyKexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault, 1198 dependencyURLs); 1199 if (!dependencyKexts) { 1200 result = kOSReturnError; 1201 goto finish; 1202 } 1203 } 1204 1205 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_KEXT_LOAD, 1206 kextIDString ? kextIDString : kextPathString); 1207 1208 setCrashLogMessage(crashInfo); 1209 1210 1211 if (kextID) { 1212 theKext = OSKextGetKextWithIdentifier(kextID); 1213 if (theKext) { 1214 CFRetain(theKext); // we're going to release it 1215 } 1216 } else { 1217 /* Make sure we also read the plugins of the kext we're asked to load, 1218 * but only if we manage to open the kext itself (or we'll get too many 1219 * error messages). 1220 */ 1221 theKext = OSKextCreate(kCFAllocatorDefault, kextAbsURL); 1222 if (theKext) { 1223 kexts = OSKextCreateKextsFromURL(kCFAllocatorDefault, kextAbsURL); 1224 kextIDString = createUTF8CStringForCFString(OSKextGetIdentifier(theKext)); 1225 if (!kextIDString) { 1226 OSKextLogMemError(); 1227 goto finish; 1228 } 1229 } 1230 } 1231 1232 if (!theKext) { 1233 OSKextLog(/* kext */ NULL, 1234 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1235 "Error: Kext %s - not found/unable to create.", 1236 kextIDString ? kextIDString : kextPathString); 1237 result = kOSKextReturnNotFound; 1238 goto finish; 1239 } 1240 1241 if (remote_euid != 0) { 1242 result = checkNonrootLoadAllowed(theKext, remote_euid, remote_pid); 1243 if (result != kOSReturnSuccess) { 1244 goto finish; 1245 } 1246 } 1247 1248 /* Get dictionary of all our excluded kexts */ 1249 if (OSKextIsInExcludeList(theKext, false)) { 1250 CFMutableDictionaryRef myAlertInfoDict = NULL; // must release 1251 addKextToAlertDict(&myAlertInfoDict, theKext); 1252 if (myAlertInfoDict) { 1253 CFRetain(myAlertInfoDict); // writeKextAlertPlist will release 1254 dispatch_async(dispatch_get_main_queue(), ^ { 1255 writeKextAlertPlist(myAlertInfoDict, EXCLUDED_KEXT_ALERT); 1256 }); 1257 SAFE_RELEASE(myAlertInfoDict); 1258 } 1259 1260 messageTraceExcludedKext(theKext); 1261 OSKextLog(NULL, 1262 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1263 kOSKextLogValidationFlag | kOSKextLogGeneralFlag, 1264 "%s is in exclude list; omitting.", 1265 kextIDString ? kextIDString : kextPathString); 1266 result = kOSKextReturnNotLoadable; 1267 goto finish; 1268 } 1269 1270 if (__esp_enabled()) { 1271 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); 1272 if (dict == NULL) { 1273 result = kOSKextReturnNotLoadable; 1274 goto finish; 1275 } 1276 xpc_dictionary_set_int64(dict, "euid", remote_euid); 1277 xpc_dictionary_set_int64(dict, "pid", remote_pid); 1278 if (kextIDString != NULL) { 1279 xpc_dictionary_set_string(dict, "kextID", kextIDString); 1280 } 1281 if (kextPathString != NULL) { 1282 xpc_dictionary_set_string(dict, "kextPath", kextPathString); 1283 } 1284 int esp_result = __esp_check("kext-load", dict); 1285 xpc_release(dict); 1286 if (esp_result != 0) { 1287 result = kOSKextReturnNotLoadable; 1288 goto finish; 1289 } 1290 } 1291 1292 /* consult sandboxing system to make sure this is OK 1293 * <rdar://problem/11015459 1294 */ 1295 if (sandbox_check(remote_pid, "system-kext-load", 1296 SANDBOX_FILTER_KEXT_BUNDLE_ID, 1297 kextIDString) != 0 ) { 1298 OSKextLog(NULL, 1299 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1300 kOSKextLogValidationFlag | kOSKextLogGeneralFlag, 1301 "%s failed sandbox check; omitting.", kextIDString); 1302 result = kOSKextReturnNotLoadable; 1303 goto finish; 1304 } 1305 1306 OSStatus sigResult = checkKextSignature(theKext, true); 1307 if ( sigResult != 0 ) { 1308 if ( isInLibraryExtensionsFolder(theKext) || 1309 sigResult == CSSMERR_TP_CERT_REVOKED ) { 1310 /* Do not load if kext has invalid signature and comes from 1311 * /Library/Extensions/ 1312 */ 1313 CFStringRef myBundleID; // do not release 1314 1315 myBundleID = OSKextGetIdentifier(theKext); 1316 result = kOSKextReturnNotLoadable; // see 13024670 1317 OSKextLogCFString(NULL, 1318 kOSKextLogErrorLevel | 1319 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1320 CFSTR("ERROR: invalid signature for %@, will not load"), 1321 myBundleID ? myBundleID : CFSTR("Unknown")); 1322 } 1323 1324 /* Put up alert if this is the first time we've seen this 1325 * kext and it is not an Apple kext 1326 */ 1327 CFMutableDictionaryRef myAlertInfoDict = NULL; // must release 1328 1329 addKextToAlertDict(&myAlertInfoDict, theKext); 1330 if (myAlertInfoDict) { 1331 CFRetain(myAlertInfoDict); // writeKextAlertPlist or sendRevokedCertAlert will release 1332 if (sigResult == CSSMERR_TP_CERT_REVOKED) { 1333 dispatch_async(dispatch_get_main_queue(), ^ { 1334 sendRevokedCertAlert(myAlertInfoDict); 1335 }); 1336 } 1337 else if (result == kOSKextReturnNotLoadable) { 1338 dispatch_async(dispatch_get_main_queue(), ^ { 1339 writeKextAlertPlist(myAlertInfoDict, NO_LOAD_KEXT_ALERT); 1340 }); 1341 } 1342#if 0 // not yet 1343 else if (sigResult == errSecCSUnsigned) { 1344 dispatch_async(dispatch_get_main_queue(), ^ { 1345 writeKextAlertPlist(myAlertInfoDict, UNSIGNED_KEXT_ALERT); 1346 }); 1347 } 1348#endif 1349 else { 1350 dispatch_async(dispatch_get_main_queue(), ^ { 1351 writeKextAlertPlist(myAlertInfoDict, INVALID_SIGNATURE_KEXT_ALERT); 1352 }); 1353 } 1354 SAFE_RELEASE(myAlertInfoDict); 1355 } // myAlertInfoDict 1356 } 1357 if (result != kOSReturnSuccess) { 1358 goto finish; 1359 } 1360 if (sigResult != 0) { 1361 CFStringRef myKextPath = NULL; // must release 1362 myKextPath = copyKextPath(theKext); 1363 if ( myKextPath ) { 1364 OSKextLogCFString(NULL, 1365 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1366 CFSTR("WARNING - Invalid signature %ld 0x%02lX for kext \"%@\""), 1367 (long)sigResult, (long)sigResult, myKextPath); 1368 SAFE_RELEASE(myKextPath); 1369 } 1370 } 1371 1372 /* <rdar://problem/12435992> 1373 */ 1374 recordKextLoadForMT(theKext); 1375 1376 /* The codepath from this function will do any error logging 1377 * and cleanup needed. 1378 */ 1379 result = OSKextLoadWithOptions(theKext, 1380 /* statExclusion */ kOSKextExcludeNone, 1381 /* addPersonalitiesExclusion */ kOSKextExcludeNone, 1382 /* personalityNames */ NULL, 1383 /* delayAutounloadFlag */ false); 1384 1385 if (result == kOSKextReturnAuthentication) { 1386 loadList = OSKextCopyLoadList(theKext, /* needAll? */ false); 1387 recordNonsecureKexts(loadList); 1388 } 1389 1390finish: 1391 SAFE_RELEASE(kextURL); 1392 SAFE_RELEASE(kextAbsURL); 1393 SAFE_RELEASE(kexts); 1394 SAFE_RELEASE(theKext); 1395 SAFE_RELEASE(dependencyURLs); 1396 SAFE_RELEASE(dependencyURL); 1397 SAFE_RELEASE(dependencyAbsURL); 1398 SAFE_RELEASE(dependencyKexts); 1399 SAFE_RELEASE(loadList); 1400 SAFE_FREE(kextIDString); 1401 1402 setCrashLogMessage(NULL); 1403 1404 return result; 1405} 1406