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