1/* 2 * kextutil_main.c 3 * kext_tools 4 * 5 * Created by Nik Gervae on 4/24/08. 6 * Copyright 2008 Apple Inc. All rights reserved. 7 * 8 */ 9#include "kextutil_main.h" 10#include "kext_tools_util.h" 11#include "security.h" 12#include "bootcaches.h" 13 14#include <libc.h> 15#include <sysexits.h> 16 17#include <IOKit/kext/OSKext.h> 18#include <IOKit/kext/OSKextPrivate.h> 19 20#include <IOKit/kext/KextManager.h> 21#include <IOKit/kext/KextManagerPriv.h> 22#include <IOKit/kext/kextmanager_types.h> 23 24#include <servers/bootstrap.h> // bootstrap mach ports 25#include <bootfiles.h> 26 27#pragma mark Constants 28/******************************************************************************* 29* Constants 30*******************************************************************************/ 31#define BAD_ADDRESS_SPEC "Address format is <bundle-id@address>, " \ 32 "with nonzero hexadecimal address." 33 34#pragma mark Global/Static Variables 35/******************************************************************************* 36* Global/Static Variables 37*******************************************************************************/ 38const char * progname = "(unknown)"; 39 40#define LOCK_MAXTRIES 90 41#define LOCK_DELAY 1 42static mach_port_t sKextdPort = MACH_PORT_NULL; 43static mach_port_t sLockPort = MACH_PORT_NULL; // kext loading lock 44static int sLockStatus = 0; 45static bool sLockTaken = false; 46 47#pragma mark Main Routine 48/******************************************************************************* 49* Global variables. 50*******************************************************************************/ 51ExitStatus 52main(int argc, char * const * argv) 53{ 54 ExitStatus result = EX_SOFTWARE; 55 ExitStatus processResult = EX_SOFTWARE; 56 Boolean fatal = false; 57 CFArrayRef allKexts = NULL; // must release 58 CFArrayRef kextsToProcess = NULL; // must release 59 KextutilArgs toolArgs; 60 61 /***** 62 * Find out what the program was invoked as. 63 */ 64 progname = rindex(argv[0], '/'); 65 if (progname) { 66 progname++; // go past the '/' 67 } else { 68 progname = (char *)argv[0]; 69 } 70 71 /* Set the OSKext log callback right away and hook up to get any 72 * warnings & errors out of the kernel. 73 */ 74 OSKextSetLogOutputFunction(&tool_log); 75 OSKextSetLogFilter(kOSKextLogWarningLevel | kOSKextLogVerboseFlagsMask, 76 /* kernel? */ true); 77 78 /***** 79 * Process args & check for permission to load. 80 */ 81 result = readArgs(argc, argv, &toolArgs); 82 if (result != EX_OK) { 83 if (result == kKextutilExitHelp) { 84 result = EX_OK; 85 } 86 goto finish; 87 } 88 89 result = checkArgs(&toolArgs); 90 if (result != EX_OK) { 91 goto finish; 92 } 93 94 /* From here on out the default exit status is ok. 95 */ 96 result = EX_OK; 97 98 /***** 99 * Turn on recording of all diagnostics. 100 */ 101 OSKextSetRecordsDiagnostics(kOSKextDiagnosticsFlagAll); 102 103 /***** 104 * Create the set of kexts we'll be working from. 105 */ 106 allKexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault, toolArgs.scanURLs); 107 if (!allKexts || !CFArrayGetCount(allKexts)) { 108 OSKextLog(/* kext */ NULL, 109 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 110 "No kernel extensions found."); 111 result = EX_SOFTWARE; 112 goto finish; 113 } 114 115 if (result != EX_OK) { 116 goto finish; 117 } 118 119 /***** 120 * Figure out which kexts we're actually loading/generating symbols for. 121 * This must be done after the kext objects are created. 122 */ 123 result = createKextsToProcess(&toolArgs, &kextsToProcess, &fatal); 124 if (fatal) { 125 goto finish; 126 } 127 128 if (!serializeLoad(&toolArgs, toolArgs.doLoad)) { 129 result = EX_OSERR; 130 goto finish; 131 } 132 133 processResult = processKexts(kextsToProcess, &toolArgs); 134 if (result == EX_OK) { 135 result = processResult; 136 } 137 138finish: 139 /***** 140 * Clean everything up. The mach stuff should be done even though we're 141 * exiting so we don't mess up other processes. 142 */ 143 if (sLockTaken) { 144 kextmanager_unlock_kextload(sKextdPort, sLockPort); 145 } 146 if (sKextdPort != MACH_PORT_NULL) { 147 mach_port_deallocate(mach_task_self(), sKextdPort); 148 } 149 if (sLockPort != MACH_PORT_NULL) { 150 mach_port_mod_refs(mach_task_self(), sLockPort, MACH_PORT_RIGHT_RECEIVE, -1); 151 } 152 153 /* We're actually not going to free anything else because we're exiting! 154 */ 155 exit(result); 156 157 SAFE_RELEASE(allKexts); 158 SAFE_RELEASE(toolArgs.loadAddresses); 159 SAFE_RELEASE(toolArgs.kextIDs); 160 SAFE_RELEASE(toolArgs.personalityNames); 161 SAFE_RELEASE(toolArgs.dependencyURLs); 162 SAFE_RELEASE(toolArgs.repositoryURLs); 163 SAFE_RELEASE(toolArgs.kextURLs); 164 SAFE_RELEASE(toolArgs.scanURLs); 165 SAFE_RELEASE(toolArgs.kernelURL); 166 SAFE_RELEASE(toolArgs.kernelFile); 167 SAFE_RELEASE(toolArgs.symbolDirURL); 168 169 return result; 170} 171 172#pragma mark Major Subroutines 173/******************************************************************************* 174* Major Subroutines 175*******************************************************************************/ 176ExitStatus 177readArgs( 178 int argc, 179 char * const * argv, 180 KextutilArgs * toolArgs) 181{ 182 ExitStatus result = EX_USAGE; 183 ExitStatus scratchResult = EX_USAGE; 184 int optchar; 185 int longindex; 186 CFStringRef scratchString = NULL; // must release 187 CFNumberRef scratchNumber = NULL; // must release 188 CFNumberRef existingAddress = NULL; // do not release 189 CFURLRef scratchURL = NULL; // must release 190 uint32_t i; 191 192 bzero(toolArgs, sizeof(*toolArgs)); 193 194 /* Set up default arg values. 195 */ 196 toolArgs->useRepositoryCaches = true; 197 toolArgs->useSystemExtensions = true; 198 toolArgs->overwriteSymbols = true; 199 toolArgs->interactiveLevel = kOSKextExcludeNone; 200 toolArgs->doLoad = true; 201 toolArgs->doStartMatching = true; 202 // toolArgs->archInfo must remain NULL before checkArgs 203 204 /***** 205 * Allocate collection objects. 206 */ 207 if (!createCFMutableDictionary(&toolArgs->loadAddresses) || 208 !createCFMutableArray(&toolArgs->kextIDs, &kCFTypeArrayCallBacks) || 209 !createCFMutableArray(&toolArgs->personalityNames, &kCFTypeArrayCallBacks) || 210 !createCFMutableArray(&toolArgs->dependencyURLs, &kCFTypeArrayCallBacks) || 211 !createCFMutableArray(&toolArgs->repositoryURLs, &kCFTypeArrayCallBacks) || 212 !createCFMutableArray(&toolArgs->kextURLs, &kCFTypeArrayCallBacks) || 213 !createCFMutableArray(&toolArgs->scanURLs, &kCFTypeArrayCallBacks)) { 214 215 result = EX_OSERR; 216 OSKextLogMemError(); 217 exit(result); 218 } 219 220 while ((optchar = getopt_long_only(argc, (char * const *)argv, 221 kOptChars, sOptInfo, &longindex)) != -1) { 222 223 char * address_string = NULL; // don't free 224 uint64_t address; 225 226 SAFE_RELEASE_NULL(scratchString); 227 SAFE_RELEASE_NULL(scratchNumber); 228 SAFE_RELEASE_NULL(scratchURL); 229 230 switch (optchar) { 231 case kOptHelp: 232 usage(kUsageLevelFull); 233 result = kKextutilExitHelp; 234 goto finish; 235 break; 236 case kOptBundleIdentifier: 237 scratchString = CFStringCreateWithCString(kCFAllocatorDefault, 238 optarg, kCFStringEncodingUTF8); 239 if (!scratchString) { 240 OSKextLogMemError(); 241 result = EX_OSERR; 242 goto finish; 243 } 244 CFArrayAppendValue(toolArgs->kextIDs, scratchString); 245 break; 246 247 case kOptPersonality: 248 scratchString = CFStringCreateWithCString(kCFAllocatorDefault, 249 optarg, kCFStringEncodingUTF8); 250 if (!scratchString) { 251 OSKextLogMemError(); 252 result = EX_OSERR; 253 goto finish; 254 } 255 CFArrayAppendValue(toolArgs->personalityNames, scratchString); 256 break; 257 258 case kOptKernel: 259 if (toolArgs->kernelURL) { 260 OSKextLog(/* kext */ NULL, 261 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 262 "Warning: multiple use of -%s (-%c); using last.", 263 kOptNameKernel, kOptKernel); 264 SAFE_RELEASE_NULL(toolArgs->kernelURL); 265 } 266 scratchURL = CFURLCreateFromFileSystemRepresentation( 267 kCFAllocatorDefault, 268 (const UInt8 *)optarg, strlen(optarg), true); 269 if (!scratchURL) { 270 OSKextLogStringError(/* kext */ NULL); 271 result = EX_OSERR; 272 goto finish; 273 } 274 toolArgs->kernelURL = CFRetain(scratchURL); 275 break; 276 277 case kOptDependency: 278 scratchURL = CFURLCreateFromFileSystemRepresentation( 279 kCFAllocatorDefault, 280 (const UInt8 *)optarg, strlen(optarg), true); 281 if (!scratchURL) { 282 OSKextLogStringError(/* kext */ NULL); 283 result = EX_OSERR; 284 goto finish; 285 } 286 CFArrayAppendValue(toolArgs->dependencyURLs, scratchURL); 287 break; 288 289 case kOptRepository: 290 scratchResult = checkPath(optarg, /* suffix */ NULL, 291 /* directoryRequired */ TRUE, /* writableRequired */ FALSE); 292 if (scratchResult != EX_OK) { 293 result = scratchResult; 294 goto finish; 295 } 296 scratchURL = CFURLCreateFromFileSystemRepresentation( 297 kCFAllocatorDefault, 298 (const UInt8 *)optarg, strlen(optarg), true); 299 if (!scratchURL) { 300 OSKextLogStringError(/* kext */ NULL); 301 result = EX_OSERR; 302 goto finish; 303 } 304 CFArrayAppendValue(toolArgs->repositoryURLs, scratchURL); 305 break; 306 307 case kOptNoCaches: 308 toolArgs->useRepositoryCaches = false; 309 break; 310 311 case kOptNoLoadedCheck: 312 toolArgs->checkLoadedForDependencies = false; 313 break; 314 315 case kOptNoSystemExtensions: 316 toolArgs->useSystemExtensions = false; 317 break; 318 319 case kOptInteractive: 320 if (toolArgs->interactiveLevel) { 321 OSKextLog(/* kext */ NULL, 322 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 323 "Warning: multiple use of -%s (-%c) or -%s (-%c); using last.", 324 kOptNameInteractive, kOptInteractive, 325 kOptNameInteractiveAll, kOptInteractiveAll); 326 } 327 toolArgs->overwriteSymbols = false; 328 toolArgs->interactiveLevel = kOSKextExcludeKext; 329 break; 330 331 case kOptInteractiveAll: 332 if (toolArgs->interactiveLevel) { 333 OSKextLog(/* kext */ NULL, 334 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 335 "Warning: multiple use of -%s (-%c) or -%s (-%c); using last.", 336 kOptNameInteractive, kOptInteractive, 337 kOptNameInteractiveAll, kOptInteractiveAll); 338 } 339 toolArgs->overwriteSymbols = false; 340 toolArgs->interactiveLevel = kOSKextExcludeAll; 341 break; 342 343 case kOptLoadOnly: 344 toolArgs->flag_l = 1; 345 break; 346 347 case kOptMatchOnly: 348 toolArgs->flag_m = 1; 349 break; 350 351 case kOptNoLoad: 352 toolArgs->flag_n = 1; 353 break; 354 355 case kOptSymbolsDirectory: 356 if (toolArgs->symbolDirURL) { 357 OSKextLog(/* kext */ NULL, 358 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 359 "Warning: multiple use of -%s (-%c); using last", 360 kOptNameSymbolsDirectory, kOptSymbolsDirectory); 361 SAFE_RELEASE_NULL(toolArgs->symbolDirURL); 362 } 363 scratchResult = checkPath(optarg, /* suffix */ NULL, 364 /* directoryRequired? */ TRUE, /* writable? */ TRUE); 365 if (scratchResult != EX_OK) { 366 result = scratchResult; 367 goto finish; 368 } 369 scratchURL = CFURLCreateFromFileSystemRepresentation( 370 kCFAllocatorDefault, 371 (const UInt8 *)optarg, strlen(optarg), true); 372 if (!scratchURL) { 373 OSKextLogStringError(/* kext */ NULL); 374 result = EX_OSERR; 375 goto finish; 376 } 377 toolArgs->symbolDirURL = CFRetain(scratchURL); 378 break; 379 380 case kOptAddress: 381 toolArgs->flag_n = 1; // -a implies -n 382 383 address_string = index(optarg, '@'); 384 if (!address_string) { 385 OSKextLog(/* kext */ NULL, 386 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 387 BAD_ADDRESS_SPEC); 388 goto finish; 389 } 390 address_string[0] = '\0'; 391 address_string++; 392 393 /* Read a 64-bit int here; we'll check at load time 394 * whether the address is too big. 395 */ 396 address = strtoull(address_string, NULL, 16); 397 if (!address) { 398 OSKextLog(/* kext */ NULL, 399 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 400 BAD_ADDRESS_SPEC); 401 goto finish; 402 } 403 scratchNumber = CFNumberCreate(kCFAllocatorDefault, 404 kCFNumberSInt64Type, &address); 405 if (!scratchNumber) { 406 OSKextLogMemError(); 407 result = EX_OSERR; 408 goto finish; 409 } 410 scratchString = CFStringCreateWithCString(kCFAllocatorDefault, 411 optarg, kCFStringEncodingUTF8); 412 if (!scratchString) { 413 OSKextLogMemError(); 414 result = EX_OSERR; 415 goto finish; 416 } 417 existingAddress = CFDictionaryGetValue(toolArgs->loadAddresses, 418 scratchString); 419 if (existingAddress && !CFEqual(scratchNumber, existingAddress)) { 420 OSKextLog(/* kext */ NULL, kOSKextLogWarningLevel, 421 "Warning: multiple addresses specified for %s; using last.", 422 optarg); 423 } 424 CFDictionarySetValue(toolArgs->loadAddresses, scratchString, 425 scratchNumber); 426 break; 427 428 case kOptUseKernelAddresses: 429 toolArgs->flag_n = 1; // -A implies -n 430 toolArgs->getAddressesFromKernel = true; 431 break; 432 433 case kOptQuiet: 434 beQuiet(); 435 toolArgs->logFilterChanged = true; 436 break; 437 438 case kOptVerbose: 439 scratchResult = setLogFilterForOpt(argc, argv, /* forceOnFlags */ 0); 440 if (scratchResult != EX_OK) { 441 result = scratchResult; 442 goto finish; 443 } 444 toolArgs->logFilterChanged = true; 445 break; 446 447 case kOptTests: 448 toolArgs->printDiagnostics = true; 449 break; 450 451 case kOptSafeBoot: 452 toolArgs->safeBootMode = true; 453 toolArgs->useRepositoryCaches = false; // -x implies -c 454 break; 455 456 case kOptNoAuthentication: 457 toolArgs->skipAuthentication = true; 458 break; 459 460 case kOptNoResolveDependencies: 461 toolArgs->skipDependencies = true; 462 break; 463 464 case 0: 465 switch (longopt) { 466 case kLongOptArch: 467 if (toolArgs->archInfo) { 468 OSKextLog(/* kext */ NULL, 469 kOSKextLogWarningLevel | kOSKextLogGeneralFlag, 470 "Warning: multiple use of -%s; using last.", 471 kOptNameArch); 472 } 473 toolArgs->archInfo = NXGetArchInfoFromName(optarg); 474 if (!toolArgs->archInfo) { 475 OSKextLog(/* kext */ NULL, 476 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 477 "Unknown architecture %s.", optarg); 478 goto finish; 479 } 480 break; 481 482 default: 483 /* getopt_long_only() prints an error message for us. */ 484 goto finish; 485 break; 486 } 487 break; 488 489 default: 490 /* getopt_long_only() prints an error message for us. */ 491 goto finish; 492 break; 493 494 } /* switch (optchar) */ 495 } /* while (optchar = getopt_long_only(...) */ 496 497 /***** 498 * Record the kext names from the command line. 499 */ 500 for (i = optind; i < argc; i++) { 501 SAFE_RELEASE_NULL(scratchURL); 502 503 scratchResult = checkPath(argv[i], kOSKextBundleExtension, 504 /* directoryRequired */ TRUE, /* writableRequired */ FALSE); 505 if (scratchResult != EX_OK) { 506 result = scratchResult; 507 goto finish; 508 } 509 510 scratchURL = CFURLCreateFromFileSystemRepresentation( 511 kCFAllocatorDefault, 512 (const UInt8 *)argv[i], strlen(argv[i]), true); 513 if (!scratchURL) { 514 result = EX_OSERR; 515 OSKextLogMemError(); 516 goto finish; 517 } 518 CFArrayAppendValue(toolArgs->kextURLs, scratchURL); 519 } 520 521 result = EX_OK; 522 523finish: 524 SAFE_RELEASE(scratchString); 525 SAFE_RELEASE(scratchNumber); 526 SAFE_RELEASE(scratchURL); 527 528 if (result == EX_USAGE) { 529 usage(kUsageLevelBrief); 530 } 531 return result; 532} 533 534/******************************************************************************* 535*******************************************************************************/ 536ExitStatus 537checkArgs(KextutilArgs * toolArgs) 538{ 539 ExitStatus result = EX_USAGE; 540 char kernelPathCString[PATH_MAX]; 541 const NXArchInfo * kernelArchInfo = OSKextGetRunningKernelArchitecture(); 542 543 /* We don't need this for everything, but it's unlikely to fail. 544 */ 545 if (!kernelArchInfo) { 546 result = EX_OSERR; 547 goto finish; 548 } 549 550 /***** 551 * Check for bad combinations of arguments and options. 552 */ 553 if (toolArgs->flag_l + toolArgs->flag_m + toolArgs->flag_n > 1) { 554 OSKextLog(/* kext */ NULL, 555 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 556 "Only one of -%s (-%c), -%s (-%c), or -%s (-%c) is allowed;\n" 557 "-%s (-%c) and -%s (-%c) imply -%s (-%c).", 558 kOptNameLoadOnly, kOptLoadOnly, 559 kOptNameMatchOnly, kOptMatchOnly, 560 kOptNameNoLoad, kOptNoLoad, 561 kOptNameAddress, kOptAddress, 562 kOptNameUseKernelAddresses, kOptUseKernelAddresses, 563 kOptNameNoLoad, kOptNoLoad); 564 goto finish; 565 } else if (toolArgs->flag_l) { 566 toolArgs->doLoad = true; 567 toolArgs->doStartMatching = false; 568 } else if (toolArgs->flag_m) { 569 toolArgs->doLoad = false; 570 toolArgs->doStartMatching = true; 571 } else if (toolArgs->flag_n) { 572 toolArgs->doLoad = false; 573 toolArgs->doStartMatching = false; 574 } 575 576 if ((toolArgs->interactiveLevel != kOSKextExcludeNone) && 577 !toolArgs->doLoad && !toolArgs->doStartMatching) { 578 579 OSKextLog(/* kext */ NULL, 580 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 581 "Use interactive modes only when loading or matching."); 582 goto finish; 583 } 584 585 /* If running in quiet mode and the invocation might require 586 * interaction, just exit with an error. Interaction required when: 587 * 588 * - Explicitly flagged with -i/-I. 589 * - Saving symbols w/o loading, no addresses specified, 590 * not getting from kernel. 591 */ 592 if (OSKextGetLogFilter(/* kernel? */ false) == kOSKextLogSilentFilter) { 593 594 Boolean interactive = (toolArgs->interactiveLevel != kOSKextExcludeNone); 595 Boolean needAddresses = (toolArgs->symbolDirURL && 596 !toolArgs->doLoad && 597 CFDictionaryGetCount(toolArgs->loadAddresses) == 0 && 598 !toolArgs->getAddressesFromKernel); 599 600 if (interactive || needAddresses) { 601 result = kKextutilExitLoadFailed; 602 goto finish; 603 } 604 } 605 606 /* Disallow -address(-a) with any load or getting addresses from kernel. 607 */ 608 if (CFDictionaryGetCount(toolArgs->loadAddresses) > 0 && 609 (toolArgs->doLoad || toolArgs->getAddressesFromKernel)) { 610 611 OSKextLog(/* kext */ NULL, 612 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 613 "Don't use -%s (-%c) when loading, or with -%s (-%c).", 614 kOptNameAddress, kOptAddress, 615 kOptNameUseKernelAddresses, kOptUseKernelAddresses); 616 goto finish; 617 } 618 619 /* If sending anything into the kernel, don't use a kernel file 620 * and refuse to skip authentication. 621 */ 622 if (toolArgs->doLoad || toolArgs->doStartMatching) { 623 if (toolArgs->kernelURL) { 624 OSKextLog(/* kext */ NULL, 625 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 626 "-%s (-%c) is allowed only when not loading " 627 "or sending personalities.", 628 kOptNameKernel, kOptKernel); 629 goto finish; 630 } 631 632 if (toolArgs->skipAuthentication) { 633 OSKextLog(/* kext */ NULL, 634 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 635 "-%s (-%c) is allowed only when not loading " 636 "or sending personalities.", 637 kOptNameNoAuthentication, kOptNoAuthentication); 638 goto finish; 639 } 640 } 641 642 /* If we aren't sending anything to the kernel and not doing full 643 * tests, then don't bother authenticating. This lets developers 644 * generate symbols more conveniently & allows basic checks with -n alone. 645 */ 646 if (!toolArgs->doLoad && 647 !toolArgs->doStartMatching && 648 !toolArgs->printDiagnostics) { 649 650 toolArgs-> skipAuthentication = true; 651 } 652 653 /**** 654 * If we're getting addresses from the kernel we have to call 655 * down there, so we might as well check what's loaded before 656 * resolving dependencies too (-A overrides -D). If we're not 657 * performing a load, then don't check (-n/-m implies -D). 658 */ 659 if (toolArgs->getAddressesFromKernel) { 660 toolArgs->checkLoadedForDependencies = true; 661 } 662 663 /***** 664 * -no-resolve-dependencies/-Z is only allowed 665 * if you don't need to resolve dependencies (duh). 666 * You need to resolve if loading or saving symbols. 667 */ 668 if (toolArgs->skipDependencies) { 669 if (toolArgs->doLoad || 670 toolArgs->symbolDirURL) { 671 672 OSKextLog(/* kext */ NULL, 673 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 674 "Use -%s (-%c) only with -%s (-%c) or %s (-%c), " 675 "and not with -%s (-%c).", 676 kOptNameNoResolveDependencies, kOptNoResolveDependencies, 677 kOptNameNoLoad, kOptNoLoad, 678 kOptNameMatchOnly, kOptMatchOnly, 679 kOptNameSymbolsDirectory, kOptSymbolsDirectory); 680 goto finish; 681 } 682 } 683 684 if (!CFArrayGetCount(toolArgs->kextURLs) && 685 !CFArrayGetCount(toolArgs->kextIDs) && 686 !CFDictionaryGetCount(toolArgs->loadAddresses)) { 687 688 OSKextLog(/* kext */ NULL, 689 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 690 "No kernel extensions specified; name kernel extension bundles\n" 691 " following options, or use -%s (-%c) and -%s (-%c).", 692 kOptNameBundleIdentifier, kOptBundleIdentifier, 693 kOptNameAddress, kOptAddress); 694 goto finish; 695 } 696 697 /***** 698 * Check whether the user has permission to load into the kernel. 699 */ 700 if ((toolArgs->doLoad || toolArgs->doStartMatching) && geteuid() != 0) { 701 OSKextLog(/* kext */ NULL, 702 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 703 "You must be running as root to load kexts " 704 "or send personalities into the kernel."); 705 result = EX_NOPERM; 706 goto finish; 707 } 708 709 /***** 710 * Set up which arch to work with and sanity-check it. 711 */ 712 if (toolArgs->archInfo) { 713 714 /* If loading into or getting addresses form the kernel, 715 * any specified architecture must match that of the running kernel. 716 */ 717 if (toolArgs->doLoad || toolArgs->getAddressesFromKernel) { 718 719 if (kernelArchInfo != OSKextGetArchitecture()) { 720 721 OSKextLog(/* kext */ NULL, 722 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 723 "Specified architecture %s does not match " 724 "running kernel architecture %s.", 725 toolArgs->archInfo->name, kernelArchInfo->name); 726 goto finish; 727 } 728 } 729 730 /* All good; set the default OSKext arch & safe boot mode. 731 */ 732 OSKextSetArchitecture(toolArgs->archInfo); 733 OSKextSetSimulatedSafeBoot(toolArgs->safeBootMode); 734 } 735 736 /* Give a notice to the user in case they're doing cross-arch work. 737 */ 738 if (toolArgs->symbolDirURL && !toolArgs->archInfo && 739 !toolArgs->getAddressesFromKernel) { 740 741 OSKextLog(/* kext */ NULL, 742 kOSKextLogWarningLevel | kOSKextLogLinkFlag, 743 "Notice: Using running kernel architecture %s to generate symbols.", 744 kernelArchInfo->name); 745 /* not an error! */ 746 } 747 748 /* Give a notice to the user if safe boot mode is actually on. 749 */ 750 if (OSKextGetActualSafeBoot() && !toolArgs->safeBootMode) { 751 752 OSKextLog(/* kext */ NULL, 753 kOSKextLogWarningLevel | kOSKextLogLoadFlag, 754 "Notice: system is in safe boot mode; kernel may refuse loads."); 755 /* not an error! */ 756 } 757 758 /***** 759 * Assemble the list of URLs to scan, in this order (the OSKext lib inverts it 760 * for last-opened-wins semantics): 761 * 1. System repository directories (-no-system-extensions/-e skips). 762 * 2. Named kexts (always given after -repository & -dependency on command line). 763 * 3. Named repository directories (-repository/-r). 764 * 4. Named dependencies get priority (-dependency/-d). 765 */ 766 if (toolArgs->useSystemExtensions) { 767 CFArrayRef sysExtFolders = OSKextGetSystemExtensionsFolderURLs(); 768 // xxx - check it 769 CFArrayAppendArray(toolArgs->scanURLs, 770 sysExtFolders, RANGE_ALL(sysExtFolders)); 771 } 772 CFArrayAppendArray(toolArgs->scanURLs, toolArgs->kextURLs, 773 RANGE_ALL(toolArgs->kextURLs)); 774 CFArrayAppendArray(toolArgs->scanURLs, toolArgs->repositoryURLs, 775 RANGE_ALL(toolArgs->repositoryURLs)); 776 CFArrayAppendArray(toolArgs->scanURLs, toolArgs->dependencyURLs, 777 RANGE_ALL(toolArgs->dependencyURLs)); 778 779 if ( (CFArrayGetCount(toolArgs->kextIDs) || 780 CFDictionaryGetCount(toolArgs->loadAddresses)) && 781 !CFArrayGetCount(toolArgs->scanURLs)) { 782 783 OSKextLog(/* kext */ NULL, 784 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 785 "No kexts to search for bundle IDs; " 786 "-%s (-%c) requires kexts or repository directories " 787 "be named by path.", 788 kOptNameBundleIdentifier, kOptBundleIdentifier); 789 goto finish; 790 } 791 792 /* If no explicit kernel image was provided by the user, default it 793 * to KernelPath from /usr/standalone/bootcaches.plist 794 * <= 10.9 /mach_kernel 795 * > 10.9 /System/Library/Kernels/kernel 796 */ 797 if (!toolArgs->kernelURL) { 798 CFURLRef scratchURL = NULL; 799 800 // use KernelPath from /usr/standalone/bootcaches.plist 801 if (getKernelPathForURL(NULL, 802 kernelPathCString, 803 sizeof(kernelPathCString)) == FALSE) { 804 // no bootcaches.plist? Forced to hardwire... 805 strlcpy(kernelPathCString, "/System/Library/Kernels/kernel", 806 sizeof(kernelPathCString)); 807 } 808 809 if (useDevelopmentKernel(kernelPathCString)) { 810 if (strlen(kernelPathCString) + strlen(kDefaultKernelSuffix) + 1 < sizeof(kernelPathCString)) { 811 strlcat(kernelPathCString, 812 kDefaultKernelSuffix, 813 sizeof(kernelPathCString)); 814 } 815 } 816 817 scratchURL = CFURLCreateFromFileSystemRepresentation( 818 kCFAllocatorDefault, 819 (const UInt8 *)kernelPathCString, 820 strlen(kernelPathCString), 821 false ); 822 if (!scratchURL) { 823 OSKextLogStringError(/* kext */ NULL); 824 result = EX_OSERR; 825 goto finish; 826 } 827 toolArgs->kernelURL = scratchURL; 828 OSKextLog(/* kext */ NULL, 829 kOSKextLogBasicLevel | kOSKextLogLoadFlag, 830 "Defaulting to kernel file '%s'", 831 kernelPathCString); 832 } 833 834 if (toolArgs->kernelURL) { 835 /* create and fill our CFData object for toolArgs->kernelFile 836 */ 837 if (!CFURLGetFileSystemRepresentation(toolArgs->kernelURL, 838 true, 839 (uint8_t *)kernelPathCString, 840 sizeof(kernelPathCString))) { 841 OSKextLogStringError(/* kext */ NULL); 842 result = EX_OSFILE; 843 goto finish; 844 } 845 846 if (!createCFDataFromFile(&toolArgs->kernelFile, 847 kernelPathCString)) { 848 OSKextLog(/* kext */ NULL, 849 kOSKextLogErrorLevel | kOSKextLogFileAccessFlag, 850 "Can't read kernel file '%s'", 851 kernelPathCString); 852 result = EX_OSFILE; 853 goto finish; 854 } 855 } 856 857 if (!toolArgs->doLoad || (toolArgs->interactiveLevel != kOSKextExcludeNone)) { 858 adjustLogFilterForInteractive(toolArgs); 859 } 860 861 result = EX_OK; 862 863finish: 864 if (result == EX_USAGE) { 865 usage(kUsageLevelBrief); 866 } 867 return result; 868} 869 870/******************************************************************************* 871*******************************************************************************/ 872void adjustLogFilterForInteractive(KextutilArgs * toolArgs) 873{ 874 if (!toolArgs->logFilterChanged) { 875 OSKextSetLogFilter(kDefaultServiceLogFilter, /* kernel? */ false); 876 OSKextSetLogFilter(kDefaultServiceLogFilter, /* kernel? */ true); 877 } 878} 879 880/******************************************************************************* 881*******************************************************************************/ 882ExitStatus 883createKextsToProcess( 884 KextutilArgs * toolArgs, 885 CFArrayRef * outArray, 886 Boolean * fatal) 887{ 888 ExitStatus result = EX_OK; 889 CFMutableArrayRef kextsToProcess = NULL; // returned by ref. 890 891 CFURLRef kextURL = NULL; // do not release 892 char kextPathCString[PATH_MAX]; 893 894 CFStringRef * addressKeys = NULL; // must free 895 char * kextIDCString = NULL; // must free 896 OSKextRef theKext = NULL; // do not release 897 CFIndex kextCount, idCount, kextIndex, idIndex; 898 899 if (!createCFMutableArray(&kextsToProcess, &kCFTypeArrayCallBacks)) { 900 result = EX_OSERR; 901 goto finish; 902 } 903 904 /***** 905 * If we got kext bundle names, then create kexts for them. Kexts named 906 * by path always have priority so we're adding them first. 907 */ 908 kextCount = CFArrayGetCount(toolArgs->kextURLs); 909 for (kextIndex = 0; kextIndex < kextCount; kextIndex++) { 910 911 kextURL = (CFURLRef)CFArrayGetValueAtIndex( 912 toolArgs->kextURLs, kextIndex); 913 914 if (!CFURLGetFileSystemRepresentation(kextURL, 915 /* resolveToBase */ false, 916 (u_char *)kextPathCString, sizeof(kextPathCString))) { 917 918 OSKextLogStringError(/* kext */ NULL); 919 result = EX_OSERR; 920 *fatal = true; 921 goto finish; 922 } 923 924 OSKextLog(/* kext */ NULL, 925 kOSKextLogStepLevel | kOSKextLogKextBookkeepingFlag, 926 "Looking up extension with URL %s.", 927 kextPathCString); 928 929 /* Use OSKextGetKextWithURL() to avoid double open error messages, 930 * because we already tried to open all kexts in main(). That means 931 * we don't log here if we don't find the kext. 932 */ 933 theKext = OSKextGetKextWithURL(kextURL); 934 if (!theKext) { 935 result = kKextutilExitNotFound; 936 // keep going 937 continue; 938 } 939 addToArrayIfAbsent(kextsToProcess, theKext); 940 941 /* Since we're running a developer tool on this kext, let's go ahead 942 * and enable per-kext logging for it regardless of the in-bundle setting. 943 * Would be nice to do this for all dependencies but the user can set 944 * the verbose filter's 0x8 bit for that. It will log for all kexts 945 * but that's not so bad. 946 */ 947 OSKextSetLoggingEnabled(theKext, true); 948 } 949 950 /***** 951 * If we got load addresses on the command line, add their bundle IDs 952 * to the list of kext IDs to load. 953 */ 954 idCount = CFDictionaryGetCount(toolArgs->loadAddresses); 955 if (idCount) { 956 addressKeys = (CFStringRef *)malloc(idCount * sizeof(CFStringRef)); 957 if (!addressKeys) { 958 OSKextLogMemError(); 959 result = EX_OSERR; 960 *fatal = true; 961 goto finish; 962 } 963 CFDictionaryGetKeysAndValues(toolArgs->loadAddresses, 964 (void *)addressKeys, /* values */ NULL); 965 966 for (idIndex = 0; idIndex < idCount; idIndex++) { 967 if (kCFNotFound == CFArrayGetFirstIndexOfValue(toolArgs->kextIDs, 968 RANGE_ALL(toolArgs->kextIDs), addressKeys[idIndex])) { 969 970 CFArrayAppendValue(toolArgs->kextIDs, addressKeys[idIndex]); 971 } 972 } 973 } 974 975 /***** 976 * If we have CFBundleIdentifiers, then look them up. We just add to the 977 * kextsToProcess array here. 978 */ 979 idCount = CFArrayGetCount(toolArgs->kextIDs); 980 for (idIndex = 0; idIndex < idCount; idIndex++) { 981 CFStringRef thisKextID = (CFStringRef) 982 CFArrayGetValueAtIndex(toolArgs->kextIDs, idIndex); 983 984 SAFE_FREE_NULL(kextIDCString); 985 986 kextIDCString = createUTF8CStringForCFString(thisKextID); 987 if (!kextIDCString) { 988 OSKextLogMemError(); 989 result = EX_OSERR; 990 goto finish; 991 } 992 993 /* First see if we already have this kext in the list of kexts 994 * to process. Only if we don't have it by name do we look it up 995 * by identifier. This should allow kexts named by path on the command 996 * line to take precendence over any bundle ID lookups; for example, 997 * if the user is working with an older version of the kext, an 998 * identifier lookup would find the newer. 999 */ 1000 kextCount = CFArrayGetCount(kextsToProcess); 1001 for (kextIndex = 0; kextIndex < kextCount; kextIndex++) { 1002 OSKextRef scanKext = (OSKextRef)CFArrayGetValueAtIndex( 1003 kextsToProcess, kextIndex); 1004 CFStringRef scanKextID = OSKextGetIdentifier(scanKext); 1005 1006 if (CFEqual(thisKextID, scanKextID)) { 1007 theKext = scanKext; 1008 break; 1009 } 1010 } 1011 1012 if (!theKext) { 1013 OSKextLog(/* kext */ NULL, 1014 kOSKextLogStepLevel | kOSKextLogKextBookkeepingFlag, 1015 "Looking up extension with identifier %s.", 1016 kextIDCString); 1017 1018 theKext = OSKextGetKextWithIdentifier(thisKextID); 1019 } 1020 1021 if (!theKext) { 1022 OSKextLog(/* kext */ NULL, 1023 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1024 "Can't find extension with identifier %s.", 1025 kextIDCString); 1026 result = kKextutilExitNotFound; 1027 continue; // not fatal, keep trying the others 1028 } 1029 1030 kextURL = OSKextGetURL(theKext); 1031 if (!CFURLGetFileSystemRepresentation(kextURL, 1032 /* resolveToBase */ false, 1033 (u_char *)kextPathCString, sizeof(kextPathCString))) { 1034 1035 OSKextLogStringError(theKext); 1036 result = EX_OSERR; 1037 *fatal = true; 1038 goto finish; 1039 } 1040 1041 OSKextLog(/* kext */ NULL, 1042 kOSKextLogStepLevel | kOSKextLogKextBookkeepingFlag, 1043 "Found %s for identifier %s.", kextPathCString, kextIDCString); 1044 1045 addToArrayIfAbsent(kextsToProcess, theKext); 1046 1047 /* As above, so below; enable logging for the kext we just looked up. 1048 */ 1049 OSKextSetLoggingEnabled(theKext, true); 1050 } 1051 1052finish: 1053 SAFE_FREE(addressKeys); 1054 SAFE_FREE(kextIDCString); 1055 1056 /* Let go of these two tool args, we don't need them any more. 1057 */ 1058 SAFE_RELEASE_NULL(toolArgs->kextURLs); 1059 SAFE_RELEASE_NULL(toolArgs->kextIDs); 1060 1061 if (*fatal) { 1062 SAFE_RELEASE(kextsToProcess); 1063 *outArray = NULL; 1064 } else { 1065 *outArray = kextsToProcess; 1066 } 1067 return result; 1068} 1069 1070/******************************************************************************* 1071*******************************************************************************/ 1072typedef struct { 1073 Boolean fatal; 1074} SetAddressContext; 1075 1076void 1077setKextLoadAddress( 1078 const void * vKey, 1079 const void * vValue, 1080 void * vContext) 1081{ 1082 CFStringRef bundleID = (CFStringRef)vKey; 1083 CFNumberRef loadAddressNumber = (CFNumberRef)vValue; 1084 SetAddressContext * context = (SetAddressContext *)vContext; 1085 CFArrayRef kexts = NULL; // must release 1086 OSKextRef theKext = NULL; // do not release 1087 uint64_t loadAddress = 0; 1088 CFIndex count, i; 1089 1090 if (context->fatal) { 1091 goto finish; 1092 } 1093 1094 if (!CFNumberGetValue(loadAddressNumber, kCFNumberSInt64Type, 1095 &loadAddress)) { 1096 1097 context->fatal = true; 1098 goto finish; 1099 } 1100 1101 1102 kexts = OSKextCopyKextsWithIdentifier(bundleID); 1103 if (!kexts) { 1104 goto finish; 1105 } 1106 1107 count = CFArrayGetCount(kexts); 1108 for (i = 0; i < count; i++) { 1109 1110 theKext = (OSKextRef)CFArrayGetValueAtIndex(kexts, i); 1111 if (!OSKextSetLoadAddress(theKext, loadAddress)) { 1112 context->fatal = true; 1113 goto finish; 1114 } 1115 } 1116 1117finish: 1118 SAFE_RELEASE(kexts); 1119 return; 1120} 1121 1122/******************************************************************************* 1123*******************************************************************************/ 1124ExitStatus 1125processKexts( 1126 CFArrayRef kextsToProcess, 1127 KextutilArgs * toolArgs) 1128{ 1129 ExitStatus result = EX_OK; 1130 OSReturn readLoadInfoResult = kOSReturnError; 1131 Boolean fatal = false; 1132 SetAddressContext setLoadAddressContext; 1133 CFIndex count, i; 1134 1135 if (toolArgs->getAddressesFromKernel) { 1136 readLoadInfoResult = OSKextReadLoadedKextInfo( 1137 /* kextIdentifiers */ NULL, 1138 /* flushDependencies */ true); 1139 if (readLoadInfoResult != kOSReturnSuccess) { 1140 OSKextLog(/* kext */ NULL, 1141 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1142 "Failed to read load info for kexts - %s.", 1143 safe_mach_error_string(readLoadInfoResult)); 1144 result = EX_OSERR; 1145 goto finish; 1146 } 1147 } else if (toolArgs->loadAddresses) { 1148 setLoadAddressContext.fatal = false; 1149 CFDictionaryApplyFunction(toolArgs->loadAddresses, setKextLoadAddress, 1150 &setLoadAddressContext); 1151 if (setLoadAddressContext.fatal) { 1152 result = EX_OSERR; // xxx - or may software 1153 goto finish; 1154 } 1155 } 1156 1157 /* Get busy loading kexts. 1158 */ 1159 count = CFArrayGetCount(kextsToProcess); 1160 for (i = 0; i < count; i++) { 1161 OSKextRef theKext = (OSKextRef)CFArrayGetValueAtIndex(kextsToProcess, i); 1162 1163 int loadResult = processKext(theKext, toolArgs, &fatal); 1164 1165 /* Save the first non-OK loadResult as the return value. 1166 */ 1167 if (result == EX_OK && loadResult != EX_OK) { 1168 result = loadResult; 1169 } 1170 if (fatal) { 1171 goto finish; 1172 } 1173 } 1174finish: 1175 return result; 1176} 1177 1178/******************************************************************************* 1179*******************************************************************************/ 1180ExitStatus 1181processKext( 1182 OSKextRef aKext, 1183 KextutilArgs * toolArgs, 1184 Boolean * fatal) 1185{ 1186 ExitStatus result = EX_OK; 1187 char kextPathCString[PATH_MAX]; 1188 1189 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(aKext), 1190 /* resolveToBase */ false, 1191 (u_char *)kextPathCString, sizeof(kextPathCString))) { 1192 1193 OSKextLogMemError(); 1194 result = EX_OSERR; 1195 *fatal = true; 1196 goto finish; 1197 } 1198 1199 result = runTestsOnKext(aKext, kextPathCString, toolArgs, fatal); 1200 if (result != EX_OK) { 1201 goto finish; 1202 } 1203 1204 /* If there's no more work to do beyond printing test results, 1205 * skip right to the end. 1206 */ 1207 if (!toolArgs->doLoad && 1208 !toolArgs->doStartMatching && 1209 !toolArgs->symbolDirURL) { 1210 1211 goto finish; 1212 } 1213 1214 if (toolArgs->doLoad) { 1215 OSStatus sigResult = checkKextSignature(aKext, true, false); 1216 if ( sigResult != 0 ) { 1217 if ( isInvalidSignatureAllowed() ) { 1218 OSKextLogCFString(NULL, 1219 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1220 CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext \"%s\""), 1221 (long)sigResult, (long)sigResult, kextPathCString); 1222 } 1223 else { 1224 CFStringRef myBundleID; // do not release 1225 1226 myBundleID = OSKextGetIdentifier(aKext); 1227 result = kOSKextReturnNotLoadable; // see 13024670 1228 OSKextLogCFString(NULL, 1229 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1230 CFSTR("ERROR: invalid signature for %@, will not load"), 1231 myBundleID ? myBundleID : CFSTR("Unknown")); 1232 goto finish; 1233 } 1234 } 1235 1236 result = loadKext(aKext, kextPathCString, toolArgs, fatal); 1237 } 1238 if (result != EX_OK) { 1239 goto finish; 1240 } 1241 1242 if (toolArgs->doLoad) { 1243 /* <rdar://problem/12435992> */ 1244 recordKextLoadForMT(aKext); 1245 } 1246 1247 /* Reread loaded kext info to reflect newly-loaded kexts 1248 * if we need to save symbols (which requires load addresses) 1249 * or do interactive stuff. 1250 * 1251 * xxx - Could optimize OSKextReadLoadedKextInfo() with list 1252 * xxx - of kextIdentifiers from load list. 1253 */ 1254 if (toolArgs->doLoad && 1255 (toolArgs->symbolDirURL || 1256 toolArgs->interactiveLevel != kOSKextExcludeNone)) { 1257 1258 OSReturn readLoadedResult = OSKextReadLoadedKextInfo( 1259 /* kextIdentifiers */ NULL, 1260 /* flushDependencies */ true); 1261 if (kOSReturnSuccess != readLoadedResult) { 1262 OSKextLog(/* kext */ NULL, 1263 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1264 "Failed to reread load info after loading %s - %s.", 1265 kextPathCString, 1266 safe_mach_error_string(readLoadedResult)); 1267 result = EX_OSERR; 1268 // xxx - fatal? 1269 goto finish; 1270 } 1271 } 1272 1273 if (toolArgs->symbolDirURL) { 1274 result = generateKextSymbols(aKext, kextPathCString, toolArgs, 1275 /* save? */ TRUE, fatal); 1276 if (result != EX_OK) { 1277 goto finish; 1278 } 1279 } 1280 1281 if (toolArgs->doLoad || 1282 toolArgs->doStartMatching) { 1283 1284 result = startKextsAndSendPersonalities(aKext, toolArgs, 1285 fatal); 1286 if (result != EX_OK) { 1287 goto finish; 1288 } 1289 } 1290 1291finish: 1292 1293 return result; 1294} 1295 1296/******************************************************************************* 1297*******************************************************************************/ 1298ExitStatus 1299runTestsOnKext( 1300 OSKextRef aKext, 1301 char * kextPathCString, 1302 KextutilArgs * toolArgs, 1303 Boolean * fatal) 1304{ 1305 ExitStatus result = EX_OK; 1306 ExitStatus tempResult = EX_OK; 1307 Boolean kextLooksGood = true; 1308 Boolean tryLink = false; 1309 OSKextLogSpec logFilter = OSKextGetLogFilter(/* kernel? */ false); 1310 OSStatus sigResult = 0; 1311 1312 /* Print message if not loadable in safe boot, but keep going 1313 * for further test results. 1314 */ 1315 if (toolArgs->safeBootMode && 1316 !OSKextIsLoadableInSafeBoot(aKext)) { 1317 1318 Boolean mustQualify = (toolArgs->doLoad || toolArgs->doStartMatching); 1319 OSKextLogSpec msgLogLevel = kOSKextLogErrorLevel; 1320 1321 if (mustQualify) { 1322 msgLogLevel = kOSKextLogWarningLevel; 1323 } 1324 1325 OSKextLog(/* kext */ NULL, 1326 msgLogLevel | kOSKextLogLoadFlag, 1327 "%s%s is not eligible for loading during safe boot.", 1328 // label it just a notice if we won't be loading 1329 mustQualify ? "" : "Notice: ", 1330 kextPathCString); 1331 1332 if (mustQualify && result == EX_OK) { 1333 result = kKextutilExitSafeBoot; 1334 } 1335 } 1336 1337 if (OSKextHasLogOrDebugFlags(aKext)) { 1338 // xxx - check newline 1339 OSKextLog(/* kext */ NULL, 1340 kOSKextLogWarningLevel | kOSKextLogLoadFlag, 1341 "Notice: %s has debug properties set.", kextPathCString); 1342 } 1343 1344 /* Run the tests for this kext. These would normally be done during 1345 * a load anyhow, but we need the results up-front. *Always* call 1346 * the test function before the && so it actually runs; we want all 1347 * tests performed. 1348 */ 1349 kextLooksGood = OSKextValidate(aKext) && kextLooksGood; 1350 if (!toolArgs->skipAuthentication) { 1351 kextLooksGood = OSKextAuthenticate(aKext) && kextLooksGood; 1352 } 1353 if (!toolArgs->skipDependencies) { 1354 kextLooksGood = OSKextResolveDependencies(aKext) && kextLooksGood; 1355 kextLooksGood = OSKextValidateDependencies(aKext) && kextLooksGood; 1356 if (!toolArgs->skipAuthentication) { 1357 kextLooksGood = OSKextAuthenticateDependencies(aKext) && 1358 kextLooksGood; 1359 } 1360 } 1361 1362 /* Check for safe boot loadability. Note we do each check separately so as 1363 * not so short-circuit the checks; we want all diagnostics available. 1364 */ 1365 if (toolArgs->safeBootMode) { 1366 kextLooksGood = OSKextIsLoadableInSafeBoot(aKext) && kextLooksGood; 1367 kextLooksGood = OSKextDependenciesAreLoadableInSafeBoot(aKext) && kextLooksGood; 1368 } 1369 1370 /* Check code signature for diagnotic messages. 1371 */ 1372 sigResult = checkKextSignature(aKext, false, false); 1373 1374 /***** 1375 * Print diagnostics/warnings as needed, set status if kext can't be used. 1376 */ 1377 if (!kextLooksGood || sigResult != 0) { 1378 if ((logFilter & kOSKextLogLevelMask) >= kOSKextLogErrorLevel) { 1379 OSKextLog(aKext, 1380 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1381 "Diagnostics for %s:", 1382 kextPathCString); 1383 1384 OSKextLogDiagnostics(aKext, kOSKextDiagnosticsFlagAll); 1385 if (sigResult != 0) { 1386 OSKextLog(aKext, 1387 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1388 "Code Signing Failure: %s", 1389 (sigResult == errSecCSUnsigned 1390 ? "not code signed" 1391 : "code signature is invalid") ); 1392 } 1393 } 1394 if (!kextLooksGood) { 1395 result = kKextutilExitKextBad; 1396 goto finish; 1397 } 1398 } 1399 1400 /* Print diagnostics/warnings as needed, set status if kext can't be used. 1401 */ 1402 if (result == EX_OK) { 1403 if ((logFilter & kOSKextLogLevelMask) >= kOSKextLogWarningLevel) { 1404 // xxx - used to print "%s has potential problems:", kextPathCString 1405 OSKextLogDiagnostics(aKext, kOSKextDiagnosticsFlagWarnings); 1406 } 1407 } 1408 1409 /* Do a trial link if we aren't otherwise linking, and replace a non-error 1410 * result with the tempResult of linking. 1411 */ 1412 tryLink = !toolArgs->doLoad && 1413 !toolArgs->symbolDirURL && 1414 kextLooksGood; 1415 tryLink = tryLink && 1416 ((OSKextGetArchitecture() == OSKextGetRunningKernelArchitecture()) || 1417 toolArgs->kernelURL); 1418 if (tryLink) { 1419 1420 tempResult = generateKextSymbols(aKext, 1421 kextPathCString, toolArgs, /* save? */ false, fatal); 1422 tryLink = true; 1423 if (result == EX_OK) { 1424 result = tempResult; 1425 } 1426 // Do not goto finish from here! We want to print diagnostics first. 1427 } 1428 1429 if (result == EX_OK) { 1430 OSKextLog(/* kext */ NULL, 1431 kOSKextLogBasicLevel | kOSKextLogLoadFlag, 1432 "%s appears to be loadable (%sincluding linkage for on-disk libraries).", 1433 kextPathCString, tryLink ? "" : "not "); 1434 } 1435 1436#if 0 1437// just testing this 1438 OSKextLogDependencyGraph(aKext, /* bundleIDs */ true, 1439 /* linkGraph */ true); 1440#endif 1441 1442finish: 1443 return result; 1444} 1445 1446/******************************************************************************* 1447*******************************************************************************/ 1448ExitStatus 1449loadKext( 1450 OSKextRef aKext, 1451 char * kextPathCString, 1452 KextutilArgs * toolArgs, 1453 Boolean * fatal) 1454{ 1455 ExitStatus result = EX_OK; 1456 OSKextExcludeLevel startExclude = toolArgs->interactiveLevel; 1457 OSKextExcludeLevel matchExclude = toolArgs->interactiveLevel; 1458 CFArrayRef personalityNames = toolArgs->personalityNames; 1459 OSReturn loadResult = kOSReturnError; 1460 1461 if (OSKextIsInExcludeList(aKext, false)) { 1462#if 1 // <rdar://problem/12811081> 1463 /* notify kextd we are trying to load an excluded kext. 1464 */ 1465 CFMutableDictionaryRef myAlertInfoDict = NULL; // must release 1466 1467 addKextToAlertDict(&myAlertInfoDict, aKext); 1468 if (myAlertInfoDict) { 1469 postNoteAboutKexts(CFSTR("Excluded Kext Notification"), 1470 myAlertInfoDict ); 1471 SAFE_RELEASE(myAlertInfoDict); 1472 } 1473#endif 1474 1475 messageTraceExcludedKext(aKext); 1476 OSKextLog(NULL, 1477 kOSKextLogErrorLevel | kOSKextLogArchiveFlag | 1478 kOSKextLogValidationFlag | kOSKextLogGeneralFlag, 1479 "%s is in exclude list; omitting.", kextPathCString); 1480 result = kOSKextReturnNotLoadable; 1481 *fatal = true; 1482 goto finish; 1483 } 1484 1485 /* INTERACTIVE: ask if ok to load kext and its dependencies 1486 */ 1487 if (toolArgs->interactiveLevel != kOSKextExcludeNone) { 1488 1489 switch (user_approve(/* ask_all */ FALSE, /* default_answer */ REPLY_YES, 1490 "Load %s and its dependencies into the kernel", 1491 kextPathCString)) { 1492 1493 case REPLY_NO: 1494 fprintf(stderr, "Not loading %s.", kextPathCString); 1495 goto finish; // result is EX_OK! 1496 break; 1497 case REPLY_YES: 1498 break; 1499 default: 1500 fprintf(stderr, "Failed to read response."); 1501 result = EX_SOFTWARE; 1502 *fatal = true; 1503 goto finish; 1504 break; 1505 } 1506 } 1507 1508 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogLoadFlag, 1509 "Loading %s.", kextPathCString); 1510 1511 /* Mask out the personality/matching args as required. 1512 */ 1513 if (toolArgs->interactiveLevel != kOSKextExcludeNone) { 1514 personalityNames = NULL; 1515 } 1516 if (!toolArgs->doStartMatching) { 1517 matchExclude = kOSKextExcludeAll; 1518 } 1519 1520 loadResult = OSKextLoadWithOptions(aKext, 1521 startExclude, matchExclude, personalityNames, 1522 /* disableAutounload */ (startExclude != kOSKextExcludeNone)); 1523 1524 if (loadResult == kOSReturnSuccess) { 1525 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogLoadFlag, 1526 "%s successfully loaded (or already loaded).", 1527 kextPathCString); 1528 } else { 1529 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogLoadFlag, 1530 "Failed to load %s - %s.", 1531 kextPathCString, safe_mach_error_string(loadResult)); 1532 } 1533 1534 if (loadResult == kOSKextReturnLinkError) { 1535 OSKextLog(/* kext */ NULL, 1536 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1537 "Check library declarations for your kext with kextlibs(8)."); 1538 } 1539 1540 if (loadResult != kOSReturnSuccess) { 1541 result = kKextutilExitLoadFailed; 1542 } 1543 1544finish: 1545 return result; 1546} 1547 1548/******************************************************************************* 1549*******************************************************************************/ 1550// xxx - generally need to figure out when to flush what 1551 1552ExitStatus generateKextSymbols( 1553 OSKextRef aKext, 1554 char * kextPathCString, 1555 KextutilArgs * toolArgs, 1556 Boolean saveFlag, 1557 Boolean * fatal) 1558{ 1559 ExitStatus result = EX_OK; 1560 CFArrayRef loadList = NULL; // must release 1561 CFDictionaryRef kextSymbols = NULL; // must release 1562 const NXArchInfo * archInfo = NULL; // do not free 1563 CFIndex count, i; 1564 1565 if (saveFlag && !toolArgs->symbolDirURL) { 1566 result = EX_USAGE; 1567 *fatal = TRUE; 1568 goto finish; 1569 } 1570 1571 // xxx - we might want to check these before processing any kexts 1572 if (OSKextIsKernelComponent(aKext)) { 1573 OSKextLog(/* kext */ NULL, 1574 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1575 "%s is a kernel component; no symbols to generate.", 1576 kextPathCString); 1577 result = EX_DATAERR; 1578 goto finish; 1579 } 1580 1581 if (OSKextIsInterface(aKext)) { 1582 OSKextLog(/* kext */ NULL, 1583 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1584 "%s is a an interface kext; no symbols to generate.", 1585 kextPathCString); 1586 result = EX_DATAERR; 1587 goto finish; 1588 } 1589 1590 archInfo = OSKextGetArchitecture(); 1591 if (!OSKextSupportsArchitecture(aKext, archInfo)) { 1592 int native = (archInfo == NXGetLocalArchInfo()); 1593 OSKextLog(/* kext */ NULL, 1594 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1595 "%s does not contain code for %sarchitecture%s%s.", 1596 kextPathCString, 1597 native ? "this computer's " : "", 1598 native ? "" : " ", 1599 native ? "" : archInfo->name); 1600 result = kKextutilExitArchNotFound; 1601 goto finish; 1602 } 1603 1604 /***** 1605 * If we don't have a load address for aKext, ask for load addresses for it 1606 * and any of its dependencies. 1607 * NOTE (9656777) - OSKextNeedsLoadAddressForDebugSymbols() needs to be 1608 * called even if we loaded the kext. The reason is that loading the kext 1609 * does not necessarily mean the load address was set in the load info 1610 * kept in the kernel. Calling OSKextNeedsLoadAddressForDebugSymbols() 1611 * will implicitly set the load address if the kernel has it thus 1612 * avoiding having to ask the user for it. And without that load address 1613 * we silently give back a partial symbol file that gdb dislikes. 1614 */ 1615 if (saveFlag && 1616 OSKextNeedsLoadAddressForDebugSymbols(aKext)) { 1617 1618 loadList = OSKextCopyLoadList(aKext, /* needAll */ true); 1619 if (!loadList) { 1620 OSKextLog(/* kext */ NULL, 1621 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 1622 "Can't resolve dependencies for %s.", 1623 kextPathCString); 1624 result = EX_SOFTWARE; 1625 *fatal = true; 1626 goto finish; 1627 } 1628 1629 /***** 1630 * For each kext w/o an address in loadAddresses, ask for an address. 1631 */ 1632 1633 fprintf(stderr, "\nEnter the hexadecimal load addresses for these extensions\n" 1634 "(press Return to skip symbol generation for an extension):\n\n"); 1635 1636 count = CFArrayGetCount(loadList); 1637 for (i = 0; i < count; i++) { 1638 OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex(loadList, i); 1639 Boolean mainNeedsAddress = ((i + 1) == count); 1640 1641 do { 1642 switch (requestLoadAddress(thisKext)) { 1643 case -1: // error 1644 result = EX_SOFTWARE; 1645 goto finish; 1646 break; 1647 case 0: // user cancel 1648 fprintf(stderr, "\nuser canceled address input; exiting\n"); 1649 result = kKextutilExitUserAbort; 1650 goto finish; 1651 break; 1652 case 1: // ok to continue 1653 break; 1654 } /* switch */ 1655 1656 /* If we didn't get a load address for the main kext, the user 1657 * probably hit Return too many times. 1658 */ 1659 if (mainNeedsAddress && OSKextNeedsLoadAddressForDebugSymbols(aKext)) { 1660 switch (user_approve(/* ask_all */ FALSE, /* default_anser */ REPLY_NO, 1661 "\n%s is the main extension; really skip", kextPathCString)) { 1662 case REPLY_NO: 1663 break; 1664 case REPLY_YES: 1665 result = EX_OK; 1666 goto finish; // skip symbol gen. 1667 default: 1668 result = EX_SOFTWARE; 1669 goto finish; 1670 } 1671 } 1672 } while (mainNeedsAddress && OSKextNeedsLoadAddressForDebugSymbols(aKext)); 1673 } 1674 } 1675 1676 kextSymbols = OSKextGenerateDebugSymbols(aKext, toolArgs->kernelFile); 1677 if (!kextSymbols) { 1678 OSKextLog(/* kext */ NULL, 1679 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1680 "Check library declarations for your kext with kextlibs(8)."); 1681 result = kKextutilExitKextBad; // more probably than an EX_OSERR 1682 *fatal = true; 1683 goto finish; 1684 } 1685 1686 if (saveFlag) { 1687 SaveFileContext saveFileContext; 1688 saveFileContext.saveDirURL = toolArgs->symbolDirURL; 1689 saveFileContext.overwrite = toolArgs->overwriteSymbols; 1690 saveFileContext.fatal = false; 1691 CFDictionaryApplyFunction(kextSymbols, &saveFile, &saveFileContext); 1692 if (saveFileContext.fatal) { 1693 *fatal = true; 1694 goto finish; 1695 } 1696 } 1697 1698finish: 1699 SAFE_RELEASE(loadList); 1700 SAFE_RELEASE(kextSymbols); 1701 1702 return result; 1703} 1704 1705 1706/******************************************************************************* 1707*******************************************************************************/ 1708int 1709requestLoadAddress( 1710 OSKextRef aKext) 1711{ 1712 int result = -1; 1713 char * bundleIDCString = NULL; // must free 1714 char * user_response = NULL; // must free 1715 char * scan_pointer = NULL; // do not free 1716 uint64_t address = 0; 1717 Boolean eof = false; 1718 1719 bundleIDCString = createUTF8CStringForCFString( 1720 OSKextGetIdentifier(aKext)); 1721 if (!bundleIDCString) { 1722 goto finish; 1723 } 1724 1725 if (OSKextNeedsLoadAddressForDebugSymbols(aKext)) { 1726 1727 while (1) { 1728 SAFE_FREE(user_response); 1729 1730 user_response = (char *)user_input(&eof, "%s:", bundleIDCString); 1731 if (eof) { 1732 result = 0; 1733 goto finish; 1734 } 1735 if (!user_response) { 1736 goto finish; 1737 } 1738 1739 /* User wants to skip this one, don't set address & return success. 1740 */ 1741 if (user_response[0] == '\0') { 1742 result = 1; 1743 goto finish; 1744 break; 1745 } 1746 1747 errno = 0; 1748 address = strtoull(user_response, &scan_pointer, 16); 1749 1750 if (address == ULONG_LONG_MAX && errno == ERANGE) { 1751 fprintf(stderr, "input address %s is too large; try again\n", 1752 user_response); 1753 continue; 1754 } else if (address == 0 && errno == EINVAL) { 1755 fprintf(stderr, "no address found in input '%s'; try again\n", 1756 user_response); 1757 continue; 1758 } else if (address == 0) { 1759 fprintf(stderr, "invalid address %s\n", 1760 user_response); 1761 continue; 1762 } else if (*scan_pointer != '\0') { 1763 fprintf(stderr, 1764 "input '%s' not a plain hexadecimal address; try again\n", 1765 user_response); 1766 continue; 1767 } else { 1768 break; 1769 } 1770 } 1771 1772 OSKextSetLoadAddress(aKext, address); 1773 } 1774 1775 result = 1; 1776 1777finish: 1778 SAFE_FREE(bundleIDCString); 1779 SAFE_FREE(user_response); 1780 return result; 1781} 1782 1783/******************************************************************************* 1784xxx - should we be using paths or bundleids? 1785*******************************************************************************/ 1786ExitStatus startKextsAndSendPersonalities( 1787 OSKextRef aKext, 1788 KextutilArgs * toolArgs, 1789 Boolean * fatal) 1790{ 1791 ExitStatus result = EX_OK; 1792 CFArrayRef loadList = NULL; // must release 1793 CFMutableArrayRef kextIdentifiers = NULL; // must release 1794 char * kextIDCString = NULL; // must free 1795 char * thisKextIDCString = NULL; // must free 1796 Boolean startedAndPersonalitiesSent = TRUE; // loop breaks if ever false 1797 Boolean yesToAllKexts = FALSE; 1798 Boolean yesToAllKextPersonalities = FALSE; 1799 char kextPath[PATH_MAX]; 1800 CFIndex count, i; // used unothodoxically! 1801 1802 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(aKext), 1803 /* resoveToBase */ false, (UInt8*)kextPath, sizeof(kextPath))) { 1804 1805 strlcpy(kextPath, "(unknown)", sizeof(kextPath)); 1806 } 1807 1808 kextIDCString = createUTF8CStringForCFString(OSKextGetIdentifier(aKext)); 1809 if (!kextIDCString) { 1810 OSKextLogMemError(); 1811 result = EX_OSERR; 1812 } 1813 1814 loadList = OSKextCopyLoadList(aKext, /* needAll */ true); 1815 if (!loadList) { 1816 OSKextLog(/* kext */ NULL, 1817 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1818 "Can't get dependency list for %s.", 1819 kextIDCString); 1820 result = EX_OSERR; 1821 goto finish; 1822 } 1823 1824 count = CFArrayGetCount(loadList); 1825 if (!count) { 1826 OSKextLog(/* kext */ NULL, 1827 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 1828 "Internal error - empty load list."); 1829 result = EX_SOFTWARE; 1830 *fatal = true; 1831 goto finish; 1832 } 1833 1834 /* We'll be using this in a call to OSKextReadLoadedKextInfo() 1835 * if something goes wrong. 1836 */ 1837 kextIdentifiers = CFArrayCreateMutable(CFGetAllocator(aKext), 1838 count, &kCFTypeArrayCallBacks); 1839 if (!kextIdentifiers) { 1840 OSKextLogMemError(); 1841 result = EX_OSERR; 1842 goto finish; 1843 } 1844 1845 /***** 1846 * For interactive loading to do gdb on start functions, 1847 * go through the load list and print the started status of each kext. 1848 */ 1849 if (toolArgs->interactiveLevel != kOSKextExcludeNone && toolArgs->doLoad) { 1850 1851 fprintf(stderr, "\n" 1852 "%s and its dependencies are now loaded, and started as listed below. " 1853 "You can now return to the debugger to set breakpoints before starting " 1854 "any kexts that need to be started.\n\n", 1855 kextPath); 1856 1857 /* If we're only doing interactive for the main kext, bump the loop 1858 * index to the last one. 1859 */ 1860 if (toolArgs->interactiveLevel == kOSKextExcludeKext) { 1861 i = count - 1; 1862 } else { 1863 i = 0; 1864 } 1865 for (/* see above */ ; i < count; i++) { 1866 OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex( 1867 loadList, i); 1868 const char * status = NULL; 1869 1870 SAFE_FREE_NULL(thisKextIDCString); 1871 1872 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(thisKext), 1873 /* resoveToBase */ false, (UInt8*)kextPath, sizeof(kextPath))) { 1874 1875 strlcpy(kextPath, "(unknown)", sizeof(kextPath)); 1876 } 1877 1878 thisKextIDCString = createUTF8CStringForCFString(OSKextGetIdentifier(thisKext)); 1879 if (!thisKextIDCString) { 1880 OSKextLogMemError(); 1881 result = EX_OSERR; 1882 goto finish; 1883 } 1884 1885 if (OSKextIsInterface(thisKext)) { 1886 status = "interface, not startable"; 1887 } else if (!OSKextDeclaresExecutable(thisKext)) { 1888 status = "no executable, not startable"; 1889 } else if (OSKextIsStarted(thisKext)) { 1890 status = "already started"; 1891 } else { 1892 status = "not started"; 1893 } 1894 fprintf(stderr, " %s - %s\n", thisKextIDCString, status); 1895 } 1896 1897 fprintf(stderr, "\n"); 1898 } 1899 1900 /***** 1901 * Now go through and actually process each kext. 1902 */ 1903 1904 /* If we're only doing interactive for the main kext, bump the loop 1905 * index to the last one. 1906 */ 1907 if (toolArgs->interactiveLevel == kOSKextExcludeKext) { 1908 i = count - 1; 1909 } else { 1910 i = 0; 1911 } 1912 for (/* see above */ ; i < count; i++) { 1913 OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex( 1914 loadList, i); 1915 1916 SAFE_FREE_NULL(thisKextIDCString); 1917 1918 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(thisKext), 1919 /* resoveToBase */ false, (UInt8*)kextPath, sizeof(kextPath))) { 1920 1921 strlcpy(kextPath, "(unknown)", sizeof(kextPath)); 1922 } 1923 1924 CFArrayAppendValue(kextIdentifiers, OSKextGetIdentifier(thisKext)); 1925 1926 thisKextIDCString = createUTF8CStringForCFString(OSKextGetIdentifier(thisKext)); 1927 if (!thisKextIDCString) { 1928 OSKextLogMemError(); 1929 result = EX_OSERR; 1930 goto finish; 1931 } 1932 1933 /* Normally the kext is started when loaded, so only try to start it here 1934 * if we're in interactive mode and we loaded it. 1935 */ 1936 if (toolArgs->interactiveLevel != kOSKextExcludeNone && toolArgs->doLoad) { 1937 if (!OSKextIsStarted(thisKext)) { 1938 result = startKext(thisKext, kextPath, toolArgs, 1939 &startedAndPersonalitiesSent, &yesToAllKexts, fatal); 1940 if (result != EX_OK || !startedAndPersonalitiesSent) { 1941 break; 1942 } 1943 } 1944 } 1945 1946 /* Normally the kext's personalities are sent when the kext is loaded, 1947 * so send them from here only if we are in interactive mode or 1948 * if we are only sending personalities and not loading. 1949 * It's ok to send personalities again if they're already in the kernel; 1950 * that just restarts matching. 1951 */ 1952 if (toolArgs->interactiveLevel != kOSKextExcludeNone || 1953 (toolArgs->doStartMatching && !toolArgs->doLoad)) { 1954 1955 result = sendPersonalities(thisKext, kextPath, toolArgs, 1956 /* isMain */ (i + 1 == count), &yesToAllKextPersonalities, fatal); 1957 if (result != EX_OK) { 1958 startedAndPersonalitiesSent = false; 1959 break; 1960 } 1961 } 1962 } 1963 1964 /* If the whole graph didn't start, go backward through it unloading 1965 * any kext that didn't start. We could optimize this a bit by providing 1966 * a list of the kext identifiers in the load list. 1967 */ 1968 if (!startedAndPersonalitiesSent) { 1969 OSReturn readLoadedResult = OSKextReadLoadedKextInfo( 1970 kextIdentifiers, /* flushDependencies */ false); 1971 1972 if (kOSReturnSuccess != readLoadedResult) { 1973 OSKextLog(/* kext */ NULL, 1974 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 1975 "Failed to read load info after starting - %s.", 1976 safe_mach_error_string(readLoadedResult)); 1977 result = EX_OSERR; 1978 *fatal = true; 1979 } 1980 1981 for (i = count - 1; i >= 0; i--) { 1982 OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex( 1983 loadList, i); 1984 1985 if (!CFURLGetFileSystemRepresentation(OSKextGetURL(thisKext), 1986 /* resoveToBase */ false, (UInt8*)kextPath, sizeof(kextPath))) { 1987 1988 strlcpy(kextPath, "(unknown)", sizeof(kextPath)); 1989 } 1990 1991 if (!OSKextIsStarted(thisKext)) { 1992 OSReturn unloadResult = OSKextUnload(thisKext, 1993 /* terminateIOServicesAndRemovePersonalities */ true); 1994 1995 OSKextLog(/* kext */ NULL, 1996 kOSKextLogStepLevel | kOSKextLogLoadFlag, 1997 "Unloading kext %s after failing to start/send personalities.", kextPath); 1998 1999 if (kOSReturnSuccess != unloadResult) { 2000 OSKextLog(/* kext */ NULL, 2001 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 2002 "Failed to unload kext %s after failing to start/send personalities - %s.", 2003 kextPath, 2004 safe_mach_error_string(unloadResult)); 2005 result = EX_OSERR; 2006 } else { 2007 OSKextLog(/* kext */ NULL, 2008 kOSKextLogStepLevel | kOSKextLogLoadFlag, 2009 "%s unloaded.", kextPath); 2010 } 2011 } 2012 } 2013 } 2014 2015finish: 2016 SAFE_RELEASE(loadList); 2017 SAFE_RELEASE(kextIdentifiers); 2018 SAFE_FREE(kextIDCString); 2019 SAFE_FREE(thisKextIDCString); 2020 return result; 2021} 2022 2023/******************************************************************************* 2024* Be explicit about setting started either way here. 2025*******************************************************************************/ 2026ExitStatus startKext( 2027 OSKextRef aKext, 2028 char * kextPathCString, 2029 KextutilArgs * toolArgs, 2030 Boolean * started, 2031 Boolean * yesToAll, 2032 Boolean * fatal) 2033{ 2034 ExitStatus result = EX_OK; 2035 OSReturn startResult = kOSReturnError; 2036 2037// xxx - check on the log calls in interactive mode; use fprintf instead? 2038 2039 /* Check if the dependency is still loaded. It should be, of course. 2040 * This error is not fatal for the overall program, but we leave 2041 * this function since we can't start any other dependencies 2042 * up to the main kext that was loaded. 2043 */ 2044 if (!OSKextIsLoaded(aKext)) { 2045 OSKextLog(/* kext */ NULL, 2046 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 2047 "%s is unexpectedly not loaded after loading!", 2048 kextPathCString); 2049 *started = false; 2050 result = EX_OSERR; 2051 goto finish; 2052 } 2053 2054 if (FALSE == *yesToAll) { 2055 switch (user_approve(/* ask_all */ TRUE, 2056 /* default_answer */ REPLY_YES, 2057 "Start %s", 2058 kextPathCString)) { 2059 2060 case REPLY_NO: 2061 OSKextLog(/* kext */ NULL, 2062 kOSKextLogBasicLevel | kOSKextLogLoadFlag, 2063 "Not starting %s.", 2064 kextPathCString); 2065 *started = false; 2066 goto finish; // result is EX_OK! 2067 break; 2068 case REPLY_YES: 2069 break; 2070 case REPLY_ALL: 2071 fprintf(stderr, "Starting all kexts just loaded.\n"); 2072 *yesToAll = TRUE; 2073 break; 2074 default: 2075 OSKextLog(/* kext */ NULL, 2076 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 2077 "Error: couldn't read response."); 2078 result = EX_SOFTWARE; 2079 *started = false; 2080 *fatal = true; 2081 goto finish; 2082 break; 2083 } 2084 } 2085 2086 startResult = OSKextStart(aKext); 2087 if (kOSReturnSuccess != startResult) { 2088 OSKextLog(/* kext */ NULL, 2089 kOSKextLogErrorLevel | kOSKextLogLoadFlag, 2090 "%s failed to start - %s.", 2091 kextPathCString, 2092 safe_mach_error_string(startResult)); 2093 2094 *started = false; 2095 result = EX_OSERR; 2096 goto finish; 2097 } else { 2098 OSKextLog(/* kext */ NULL, 2099 kOSKextLogBasicLevel | kOSKextLogLoadFlag, 2100 "%s started.", kextPathCString); 2101 *started = true; 2102 } 2103 2104finish: 2105 return result; 2106} 2107 2108/******************************************************************************* 2109*******************************************************************************/ 2110ExitStatus sendPersonalities( 2111 OSKextRef aKext, 2112 char * kextPathCString, 2113 KextutilArgs * toolArgs, 2114 Boolean isMainFlag, 2115 Boolean * yesToAllKextPersonalities, 2116 Boolean * fatal) 2117{ 2118 ExitStatus result = EX_OK; 2119 CFDictionaryRef kextPersonalities = NULL; // do not release 2120 CFMutableArrayRef namesToSend = NULL; // must release 2121 CFStringRef * names = NULL; // must free 2122 char * nameCString = NULL; // must free 2123 OSReturn sendPersonalitiesResult = kOSReturnError; 2124 Boolean yesToAllPersonalities = FALSE; 2125 CFIndex count, i; 2126 2127 kextPersonalities = OSKextGetValueForInfoDictionaryKey(aKext, 2128 CFSTR(kIOKitPersonalitiesKey)); 2129 if (!kextPersonalities || !CFDictionaryGetCount(kextPersonalities)) { 2130 OSKextLog(/* kext */ NULL, 2131 kOSKextLogStepLevel | kOSKextLogLoadFlag, 2132 "%s has no personalities to send.", 2133 kextPathCString); 2134 goto finish; 2135 } 2136 2137 if (toolArgs->interactiveLevel != kOSKextExcludeNone) { 2138 if (FALSE == *yesToAllKextPersonalities) { 2139 switch (user_approve(/* ask_all */ TRUE, /* default_answer */ REPLY_YES, 2140 "Send personalities for %s", 2141 kextPathCString)) { 2142 2143 case REPLY_NO: 2144 fprintf(stderr, "Not sending personalities for %s.", kextPathCString); 2145 goto finish; // result is EX_OK! 2146 break; 2147 case REPLY_YES: 2148 break; 2149 case REPLY_ALL: 2150 fprintf(stderr, "Sending personalities for all kexts just loaded.\n"); 2151 *yesToAllKextPersonalities = TRUE; 2152 break; 2153 default: 2154 fprintf(stderr, "Error: couldn't read response."); 2155 result = EX_SOFTWARE; 2156 *fatal = true; 2157 goto finish; 2158 break; 2159 } 2160 } 2161 } 2162 2163 namesToSend = CFArrayCreateMutable(kCFAllocatorDefault, 0, 2164 &kCFTypeArrayCallBacks); 2165 if (!namesToSend) { 2166 OSKextLogMemError(); 2167 result = EX_OSERR; 2168 *fatal = true; 2169 goto finish; 2170 } 2171 2172 count = CFDictionaryGetCount(kextPersonalities); 2173 names = (CFStringRef *)malloc(count * sizeof(CFStringRef)); 2174 if (!names) { 2175 OSKextLogMemError(); 2176 result = EX_OSERR; 2177 *fatal = true; 2178 goto finish; 2179 } 2180 CFDictionaryGetKeysAndValues(kextPersonalities, 2181 (const void **)names, NULL); 2182 2183 for (i = 0; i < count; i++) { 2184 Boolean includeIt = TRUE; 2185 2186 SAFE_FREE_NULL(nameCString); 2187 2188 nameCString = createUTF8CStringForCFString(names[i]); 2189 if (!nameCString) { 2190 OSKextLogMemError(); 2191 result = EX_OSERR; 2192 *fatal = true; 2193 goto finish; 2194 } 2195 2196 /* If -p was used on the command line, only consider those personalities. 2197 */ 2198 if (isMainFlag && CFArrayGetCount(toolArgs->personalityNames) > 0) { 2199 if (kCFNotFound == CFArrayGetFirstIndexOfValue( 2200 toolArgs->personalityNames, 2201 RANGE_ALL(toolArgs->personalityNames), names[i])) { 2202 2203 continue; 2204 } 2205 } 2206 2207 if (toolArgs->interactiveLevel != kOSKextExcludeNone && 2208 FALSE == *yesToAllKextPersonalities) { 2209 2210 if (FALSE == yesToAllPersonalities) { 2211 switch (user_approve(/* ask_all */ TRUE, /* default_answer */ REPLY_YES, 2212 "Send personality %s", nameCString)) { 2213 2214 case REPLY_NO: 2215 includeIt = FALSE; 2216 break; 2217 case REPLY_YES: 2218 includeIt = TRUE; 2219 break; 2220 case REPLY_ALL: 2221 fprintf(stderr, "Sending all personalities for %s.\n", 2222 kextPathCString); 2223 includeIt = TRUE; 2224 yesToAllPersonalities = TRUE; 2225 break; 2226 default: 2227 fprintf(stderr, "Error: couldn't read response."); 2228 result = EX_SOFTWARE; 2229 *fatal = true; 2230 goto finish; 2231 break; 2232 } /* switch */ 2233 } /* if (!*yesToAll) */ 2234 } /* if (toolArgs->interactiveLevel ... ) */ 2235 2236 if (includeIt) { 2237 CFArrayAppendValue(namesToSend, names[i]); 2238 } 2239 } /* for */ 2240 2241 OSKextLog(/* kext */ NULL, 2242 kOSKextLogStepLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 2243 "Sending personalities of %s to the IOCatalogue.", 2244 kextPathCString); 2245 2246 sendPersonalitiesResult = OSKextSendKextPersonalitiesToKernel(aKext, namesToSend); 2247 if (kOSReturnSuccess != sendPersonalitiesResult) { 2248 OSKextLog(/* kext */ NULL, 2249 kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 2250 "Failed to send personalities for %s - %s.", 2251 kextPathCString, 2252 safe_mach_error_string(sendPersonalitiesResult)); 2253 2254 result = EX_OSERR; 2255 goto finish; 2256 } else { 2257 OSKextLog(/* kext */ NULL, 2258 kOSKextLogStepLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag, 2259 "Personalities sent for %s.", kextPathCString); 2260 } 2261 2262finish: 2263 SAFE_RELEASE(namesToSend); 2264 SAFE_FREE(names); 2265 SAFE_FREE(nameCString); 2266 return result; 2267} 2268 2269/******************************************************************************* 2270*******************************************************************************/ 2271Boolean serializeLoad(KextutilArgs * toolArgs, Boolean loadFlag) 2272{ 2273 Boolean result = false; 2274 kern_return_t kern_result; 2275 int lock_retries = LOCK_MAXTRIES; 2276 2277 if (!loadFlag) { 2278 result = true; 2279 goto finish; 2280 } 2281 2282 /***** 2283 * Serialize running kextload processes that are actually loading. Note 2284 * that we can't bail on failing to contact kextd, we can only print 2285 * warnings, since kextload may need to be run in single-user mode. We 2286 * do bail on hard OS errors though. 2287 */ 2288 kern_result = bootstrap_look_up(bootstrap_port, 2289 KEXTD_SERVER_NAME, &sKextdPort); 2290 if (kern_result != KERN_SUCCESS) { 2291 2292 OSKextLog(/* kext */ NULL, 2293 kOSKextLogWarningLevel | kOSKextLogIPCFlag, 2294 "Can't contact kextd (continuing anyway) - %s.", 2295 bootstrap_strerror(kern_result)); 2296 } 2297 if (sKextdPort != MACH_PORT_NULL) { 2298 kern_result = mach_port_allocate(mach_task_self(), 2299 MACH_PORT_RIGHT_RECEIVE, &sLockPort); 2300 if (kern_result != KERN_SUCCESS) { 2301 OSKextLog(/* kext */ NULL, 2302 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 2303 "Can't allocate kext loading serialization mach port."); 2304 goto finish; 2305 } 2306 do { 2307 kern_result = kextmanager_lock_kextload(sKextdPort, sLockPort, 2308 &sLockStatus); 2309 if (kern_result != KERN_SUCCESS) { 2310 OSKextLog(/* kext */ NULL, 2311 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 2312 "Can't acquire kextload serialization lock; aborting."); 2313 goto finish; 2314 } 2315 2316 if (sLockStatus == EBUSY) { 2317 --lock_retries; 2318 OSKextLog(/* kext */ NULL, 2319 kOSKextLogWarningLevel | kOSKextLogIPCFlag, 2320 "Kext loading serialization lock busy; " 2321 "sleeping (%d retries left).", 2322 lock_retries); 2323 sleep(LOCK_DELAY); 2324 } 2325 } while (sLockStatus == EBUSY && lock_retries > 0); 2326 2327 if (sLockStatus != 0) { 2328 OSKextLog(/* kext */ NULL, 2329 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 2330 "Can't acquire kextload serialization lock; aborting."); 2331 goto finish; 2332 } else { 2333 sLockTaken = true; 2334 } 2335 } 2336 2337 result = true; 2338finish: 2339 return result; 2340} 2341 2342/******************************************************************************* 2343* usage() 2344*******************************************************************************/ 2345void usage(UsageLevel usageLevel) 2346{ 2347 fprintf(stderr, "usage: %s [options] [--] [kext] ...\n" 2348 "\n", progname); 2349 2350 if (usageLevel == kUsageLevelBrief) { 2351 fprintf(stderr, "use %s -%s for an explanation of each option\n", 2352 progname, kOptNameHelp); 2353 return; 2354 } 2355 2356 fprintf(stderr, "kext: a kext bundle to load or examine\n"); 2357 fprintf(stderr, "\n"); 2358 2359 fprintf(stderr, "-%s <bundle_id> (-%c):\n" 2360 " load/use the kext whose CFBundleIdentifier is <bundle_id>\n", 2361 kOptNameBundleIdentifier, kOptBundleIdentifier); 2362 fprintf(stderr, "-%s <personality> (-%c):\n" 2363 " send the named personality to the catalog\n", 2364 kOptNamePersonality, kOptPersonality); 2365 fprintf(stderr, "-%s <kext> (-%c):\n" 2366 " consider <kext> as a candidate dependency\n", 2367 kOptNameDependency, kOptDependency); 2368 fprintf(stderr, "-%s <directory> (-%c):\n" 2369 " look in <directory> for kexts\n", 2370 kOptNameRepository, kOptRepository); 2371 fprintf(stderr, "\n"); 2372 2373 fprintf(stderr, "-%s (-%c):\n" 2374 " don't use repository caches; scan repository folders\n", 2375 kOptNameNoCaches, kOptNoCaches); 2376 fprintf(stderr, "-%s (-%c):\n" 2377 " don't check for loaded kexts when resolving dependencies " 2378 "(deprecated)\n", 2379 kOptNameNoLoadedCheck, kOptNoLoadedCheck); 2380 fprintf(stderr, "-%s (-%c):\n" 2381 " don't use system extension folders\n", 2382 kOptNameNoSystemExtensions, kOptNoSystemExtensions); 2383 fprintf(stderr, "\n"); 2384 2385 fprintf(stderr, "-%s (-%c):\n" 2386 " interactive mode\n", 2387 kOptNameInteractive, kOptInteractive); 2388 fprintf(stderr, "-%s (-%c):\n" 2389 " interactive mode for extension and all its dependencies\n", 2390 kOptNameInteractiveAll, kOptInteractiveAll); 2391 fprintf(stderr, "\n"); 2392 2393 fprintf(stderr, "-%s (-%c):\n" 2394 " load & start only; don't start matching\n", 2395 kOptNameLoadOnly, kOptLoadOnly); 2396 fprintf(stderr, "-%s (-%c):\n" 2397 " start matching only, by sending personalities; " 2398 "don't load executable\n", 2399 kOptNameMatchOnly, kOptMatchOnly); 2400 fprintf(stderr, "-%s (-%c):\n" 2401 " neither load nor start matching\n", 2402 kOptNameNoLoad, kOptNoLoad); 2403 fprintf(stderr, "-%s <directory> (-%c):\n" 2404 " write symbol files into <directory>\n", 2405 kOptNameSymbolsDirectory, kOptSymbolsDirectory); 2406 fprintf(stderr, "-%s <archname>:\n" 2407 " use architecture <archnaem>\n", 2408 kOptNameArch); 2409 fprintf(stderr, "-%s <kext_id@address> (-%c):\n" 2410 " <kext_id> is loaded at address (for symbol generation)\n", 2411 kOptNameAddress, kOptAddress); 2412 fprintf(stderr, "-%s (-%c):\n" 2413 " get load addresses for kexts from what's loaded " 2414 "(for symbol generation)\n", 2415 kOptNameUseKernelAddresses, kOptUseKernelAddresses); 2416 fprintf(stderr, "-%s <kernelFile> (-%c):\n" 2417 " link against <kernelFile> (default is /System/Library/Kernels/kernel)\n", 2418 kOptNameKernel, kOptKernel); 2419 fprintf(stderr, "\n"); 2420 2421 fprintf(stderr, "-%s (-%c):\n" 2422 " quiet mode: print no informational or error messages\n", 2423 kOptNameQuiet, kOptQuiet); 2424 fprintf(stderr, "-%s [ 0-6 | 0x<flags> ] (-%c):\n" 2425 " verbose mode; print info about analysis & loading\n", 2426 kOptNameVerbose, kOptVerbose); 2427 fprintf(stderr, "\n"); 2428 2429 fprintf(stderr, "-%s (-%c):\n" 2430 " perform all diagnostic tests and print a report on each kext\n", 2431 kOptNameTests, kOptTests); 2432 fprintf(stderr, "-%s (-%c):\n" 2433 " simulate safe boot mode for diagnostic tests\n", 2434 kOptNameSafeBoot, kOptSafeBoot); 2435 fprintf(stderr, "-%s (-%c):\n" 2436 " don't authenticate kexts (for use during development)\n", 2437 kOptNameNoAuthentication, kOptNoAuthentication); 2438 fprintf(stderr, "-%s (-%c):\n" 2439 " don't check dependencies when diagnosing with\n" 2440 " -%s & -%s (-%c%c)\n", 2441 kOptNameNoResolveDependencies, kOptNoResolveDependencies, 2442 kOptNameNoLoad, kOptNameTests, 2443 kOptNoLoad, kOptTests); 2444 fprintf(stderr, "\n"); 2445 2446 fprintf(stderr, "-%s (-%c): print this message and exit\n", 2447 kOptNameHelp, kOptHelp); 2448 fprintf(stderr, "\n"); 2449 2450 fprintf(stderr, "--: end of options\n"); 2451 return; 2452} 2453