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, false); 513 if ( sigResult != 0 ) { 514 if ( isInvalidSignatureAllowed() ) { 515 CFStringRef myKextPath = NULL; // must release 516 517 myKextPath = copyKextPath(osKext); 518 OSKextLogCFString(NULL, 519 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 520 CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext \"%@\""), 521 (long)sigResult, (long)sigResult, 522 myKextPath ? myKextPath : CFSTR("Unknown")); 523 SAFE_RELEASE(myKextPath); 524 } 525 else { 526 CFStringRef myBundleID = NULL; // do not release 527 528 myBundleID = OSKextGetIdentifier(osKext); 529 OSKextLogCFString(NULL, 530 kOSKextLogErrorLevel | 531 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 532 CFSTR("ERROR: invalid signature for %@, will not load"), 533 myBundleID ? myBundleID : CFSTR("Unknown")); 534 OSKextRemoveKextPersonalitiesFromKernel(osKext); 535 goto finish; 536 } 537 } 538 539 osLoadResult = OSKextLoad(osKext); 540 if (osLoadResult != kOSReturnSuccess) { 541 OSKextLog(/* kext */ NULL, 542 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 543 "Load %s failed; removing personalities from kernel.", kext_id); 544 OSKextRemoveKextPersonalitiesFromKernel(osKext); 545 } else { 546 if (kOSReturnSuccess != IOCatalogueModuleLoaded( 547 kIOMasterPortDefault, kext_id)) { 548 549 OSKextLog(/* kext */ NULL, 550 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 551 "Failed to notify IOCatalogue that %s loaded.", 552 kext_id); 553 } else { 554 OSKextLog(/* kext */ NULL, 555 kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 556 "Loaded %s and notified IOCatalogue.", 557 kext_id); 558 } 559 } 560 561 if (osLoadResult == kOSKextReturnAuthentication) { 562 loadList = OSKextCopyLoadList(osKext, /* needAll? */ false); 563 recordNonsecureKexts(loadList); 564 } 565 566finish: 567 SAFE_RELEASE(loadList); 568 SAFE_FREE(kext_id); 569 setCrashLogMessage(NULL); 570 571 return; 572} 573 574/******************************************************************************* 575* Kernel resource file request. 576*******************************************************************************/ 577#define kDSStoreFilename ".DS_Store" 578 579void 580kextdProcessKernelResourceRequest( 581 CFDictionaryRef request) 582{ 583 CFDictionaryRef requestArgs = NULL; // do not release 584 OSKextRef osKext = NULL; // must release 585 CFDataRef resource = NULL; // must release 586 OSReturn requestResult = kOSKextReturnInvalidArgument; 587 588 CFStringRef kextIdentifier = NULL; // do not release 589 CFStringRef resourceName = NULL; // do not release 590 CFURLRef kextURL = NULL; // do not release 591 char * kextIdentifierCString = NULL; // must free 592 char * resourceNameCString = NULL; // must free 593 char kextPathCString[PATH_MAX]; 594 char crashInfo[sizeof(CRASH_INFO_KERNEL_KEXT_RESOURCE) + 595 KMOD_MAX_NAME + PATH_MAX]; 596 597 requestArgs = request ? CFDictionaryGetValue(request, 598 CFSTR(kKextRequestArgumentsKey)) : NULL; 599 kextIdentifier = requestArgs ? CFDictionaryGetValue(requestArgs, 600 CFSTR(kKextRequestArgumentBundleIdentifierKey)) : NULL; 601 resourceName = requestArgs ? CFDictionaryGetValue(requestArgs, 602 CFSTR(kKextRequestArgumentNameKey)) : NULL; 603 604 OSKextLog(/* kext */ NULL, 605 kOSKextLogDebugLevel | kOSKextLogIPCFlag, 606 "Request for resource."); 607 608 if (!requestArgs) { 609 OSKextLog(/* kext */ NULL, 610 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 611 "No arguments in kernel kext resource request."); 612 goto finish; 613 } 614 if (!kextIdentifier) { 615 OSKextLog(/* kext */ NULL, 616 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 617 "No kext ID in kernel kext resource request."); 618 goto finish; 619 } 620 if (!resourceName) { 621 OSKextLog(/* kext */ NULL, 622 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 623 "No resource name in kernel kext resource request."); 624 goto finish; 625 } 626 627 requestResult = kOSKextReturnNoMemory; 628 629 kextIdentifierCString = createUTF8CStringForCFString(kextIdentifier); 630 resourceNameCString = createUTF8CStringForCFString(resourceName); 631 if (!kextIdentifierCString || !resourceNameCString) { 632 // xxx - not much we can do here. 633 OSKextLogMemError(); 634 goto finish; 635 } 636 637 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_KERNEL_KEXT_RESOURCE, 638 resourceNameCString, kextIdentifierCString); 639 640 setCrashLogMessage(crashInfo); 641 642 if (CFEqual(resourceName, CFSTR(kDSStoreFilename))) { 643 requestResult = kOSKextReturnInvalidArgument; 644 OSKextLog(/* kext */ NULL, 645 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogFileAccessFlag, 646 "Request for %s resource by %s - not allowed.", 647 kDSStoreFilename, kextIdentifierCString); 648 goto finish; 649 } 650 651 /* Read the extensions if necessary (also resets the release timer). 652 */ 653 readExtensions(); 654 655 OSKextLog(/* kext */ NULL, 656 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 657 "Kernel requests resource %s from kext id %s.", 658 resourceNameCString, kextIdentifierCString); 659 660 requestResult = kOSKextReturnNotFound; 661 662 osKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, kextIdentifier); 663 if (!osKext) { 664 OSKextLog(/* kext */ NULL, 665 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 666 "Kext id %s not found; can't retrieve requested resource.", 667 kextIdentifierCString); 668 goto finish; 669 } 670 671 kextURL = OSKextGetURL(osKext); 672 if (!kextURL || 673 !CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase? */ TRUE, 674 (UInt8 *)kextPathCString, sizeof(kextPathCString))) { 675 676 strlcpy(kextPathCString, "(unknown)", sizeof("(unknown)")); 677 } 678 679 OSKextLog(/* kext */ NULL, 680 kOSKextLogProgressLevel | kOSKextLogIPCFlag, 681 "Seeking resource %s in %s.", 682 resourceNameCString, kextPathCString); 683 684 if (!OSKextIsValid(osKext)) { 685 OSKextLog(/* kext */ NULL, 686 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogValidationFlag, 687 "%s is not valid; can't retrieve requested resource.", 688 kextPathCString); 689 requestResult = kOSKextReturnValidation; 690 goto finish; 691 } 692 693 694 if (!OSKextIsAuthentic(osKext)) { 695 OSKextLog(/* kext */ NULL, 696 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogAuthenticationFlag, 697 "%s has incorrect permissions; can't retrieve requested resource.", 698 kextPathCString); 699 requestResult = kOSKextReturnAuthentication; 700 goto finish; 701 } 702 703 resource = OSKextCopyResource(osKext, resourceName, 704 /* resourceType */ NULL); 705 if (!resource) { 706 OSKextLog(/* kext */ NULL, 707 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogFileAccessFlag, 708 "Can't find resource %s in %s.", 709 resourceNameCString, kextPathCString); 710 requestResult = kOSKextReturnNotFound; 711 goto finish; 712 } 713 714 requestResult = kOSReturnSuccess; 715 716 OSKextLog(/* kext */ NULL, 717 kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogValidationFlag, 718 "Found resource %s in %s; sending to kernel.", 719 resourceNameCString, kextPathCString); 720 721finish: 722 // now we send it to the kernel 723 (void) _OSKextSendResource(request, requestResult, resource); 724 725 SAFE_RELEASE(resource); 726 SAFE_RELEASE(osKext); 727 SAFE_FREE(kextIdentifierCString); 728 SAFE_FREE(resourceNameCString); 729 setCrashLogMessage(NULL); 730 return; 731} 732 733#pragma mark User Space Kext Load Requests 734/******************************************************************************* 735* User space load request. 736*******************************************************************************/ 737kern_return_t 738_kextmanager_load_kext( 739 mach_port_t server, 740 audit_token_t audit_token, 741 char * xml_data_in, 742 int xml_data_length) 743{ 744 OSReturn result = kOSReturnError; 745 CFDataRef requestData = NULL; // must release 746 CFDictionaryRef request = NULL; // must release 747 CFErrorRef error = NULL; // must release 748 pid_t remote_pid = -1; 749 uid_t remote_euid = -1; 750 751 requestData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, 752 (const UInt8 *)xml_data_in, xml_data_length, 753 /* deallocator */ kCFAllocatorNull); 754 if (!requestData) { 755 OSKextLogMemError(); 756 result = kOSKextReturnNoMemory; 757 goto finish; 758 } 759 request = CFPropertyListCreateWithData(kCFAllocatorDefault, 760 requestData, /* options */ 0, /* format */ NULL, 761 &error); 762 if (!request) { 763 OSKextLog(/* kext */ NULL, 764 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 765 "Can't read kext load request."); 766 log_CFError(/* kext */ NULL, 767 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 768 error); 769 result = kOSKextReturnSerialization; 770 goto finish; 771 } 772 if (CFGetTypeID(request) != CFDictionaryGetTypeID()) { 773 result = kOSKextReturnBadData; 774 goto finish; 775 } 776 777 audit_token_to_au32(audit_token, /* audit UID */ NULL, 778 &remote_euid, /* egid */ NULL, /* ruid */ NULL, /* rgid */ NULL, 779 &remote_pid, /* asid */ NULL, /* au_tid_t */ NULL); 780 781 result = kextdProcessUserLoadRequest(request, remote_euid, remote_pid); 782 783finish: 784 SAFE_RELEASE(requestData); 785 SAFE_RELEASE(request); 786 SAFE_RELEASE(error); 787 788 OSKextFlushInfoDictionary(NULL /* all kexts */); 789 OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true); 790 791 /* MIG is consume-on-success 792 * xxx - do we need separate result & op-result? 793 */ 794 if (result == kOSReturnSuccess) { 795 vm_deallocate(mach_task_self(), (vm_address_t)xml_data_in, 796 (vm_size_t)xml_data_length); 797 } 798 return result; 799} 800 801/******************************************************************************* 802*******************************************************************************/ 803const char * nameForPID(pid_t pid) 804{ 805 char * result = NULL; 806 int path_length = 0; 807 char path[PROC_PIDPATHINFO_MAXSIZE]; 808 809 path_length = proc_pidpath(pid, path, 810 sizeof(path)); 811 if (path_length > 0) { 812 result = basename(path); 813 } 814 if (!result) { 815 result = "(unknown)"; 816 } 817 return result; 818} 819 820/******************************************************************************* 821*******************************************************************************/ 822#define UNKNOWN_KEXT "unknown kext" 823#define SYSTEM_FOLDER "/System/" 824 825#define _kSystemExtensionsDirSlash (kSystemExtensionsDir "/") 826#define _kLibraryExtensionsDirSlash (kLibraryExtensionsDir "/") 827#define _kSystemFilesystemsDirSlash ("/System/Library/Filesystems/") 828 829/******************************************************************************* 830*******************************************************************************/ 831static CFURLRef createAbsOrRealURLForURL( 832 CFURLRef anURL, 833 uid_t remote_euid, 834 pid_t remote_pid, 835 OSReturn * error) 836{ 837 CFURLRef result = NULL; 838 OSReturn localError = kOSReturnSuccess; 839 Boolean inLE = FALSE; 840 Boolean inSLE = FALSE; 841 Boolean inSLF = FALSE; 842 char urlPathCString[PATH_MAX]; 843 char realpathCString[PATH_MAX]; 844 845 if (!CFURLGetFileSystemRepresentation(anURL, /* resolveToBase? */ TRUE, 846 (UInt8 *)urlPathCString, sizeof(urlPathCString))) 847 { 848 OSKextLog(/* kext */ NULL, 849 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 850 "Can't get path from URL for kext load request."); 851 localError = kOSKextReturnSerialization; 852 goto finish; 853 } 854 855 if (remote_euid == 0) { 856 result = CFURLCopyAbsoluteURL(anURL); 857 if (!result) { 858 OSKextLogMemError(); 859 goto finish; 860 } 861 goto finish; 862 } else { 863 864 inSLE = (0 == strncmp(urlPathCString, _kSystemExtensionsDirSlash, 865 strlen(_kSystemExtensionsDirSlash))); 866 inLE = (0 == strncmp(urlPathCString, _kLibraryExtensionsDirSlash, 867 strlen(_kLibraryExtensionsDirSlash))); 868 inSLF = (0 == strncmp(urlPathCString, _kSystemFilesystemsDirSlash, 869 strlen(_kSystemFilesystemsDirSlash))); 870 871 /***** 872 * May want to open these checks to use OSKextGetSystemExtensionsFolderURLs(). 873 * For now, keep it tight and just do /System/Library/Extensions & Filesystems. 874 */ 875 if (!inSLE && !inSLF && !inLE) { 876 localError = kOSKextReturnNotPrivileged; 877 if (!inSLE && !inSLF) { 878 OSKextLog(/* kext */ NULL, 879 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 880 "Request from non-root process '%s' (euid %d) to load %s - " 881 "not in extensions dirs or filesystems folder.", 882 nameForPID(remote_pid), remote_euid, urlPathCString); 883 } 884 goto finish; 885 } 886 887 if (!realpath(urlPathCString, realpathCString)) { 888 889 localError = kOSReturnError; // xxx - should we have a filesystem error? 890 OSKextLog(/* kext */ NULL, 891 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 892 "Unable to resolve raw path %s.", urlPathCString); 893 goto finish; 894 } 895 896 /***** 897 * Check the path once more now that we've resolved it with realpath(). 898 */ 899 inSLE = (0 == strncmp(realpathCString, _kSystemExtensionsDirSlash, 900 strlen(_kSystemExtensionsDirSlash))); 901 inLE = (0 == strncmp(urlPathCString, _kLibraryExtensionsDirSlash, 902 strlen(_kLibraryExtensionsDirSlash))); 903 inSLF = (0 == strncmp(realpathCString, _kSystemFilesystemsDirSlash, 904 strlen(_kSystemFilesystemsDirSlash))); 905 906 if (!inSLE && !inSLF && !inLE) { 907 908 localError = kOSKextReturnNotPrivileged; 909 OSKextLog(/* kext */ NULL, 910 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 911 "Request from non-root process '%s' (euid %d) to load %s - " 912 "(real path %s) - not in extensions dirs or filesystems folder.", 913 nameForPID(remote_pid), remote_euid, urlPathCString, 914 realpathCString); 915 goto finish; 916 } 917 } 918 919 result = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, 920 (UInt8 *)realpathCString, strlen(realpathCString), /* isDir */ TRUE); 921 if (!result) { 922 OSKextLogMemError(); 923 goto finish; 924 } 925 926finish: 927 if (error) { 928 *error = localError; 929 } 930 return result; 931} 932 933/******************************************************************************* 934*******************************************************************************/ 935static OSReturn 936checkNonrootLoadAllowed( 937 OSKextRef kext, 938 uid_t remote_euid, 939 pid_t remote_pid) 940{ 941 OSReturn result = kOSKextReturnNotPrivileged; 942 CFArrayRef loadList = NULL; // must release 943 CFStringRef kextPath = NULL; // must release 944 Boolean kextAllows = TRUE; 945 char kextPathCString[PATH_MAX]; 946 CFIndex count, index; 947 948 loadList = OSKextCopyLoadList(kext, /* needAll?*/ TRUE); 949 if (!loadList) { 950 OSKextLog(/* kext */ NULL, 951 kOSKextLogErrorLevel | kOSKextLogLoadFlag | 952 kOSKextLogDependenciesFlag | kOSKextLogIPCFlag, 953 "Can't resolve dependencies for kext load request."); 954 result = kOSKextReturnDependencies; 955 goto finish; 956 } 957 958 count = CFArrayGetCount(loadList); 959 for (index = count - 1; index >= 0; index--) { 960 OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex(loadList, index); 961 CFBooleanRef allowed = (CFBooleanRef)OSKextGetValueForInfoDictionaryKey( 962 thisKext, CFSTR(kOSBundleAllowUserLoadKey)); 963 CFURLRef kextURL = OSKextGetURL(thisKext); 964 965 SAFE_RELEASE_NULL(kextPath); 966 967 kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle); 968 if (!kextPath) { 969 OSKextLogMemError(); 970 result = kOSKextReturnNoMemory; 971 } 972 if (!CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase? */ TRUE, 973 (UInt8 *)kextPathCString, sizeof(kextPathCString))) { 974 strlcpy(kextPathCString, UNKNOWN_KEXT, sizeof(UNKNOWN_KEXT)); 975 OSKextLog(/* kext */ NULL, 976 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 977 "Can't get path from URL for kext load request."); 978 result = kOSKextReturnSerialization; 979 goto finish; 980 } 981 982 if (!allowed || 983 (CFGetTypeID(allowed) != CFBooleanGetTypeID()) || 984 !CFBooleanGetValue(allowed)) { 985 986 kextAllows = FALSE; 987 goto finish; 988 } 989 } 990 991 result = kOSReturnSuccess; 992 993finish: 994 SAFE_RELEASE(loadList); 995 SAFE_RELEASE(kextPath); 996 997 if (!kextAllows) { 998 result = kOSKextReturnNotPrivileged; 999 1000 OSKextLog(/* kext */ NULL, 1001 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1002 "Request from non-root process '%s' (euid %d) to load %s - not allowed.", 1003 nameForPID(remote_pid), remote_euid, kextPathCString); 1004 } 1005 1006 return result; 1007} 1008 1009/******************************************************************************* 1010*******************************************************************************/ 1011kern_return_t 1012kextdProcessUserLoadRequest( 1013 CFDictionaryRef request, 1014 uid_t remote_euid, 1015 pid_t remote_pid) 1016{ 1017 OSReturn result = kOSReturnSuccess; 1018 CFStringRef kextID = NULL; // do not release 1019 char * kextIDString = NULL; // must free 1020 CFStringRef kextPath = NULL; // do not release 1021 CFArrayRef dependencyPaths = NULL; // do not release 1022 CFURLRef kextURL = NULL; // must release 1023 CFURLRef kextAbsURL = NULL; // must release 1024 OSKextRef theKext = NULL; // must release 1025 CFArrayRef kexts = NULL; // must release 1026 CFMutableArrayRef dependencyURLs = NULL; // must release 1027 CFURLRef dependencyURL = NULL; // must release 1028 CFURLRef dependencyAbsURL = NULL; // must release 1029 CFArrayRef dependencyKexts = NULL; // must release 1030 CFArrayRef loadList = NULL; // must release 1031 1032 char kextPathString[PATH_MAX] = "unknown"; 1033 char crashInfo[sizeof(CRASH_INFO_USER_KEXT_LOAD) + 1034 KMOD_MAX_NAME + PATH_MAX]; 1035 CFIndex count, index; 1036 1037 /* First get the identifier or URL to load, and convert it to a C string 1038 * for logging. 1039 */ 1040 kextID = (CFStringRef)CFDictionaryGetValue(request, kKextLoadIdentifierKey); 1041 if (kextID) { 1042 if (CFGetTypeID(kextID) != CFStringGetTypeID()) { 1043 result = kOSKextReturnInvalidArgument; 1044 goto finish; 1045 } 1046 kextIDString = createUTF8CStringForCFString(kextID); 1047 if (!kextIDString) { 1048 OSKextLogMemError(); 1049 goto finish; 1050 } 1051 } else { 1052 kextPath = (CFStringRef)CFDictionaryGetValue(request, kKextLoadPathKey); 1053 if (!kextPath || CFGetTypeID(kextPath) != CFStringGetTypeID()) { 1054 result = kOSKextReturnInvalidArgument; 1055 goto finish; 1056 } 1057 1058 if (!CFStringHasPrefix(kextPath, CFSTR("/"))) { 1059 OSKextLog(/* kext */ NULL, 1060 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1061 "Error: Request from '%s' (euid %d) to load kext with relative path.", 1062 nameForPID(remote_pid), remote_euid); 1063 result = kOSKextReturnInvalidArgument; 1064 goto finish; 1065 } 1066 1067 kextURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 1068 kextPath, kCFURLPOSIXPathStyle, /* isDir? */ true); 1069 if (!kextURL) { 1070 result = kOSKextReturnSerialization; // xxx - or other? 1071 goto finish; 1072 } 1073 result = kOSReturnError; 1074 kextAbsURL = createAbsOrRealURLForURL(kextURL, 1075 remote_euid, remote_pid, &result); 1076 if (!kextAbsURL) { 1077 goto finish; 1078 } 1079 CFURLGetFileSystemRepresentation(kextAbsURL, /* resolveToBase */ true, 1080 (UInt8 *)kextPathString, 1081 sizeof(kextPathString)); 1082 } 1083 1084 /* Read the extensions if necessary (also resets the release timer). 1085 */ 1086 readExtensions(); 1087 1088 /* Now log before the attempt, then try to look up or create the kext. 1089 */ 1090 if (remote_euid != 0) { 1091 OSKextLog(/* kext */ NULL, 1092 kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1093 "Request from '%s' (euid %d) to load %s.", 1094 nameForPID(remote_pid), remote_euid, 1095 kextIDString ? kextIDString : kextPathString); 1096 } 1097 1098 /* Open any dependencies provided, *before* we create the kext, since 1099 * a request by identifier must be resolvable from the dependencies 1100 * as well as system extensions folders. 1101 */ 1102 dependencyPaths = (CFArrayRef)CFDictionaryGetValue(request, 1103 kKextLoadDependenciesKey); 1104 if (dependencyPaths) { 1105 if (CFGetTypeID(dependencyPaths) != CFArrayGetTypeID()) { 1106 result = kOSKextReturnInvalidArgument; 1107 goto finish; 1108 } 1109 1110 count = CFArrayGetCount(dependencyPaths); 1111 1112 dependencyURLs = CFArrayCreateMutable(kCFAllocatorDefault, 1113 /* capacity */ count, 1114 &kCFTypeArrayCallBacks); 1115 if (!dependencyURLs) { 1116 result = kOSKextReturnNoMemory; 1117 goto finish; 1118 } 1119 1120 for (index = 0; index < count; index++) { 1121 CFStringRef thisPath = (CFStringRef)CFArrayGetValueAtIndex( 1122 dependencyPaths, index); 1123 1124 SAFE_RELEASE_NULL(dependencyURL); 1125 SAFE_RELEASE_NULL(dependencyAbsURL); 1126 if (CFGetTypeID(thisPath) != CFStringGetTypeID()) { 1127 result = kOSKextReturnInvalidArgument; 1128 goto finish; 1129 } 1130 if (!CFStringHasPrefix(thisPath, CFSTR("/"))) { 1131 OSKextLog(/* kext */ NULL, 1132 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1133 "Error: Request to load kext using dependency with relative path."); 1134 result = kOSKextReturnInvalidArgument; 1135 goto finish; 1136 } 1137 1138 dependencyURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 1139 thisPath, kCFURLPOSIXPathStyle, /* isDir? */ true); 1140 if (!dependencyURL) { 1141 result = kOSKextReturnSerialization; // xxx - or other? 1142 goto finish; 1143 } 1144 result = kOSReturnError; 1145 dependencyAbsURL = createAbsOrRealURLForURL(dependencyURL, 1146 remote_euid, remote_pid, &result); 1147 if (!dependencyAbsURL) { 1148 goto finish; 1149 } 1150 CFArrayAppendValue(dependencyURLs, dependencyAbsURL); 1151 } 1152 dependencyKexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault, 1153 dependencyURLs); 1154 if (!dependencyKexts) { 1155 result = kOSReturnError; 1156 goto finish; 1157 } 1158 } 1159 1160 snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_KEXT_LOAD, 1161 kextIDString ? kextIDString : kextPathString); 1162 1163 setCrashLogMessage(crashInfo); 1164 1165 1166 if (kextID) { 1167 theKext = OSKextGetKextWithIdentifier(kextID); 1168 if (theKext) { 1169 CFRetain(theKext); // we're going to release it 1170 } 1171 } else { 1172 /* Make sure we also read the plugins of the kext we're asked to load, 1173 * but only if we manage to open the kext itself (or we'll get too many 1174 * error messages). 1175 */ 1176 theKext = OSKextCreate(kCFAllocatorDefault, kextAbsURL); 1177 if (theKext) { 1178 kexts = OSKextCreateKextsFromURL(kCFAllocatorDefault, kextAbsURL); 1179 kextIDString = createUTF8CStringForCFString(OSKextGetIdentifier(theKext)); 1180 if (!kextIDString) { 1181 OSKextLogMemError(); 1182 goto finish; 1183 } 1184 } 1185 } 1186 1187 if (!theKext) { 1188 OSKextLog(/* kext */ NULL, 1189 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1190 "Error: Kext %s - not found/unable to create.", 1191 kextIDString ? kextIDString : kextPathString); 1192 result = kOSKextReturnNotFound; 1193 goto finish; 1194 } 1195 1196 if (remote_euid != 0) { 1197 result = checkNonrootLoadAllowed(theKext, remote_euid, remote_pid); 1198 if (result != kOSReturnSuccess) { 1199 goto finish; 1200 } 1201 } 1202 1203 /* Get dictionary of all our excluded kexts */ 1204 if (OSKextIsInExcludeList(theKext, false)) { 1205 CFMutableDictionaryRef myAlertInfoDict = NULL; // must release 1206 addKextToAlertDict(&myAlertInfoDict, theKext); 1207 if (myAlertInfoDict) { 1208 CFRetain(myAlertInfoDict); // writeKextAlertPlist will release 1209 dispatch_async(dispatch_get_main_queue(), ^ { 1210 writeKextAlertPlist(myAlertInfoDict, EXCLUDED_KEXT_ALERT); 1211 }); 1212 SAFE_RELEASE(myAlertInfoDict); 1213 } 1214 1215 messageTraceExcludedKext(theKext); 1216 OSKextLog(NULL, 1217 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1218 kOSKextLogValidationFlag | kOSKextLogGeneralFlag, 1219 "%s is in exclude list; omitting.", 1220 kextIDString ? kextIDString : kextPathString); 1221 result = kOSKextReturnNotLoadable; 1222 goto finish; 1223 } 1224 1225 if (__esp_enabled()) { 1226 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); 1227 if (dict == NULL) { 1228 result = kOSKextReturnNotLoadable; 1229 goto finish; 1230 } 1231 xpc_dictionary_set_int64(dict, "euid", remote_euid); 1232 xpc_dictionary_set_int64(dict, "pid", remote_pid); 1233 if (kextIDString != NULL) { 1234 xpc_dictionary_set_string(dict, "kextID", kextIDString); 1235 } 1236 if (kextPathString != NULL) { 1237 xpc_dictionary_set_string(dict, "kextPath", kextPathString); 1238 } 1239 int esp_result = __esp_check("kext-load", dict); 1240 xpc_release(dict); 1241 if (esp_result != 0) { 1242 result = kOSKextReturnNotLoadable; 1243 goto finish; 1244 } 1245 } 1246 1247 /* consult sandboxing system to make sure this is OK 1248 * <rdar://problem/11015459 1249 */ 1250 if (sandbox_check(remote_pid, "system-kext-load", 1251 SANDBOX_FILTER_KEXT_BUNDLE_ID, 1252 kextIDString) != 0 ) { 1253 OSKextLog(NULL, 1254 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1255 kOSKextLogValidationFlag | kOSKextLogGeneralFlag, 1256 "%s failed sandbox check; omitting.", kextIDString); 1257 result = kOSKextReturnNotLoadable; 1258 goto finish; 1259 } 1260 1261 OSStatus sigResult = checkKextSignature(theKext, true, false); 1262 if ( sigResult != 0 ) { 1263 if ( isInvalidSignatureAllowed() ) { 1264 CFStringRef myKextPath = NULL; // must release 1265 myKextPath = copyKextPath(theKext); 1266 OSKextLogCFString(NULL, 1267 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1268 CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext \"%@\""), 1269 (long)sigResult, (long)sigResult, 1270 myKextPath ? myKextPath : CFSTR("Unknown")); 1271 SAFE_RELEASE(myKextPath); 1272 } 1273 else { 1274 CFStringRef myBundleID; // do not release 1275 1276 myBundleID = OSKextGetIdentifier(theKext); 1277 OSKextLogCFString(NULL, 1278 kOSKextLogErrorLevel | 1279 kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1280 CFSTR("ERROR: invalid signature for %@, will not load"), 1281 myBundleID ? myBundleID : CFSTR("Unknown")); 1282 result = kOSKextReturnNotLoadable; 1283 goto finish; 1284 } 1285 } 1286 1287 /* The codepath from this function will do any error logging 1288 * and cleanup needed. 1289 */ 1290 result = OSKextLoadWithOptions(theKext, 1291 /* statExclusion */ kOSKextExcludeNone, 1292 /* addPersonalitiesExclusion */ kOSKextExcludeNone, 1293 /* personalityNames */ NULL, 1294 /* delayAutounloadFlag */ false); 1295 1296finish: 1297 SAFE_RELEASE(kextURL); 1298 SAFE_RELEASE(kextAbsURL); 1299 SAFE_RELEASE(kexts); 1300 SAFE_RELEASE(theKext); 1301 SAFE_RELEASE(dependencyURLs); 1302 SAFE_RELEASE(dependencyURL); 1303 SAFE_RELEASE(dependencyAbsURL); 1304 SAFE_RELEASE(dependencyKexts); 1305 SAFE_RELEASE(loadList); 1306 SAFE_FREE(kextIDString); 1307 1308 setCrashLogMessage(NULL); 1309 1310 return result; 1311} 1312