1/* 2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <CoreFoundation/CoreFoundation.h> 29#include <CoreFoundation/CFPriv.h> // for _CFRunLoopSetCurrent() 30#include <IOKit/IOKitLib.h> 31#include <IOKit/IOKitServer.h> 32#include <IOKit/IOCFURLAccess.h> 33#include <IOKit/IOCFUnserialize.h> 34#include <IOKit/storage/RAID/AppleRAIDUserLib.h> 35#include <IOKit/storage/CoreStorage/CoreStorageUserLib.h> 36#include <IOKit/kext/OSKext.h> 37#include <mach/mach.h> 38#include <mach/mach_host.h> 39#include <mach/mach_error.h> 40#include <mach-o/arch.h> 41#include <sys/types.h> 42#include <sys/sysctl.h> 43#include <libc.h> 44#include <servers/bootstrap.h> 45#include <signal.h> 46#include <sysexits.h> 47#include <sys/types.h> 48#include <sys/stat.h> 49#include <sys/sysctl.h> 50#include <sys/param.h> 51#include <sys/mount.h> 52#include <sys/resource.h> 53#include <unistd.h> 54#include <paths.h> 55 56#include <IOKit/kext/OSKext.h> 57#include <IOKit/kext/OSKextPrivate.h> 58#include <IOKit/kext/kextmanager_types.h> 59#include <bootfiles.h> 60 61#include "kextd_main.h" 62 63#include "kext_tools_util.h" 64#include "kextd_globals.h" 65#include "kextd_personalities.h" 66#include "kextd_mig_server.h" 67#include "kextd_request.h" 68#include "kextd_usernotification.h" 69#include "kextd_watchvol.h" 70 71#include "bootcaches.h" 72 73 74/******************************************************************************* 75* Globals set from invocation arguments (xxx - could use fewer globals). 76*******************************************************************************/ 77const char * progname = "(unknown)"; // don't free 78 79/******************************************************************************* 80*******************************************************************************/ 81struct option sOptInfo[] = { 82 { kOptNameHelp, no_argument, NULL, kOptHelp }, 83 { kOptNameNoCaches, no_argument, NULL, kOptNoCaches }, 84 { kOptNameDebug, no_argument, NULL, kOptDebug }, 85 86 { kOptNameQuiet, required_argument, NULL, kOptQuiet }, 87 { kOptNameVerbose, optional_argument, NULL, kOptVerbose }, 88 89 { NULL, 0, NULL, 0 } // sentinel to terminate list 90}; 91 92/******************************************************************************* 93* Globals created at run time. 94*******************************************************************************/ 95KextdArgs sToolArgs; 96CFArrayRef gRepositoryURLs = NULL; 97static CFArrayRef sAllKexts = NULL; 98 99Boolean gKernelRequestsPending = false; 100 101// all the following are released in setUpServer() 102static CFRunLoopTimerRef sReleaseKextsTimer = NULL; 103static CFRunLoopSourceRef sClientRequestRunLoopSource = NULL; 104static CFMachPortRef sKextdSignalMachPort = NULL; 105static mach_port_t sKextSignalMachPortMachPort = MACH_PORT_NULL; 106static CFRunLoopSourceRef sSignalRunLoopSource = NULL; 107 108const NXArchInfo * gKernelArchInfo = NULL; // do not free 109 110ExitStatus sKextdExitStatus = kKextdExitOK; 111 112/******************************************************************************* 113 * Static routines. 114 ******************************************************************************/ 115static void NoLoadSigFailureKextCallback( 116 CFNotificationCenterRef center, 117 void *observer, 118 CFStringRef name, 119 const void *object, 120 CFDictionaryRef userInfo ); 121static void InvalidSignedKextCallback( 122 CFNotificationCenterRef center, 123 void *observer, 124 CFStringRef name, 125 const void *object, 126 CFDictionaryRef userInfo ); 127static void RevokedCertKextCallback( 128 CFNotificationCenterRef center, 129 void *observer, 130 CFStringRef name, 131 const void *object, 132 CFDictionaryRef userInfo ); 133#if 0 // not yet 134static void UnsignedKextCallback( 135 CFNotificationCenterRef center, 136 void *observer, 137 CFStringRef name, 138 const void *object, 139 CFDictionaryRef userInfo ); 140#endif 141static void ExcludedKextCallback( 142 CFNotificationCenterRef center, 143 void *observer, 144 CFStringRef name, 145 const void *object, 146 CFDictionaryRef userInfo ); 147static void LoadedKextCallback( 148 CFNotificationCenterRef center, 149 void *observer, 150 CFStringRef name, 151 const void *object, 152 CFDictionaryRef userInfo ); 153 154/******************************************************************************* 155*******************************************************************************/ 156 157int main(int argc, char * const * argv) 158{ 159 char logSpecBuffer[16]; // enough for a 64-bit hex value 160 161 /***** 162 * Find out what my name is. 163 */ 164 progname = rindex(argv[0], '/'); 165 if (progname) { 166 progname++; // go past the '/' 167 } else { 168 progname = (char *)argv[0]; 169 } 170 171 OSKextSetLogOutputFunction(&tool_log); 172 173 /* Read command line and set a few other args that don't involve 174 * logging. (Syslog is opened up just below; we have to do that after 175 * parsing args, unfortunately.) 176 */ 177 sKextdExitStatus = readArgs(argc, argv, &sToolArgs); 178 if (sKextdExitStatus != EX_OK) { 179 goto finish; 180 } 181 182 /***** 183 * If not running in debug mode, then hook up to syslog. 184 */ 185 if (!sToolArgs.debugMode) { 186 tool_openlog("com.apple.kextd"); 187 } 188 189 /***** 190 * Set an environment variable that children (such as kextcache) 191 * can use to alter behavior (logging to syslog etc.). 192 */ 193 setenv("KEXTD_SPAWNED", "", /* overwrite */ 1); 194 snprintf(logSpecBuffer, sizeof(logSpecBuffer), "0x%x", 195 OSKextGetLogFilter(/* kernel? */ true)); 196 setenv("KEXT_LOG_FILTER_KERNEL", logSpecBuffer, /* overwrite */ 1); 197 snprintf(logSpecBuffer, sizeof(logSpecBuffer), "0x%x", 198 OSKextGetLogFilter(/* kernel? */ false)); 199 setenv("KEXT_LOG_FILTER_USER", logSpecBuffer, /* overwrite */ 1); 200 201 gRepositoryURLs = OSKextGetSystemExtensionsFolderURLs(); 202 if (!gRepositoryURLs) { 203 goto finish; 204 } 205 206 /* Get the running kernel arch for OSKext ops & cache creation. 207 */ 208 if (!gKernelArchInfo) { 209 gKernelArchInfo = OSKextGetRunningKernelArchitecture(); 210 if (!gKernelArchInfo) { 211 goto finish; 212 } 213 } 214 215 /* Check kernel first for safe boot, -x/-safe-boot is only for debugging. 216 */ 217 if (OSKextGetActualSafeBoot()) { 218 sToolArgs.safeBootMode = true; 219 } else if (sToolArgs.safeBootMode) { 220 OSKextSetSimulatedSafeBoot(true); 221 } 222 223 OSKextSetUsesCaches(sToolArgs.useRepositoryCaches); 224 225 OSKextSetRecordsDiagnostics(kOSKextDiagnosticsFlagNone); 226 readExtensions(); 227 228 sKextdExitStatus = setUpServer(&sToolArgs); 229 if (sKextdExitStatus != EX_OK) { 230 goto finish; 231 } 232 233 /* Tell the IOCatalogue that we are ready to service load requests. 234 */ 235 sendActiveToKernel(); 236 237 /***** 238 * Send the kext personalities to the kernel to trigger matching. 239 * Now that we have UUID dependency checks, the kernel shouldn't 240 * be able to hurt itself if kexts are out of date somewhere. 241 * 242 * sAllKexts gets cleaned up on the run loop so it's okay to use it here. 243 * 244 * We shouldn't need to reset the IOCatalogue here as it's startup time. 245 */ 246 if (kOSReturnSuccess != sendSystemKextPersonalitiesToKernel(sAllKexts, /* reset? */ false)) { 247 sKextdExitStatus = EX_OSERR; 248 goto finish; 249 } 250 251 /* Note: We are not going to try to update the OSBunderHelpers cache 252 * this early as it isn't needed until login. It should normally be 253 * up to date anyhow so let's keep startup I/O to an absolute minimum. 254 */ 255 256 /* Let IOCatalogue drop the artificial busy count on the registry 257 * now that it has personalities (which are sure to have naturally 258 * bumped the busy count). 259 */ 260 sendFinishedToKernel(); 261 262 // Start run loop 263 CFRunLoopRun(); 264 265 // Runloop is done - for restart performance exit asap 266 _exit(sKextdExitStatus); 267 268finish: 269#ifndef NO_CFUserNotification 270 stopMonitoringConsoleUser(); 271#endif /* ifndef NO_CFUserNotification */ 272 273 kextd_stop_volwatch(); // no-op if watch_volumes not called 274 275 if (sKextdExitStatus == kKextdExitHelp) { 276 sKextdExitStatus = kKextdExitOK; 277 } 278 279 exit(sKextdExitStatus); 280 281 return sKextdExitStatus; 282} 283 284 285#pragma mark Major Subroutines 286/******************************************************************************* 287* Major Subroutines 288*******************************************************************************/ 289ExitStatus 290readArgs( 291 int argc, 292 char * const * argv, 293 KextdArgs * toolArgs) 294{ 295 ExitStatus result = EX_USAGE; 296 ExitStatus scratchResult = EX_USAGE; 297 struct stat stat_buf; 298 int optchar; 299 int longindex; 300 CFStringRef scratchString = NULL; // must release 301 CFNumberRef scratchNumber = NULL; // must release 302 CFURLRef scratchURL = NULL; // must release 303 304 /* Kextd is not interested in log messages from the kernel, since 305 * kextd itself prints to the system log and this would duplicate 306 * things coming from the kernel. If you want more kernel kext 307 * logging, use the kextlog boot arg. 308 */ 309 OSKextSetLogFilter(kDefaultServiceLogFilter, /* kernel? */ false); 310 OSKextSetLogFilter(kOSKextLogSilentFilter, /* kernel? */ true); 311 312 bzero(toolArgs, sizeof(*toolArgs)); 313 toolArgs->debugMode = false; 314 toolArgs->useRepositoryCaches = true; 315 316 if (stat(kAppleSetupDonePath, &stat_buf) == -1 && errno == ENOENT) { 317 toolArgs->firstBoot = true; 318 } else { 319 toolArgs->firstBoot = false; 320 } 321 322 while ((optchar = getopt_long_only(argc, (char * const *)argv, 323 kOptChars, sOptInfo, &longindex)) != -1) { 324 325 SAFE_RELEASE_NULL(scratchString); 326 SAFE_RELEASE_NULL(scratchNumber); 327 SAFE_RELEASE_NULL(scratchURL); 328 329 switch (optchar) { 330 case kOptHelp: 331 usage(kUsageLevelFull); 332 result = kKextdExitHelp; 333 goto finish; 334 break; 335 336 case kOptNoCaches: 337 toolArgs->useRepositoryCaches = false; 338 break; 339 340 case kOptDebug: 341 toolArgs->debugMode = true; 342 break; 343 344 case kOptQuiet: 345 beQuiet(); 346 break; 347 348 case kOptVerbose: 349 /* Set the log flags by the command line, but then turn off 350 * the kernel bridge again. 351 */ 352 scratchResult = setLogFilterForOpt(argc, argv, /* forceOnFlags */ 0); 353 if (scratchResult != EX_OK) { 354 result = scratchResult; 355 goto finish; 356 } 357 OSKextSetLogFilter(kOSKextLogSilentFilter, /* kernel? */ true); 358 break; 359 360 case kOptSafeBoot: 361 toolArgs->safeBootMode = true; 362 toolArgs->useRepositoryCaches = false; // -x implies -c 363 break; 364 365 default: 366 /* getopt_long_only() prints an error message for us. */ 367 goto finish; 368 break; 369 370 } /* switch (optchar) */ 371 } /* while (optchar = getopt_long_only(...) */ 372 373 argc -= optind; 374 argv += optind; 375 376 if (argc) { 377 OSKextLog(/* kext */ NULL, 378 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 379 "Extra input on command line; %s....", argv[0]); 380 goto finish; 381 } 382 383 result = EX_OK; 384 385finish: 386 SAFE_RELEASE(scratchString); 387 SAFE_RELEASE(scratchNumber); 388 SAFE_RELEASE(scratchURL); 389 390 if (result == EX_USAGE) { 391 usage(kUsageLevelBrief); 392 } 393 return result; 394} 395 396/******************************************************************************* 397*******************************************************************************/ 398Boolean isNetboot(void) 399{ 400 Boolean result = false; 401 int netboot_mib_name[] = { CTL_KERN, KERN_NETBOOT }; 402 int netboot = 0; 403 size_t netboot_len = sizeof(netboot); 404 405 if (sysctl(netboot_mib_name, sizeof(netboot_mib_name) / sizeof(int), 406 &netboot, &netboot_len, NULL, 0) != 0) { 407 408 OSKextLog(/* kext */ NULL, 409 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 410 "Failed to detect netboot - %s.", strerror(errno)); 411 goto finish; 412 } 413 414 result = netboot ? true : false; 415 416finish: 417 return result; 418} 419 420/******************************************************************************* 421* Tell the IOCatalogue that kextd is ready to service kernel requests. 422*******************************************************************************/ 423void sendActiveToKernel(void) 424{ 425 kern_return_t kernelResult; 426 kernelResult = IOCatalogueSendData(kIOMasterPortDefault, 427 kIOCatalogKextdActive, 0, 0); 428 if (kernelResult != KERN_SUCCESS) { 429 OSKextLog(/* kext */ NULL, 430 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 431 "Failed to notify kernel that kextd is active - %s.", 432 safe_mach_error_string(kernelResult)); 433 } 434 435 return; 436} 437 438/******************************************************************************* 439* sendFinishedToKernel() 440* 441* Tell the IOCatalogue that kextd is about to enter its run loop to service 442* requests just generated by sending down all the personalities. 443* The IOCatalogue then drops its artificial busy count on the registry. 444*******************************************************************************/ 445void sendFinishedToKernel(void) 446{ 447 kern_return_t kernelResult; 448 kernelResult = IOCatalogueSendData(kIOMasterPortDefault, 449 kIOCatalogKextdFinishedLaunching, 0, 0); 450 if (kernelResult != KERN_SUCCESS) { 451 OSKextLog(/* kext */ NULL, 452 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 453 "Failed to notify kernel that kextd is finished launching - %s.", 454 safe_mach_error_string(kernelResult)); 455 } 456 457 return; 458} 459 460/******************************************************************************* 461* setUpServer() 462*******************************************************************************/ 463ExitStatus setUpServer(KextdArgs * toolArgs) 464{ 465 ExitStatus result = EX_OSERR; 466 kern_return_t kernelResult = KERN_SUCCESS; 467 unsigned int sourcePriority = 1; 468 CFMachPortRef kextdMachPort = NULL; // must release 469 mach_port_limits_t limits; // queue limit for signal-handler port 470 mach_port_t servicePort; 471 472 /* Check in with the bootstrap services. 473 */ 474 kernelResult = bootstrap_check_in(bootstrap_port, 475 KEXTD_SERVER_NAME, &servicePort); 476 477 if (kernelResult != BOOTSTRAP_SUCCESS) { 478 OSKextLog(/* kext */ NULL, 479 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogIPCFlag, 480 "Failed server check-in - %s", bootstrap_strerror(kernelResult)); 481 exit(EX_OSERR); 482 } 483 484 /* Initialize the run loop so we can start adding sources. 485 */ 486 if (!CFRunLoopGetCurrent()) { 487 OSKextLog(/* kext */ NULL, 488 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 489 "Failed to create run loop."); 490 goto finish; 491 } 492 493 /***** 494 * Add the runloop sources in decreasing priority (increasing "order"). 495 * Signals are handled first, followed by kernel requests, and then by 496 * client requests. It's important that each source have a distinct 497 * priority; sharing them causes unpredictable behavior with the runloop. 498 * Note: CFRunLoop.h, however, says 'order' should generally be 0 for all. 499 */ 500 501 kextdMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, 502 servicePort, kextd_mach_port_callback, /* CFMachPortContext */ NULL, 503 /* shouldFreeInfo? */ NULL); 504 sClientRequestRunLoopSource = CFMachPortCreateRunLoopSource( 505 kCFAllocatorDefault, kextdMachPort, sourcePriority++); 506 if (!sClientRequestRunLoopSource) { 507 OSKextLog(/* kext */ NULL, 508 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 509 "Failed to create client request run loop source."); 510 goto finish; 511 } 512 CFRunLoopAddSource(CFRunLoopGetCurrent(), sClientRequestRunLoopSource, 513 kCFRunLoopDefaultMode); 514 515 // 5519500: kextd_watch_volumes now holds off on updates on its own 516 if (kextd_watch_volumes(sourcePriority++)) { 517 goto finish; 518 } 519 520 sKextdSignalMachPort = CFMachPortCreate(kCFAllocatorDefault, 521 handleSignalInRunloop, NULL, NULL); 522 if (!sKextdSignalMachPort) { 523 OSKextLog(/* kext */ NULL, 524 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 525 "Failed to create signal-handling Mach port."); 526 goto finish; 527 } 528 sKextSignalMachPortMachPort = CFMachPortGetPort(sKextdSignalMachPort); 529 limits.mpl_qlimit = 1; 530 kernelResult = mach_port_set_attributes(mach_task_self(), 531 sKextSignalMachPortMachPort, 532 MACH_PORT_LIMITS_INFO, 533 (mach_port_info_t)&limits, 534 MACH_PORT_LIMITS_INFO_COUNT); 535 if (kernelResult != KERN_SUCCESS) { 536 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 537 "Failed to set signal-handling port limits."); 538 } 539 sSignalRunLoopSource = CFMachPortCreateRunLoopSource( 540 kCFAllocatorDefault, sKextdSignalMachPort, sourcePriority++); 541 if (!sSignalRunLoopSource) { 542 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 543 "Failed to create signal-handling run loop source."); 544 goto finish; 545 } 546 CFRunLoopAddSource(CFRunLoopGetCurrent(), sSignalRunLoopSource, 547 kCFRunLoopDefaultMode); 548 549 /* Watch for RAID changes so we can forcibly update their boot partitions. 550 */ 551 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 552 NULL, // const void *observer 553 updateRAIDSet, 554 CFSTR(kAppleRAIDNotificationSetChanged), 555 NULL, // const void *object 556 CFNotificationSuspensionBehaviorHold); 557 kernelResult = AppleRAIDEnableNotifications(); 558 if (kernelResult != KERN_SUCCESS) { 559 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 560 "Failed to register for RAID notifications."); 561 } 562 563 /* Watch for CoreStorage changes so we can update their boot partitions. 564 */ 565 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 566 NULL, // const void *observer 567 updateCoreStorageVolume, 568 CFSTR(kCoreStorageNotificationLVGChanged), 569 NULL, // const void *object 570 CFNotificationSuspensionBehaviorHold); 571 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 572 NULL, // const void *observer 573 updateCoreStorageVolume, 574 CFSTR(kCoreStorageNotificationVolumeChanged), 575 NULL, // const void *object 576 CFNotificationSuspensionBehaviorHold); 577 kernelResult = CoreStorageEnableNotifications(); 578 if (kernelResult != KERN_SUCCESS) { 579 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 580 "Failed to register for CoreStorage Volume notifications."); 581 } 582 583 /* Sign up to receive notifications when nonsigned kexts are found. We 584 * currently get messages from kextcache, kextload and kextutil. 585 */ 586 CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), 587 NULL, 588 NoLoadSigFailureKextCallback, 589 CFSTR("No Load Kext Notification"), 590 NULL, 591 CFNotificationSuspensionBehaviorDeliverImmediately); 592 593 /* Sign up to receive notifications when invalid signed kexts are found. We 594 * currently get messages from kextcache, kextload and kextutil. 595 */ 596 CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), 597 NULL, 598 InvalidSignedKextCallback, 599 CFSTR("Invalid Signature Kext Notification"), 600 NULL, 601 CFNotificationSuspensionBehaviorDeliverImmediately); 602 603 /* Sign up to receive notifications when kexts are found on the exclude 604 * list. We currently get messages from kextcache, kextload and kextutil. 605 */ 606 CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), 607 NULL, 608 ExcludedKextCallback, 609 CFSTR("Excluded Kext Notification"), 610 NULL, 611 CFNotificationSuspensionBehaviorDeliverImmediately); 612 613 /* Sign up to receive notifications when kexts with revoked certs are 614 * found. We currently get messages from kextcache, kextload and kextutil. 615 */ 616 CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), 617 NULL, 618 RevokedCertKextCallback, 619 CFSTR("Revoked Cert Kext Notification"), 620 NULL, 621 CFNotificationSuspensionBehaviorDeliverImmediately); 622 623#if 0 // not yet 624 /* Sign up to receive notifications when unisgned kexts are found. We 625 * currently get messages from kextcache, kextload and kextutil. 626 */ 627 CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), 628 NULL, 629 UnsignedKextCallback, 630 CFSTR("Unsigned Kext Notification"), 631 NULL, 632 CFNotificationSuspensionBehaviorDeliverImmediately); 633#endif 634 635 /* Sign up to receive notifications when kexts are loaded. 636 * We currently get messages from kextcache, kextload and kextutil. 637 */ 638 CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), 639 NULL, 640 LoadedKextCallback, 641 CFSTR("Loaded Kext Notification"), 642 NULL, 643 CFNotificationSuspensionBehaviorDeliverImmediately); 644 645 646#ifndef NO_CFUserNotification 647 result = startMonitoringConsoleUser(toolArgs, &sourcePriority); 648 if (result != EX_OK) { 649 goto finish; 650 } 651#endif /* ifndef NO_CFUserNotification */ 652 653 signal(SIGHUP, handleSignal); 654 signal(SIGTERM, handleSignal); 655 signal(SIGCHLD, handleSignal); 656 657 result = EX_OK; 658 659finish: 660 SAFE_RELEASE(sClientRequestRunLoopSource); 661 SAFE_RELEASE(sKextdSignalMachPort); 662 SAFE_RELEASE(sSignalRunLoopSource); 663 SAFE_RELEASE(kextdMachPort); 664 665 return result; 666} 667 668#include "security.h" 669 670/****************************************************************************** 671 * NoLoadSigFailureKextCallback() CFNotificationCenter posts from kextcache, 672 * kextload and kextutil enter here. 673 ******************************************************************************/ 674void NoLoadSigFailureKextCallback(CFNotificationCenterRef center, 675 void *observer, 676 CFStringRef name, 677 const void *object, 678 CFDictionaryRef userInfo) 679{ 680 if (userInfo) { 681 /* synchronize access to our plist file */ 682 CFRetain(userInfo); 683 dispatch_async(dispatch_get_main_queue(), ^ { 684 writeKextAlertPlist(userInfo, NO_LOAD_KEXT_ALERT); 685 }); 686 } 687 688 return; 689} 690 691/****************************************************************************** 692 * RevokedCertKextCallback() CFNotificationCenter posts from kextcache, 693 * kextload and kextutil enter here. 694 ******************************************************************************/ 695void RevokedCertKextCallback(CFNotificationCenterRef center, 696 void *observer, 697 CFStringRef name, 698 const void *object, 699 CFDictionaryRef userInfo) 700{ 701 if (userInfo) { 702 /* synchronize access to our plist file */ 703 CFRetain(userInfo); 704 dispatch_async(dispatch_get_main_queue(), ^ { 705 sendRevokedCertAlert(userInfo); 706 }); 707 } 708 709 return; 710} 711 712#if 0 // not yet 713/****************************************************************************** 714 * UnsignedKextCallback() CFNotificationCenter posts from kextcache, 715 * kextload and kextutil enter here. 716 ******************************************************************************/ 717void UnsignedKextCallback(CFNotificationCenterRef center, 718 void *observer, 719 CFStringRef name, 720 const void *object, 721 CFDictionaryRef userInfo) 722{ 723 if (userInfo) { 724 /* synchronize access to our plist file */ 725 CFRetain(userInfo); 726 dispatch_async(dispatch_get_main_queue(), ^ { 727 writeKextAlertPlist(userInfo, UNSIGNED_KEXT_ALERT); 728 }); 729 } 730 731 return; 732} 733#endif 734 735/****************************************************************************** 736 * InvalidSignedKextCallback() CFNotificationCenter posts from kextcache, 737 * kextload and kextutil enter here. 738 ******************************************************************************/ 739void InvalidSignedKextCallback(CFNotificationCenterRef center, 740 void *observer, 741 CFStringRef name, 742 const void *object, 743 CFDictionaryRef userInfo) 744{ 745 if (userInfo) { 746 /* synchronize access to our plist file */ 747 CFRetain(userInfo); 748 dispatch_async(dispatch_get_main_queue(), ^ { 749 writeKextAlertPlist(userInfo, INVALID_SIGNATURE_KEXT_ALERT); 750 }); 751 } 752 753 return; 754} 755 756/****************************************************************************** 757 * ExcludedKextCallback() CFNotificationCenter posts from kextcache, kextload 758 * and kextutil enter here. 759 ******************************************************************************/ 760void ExcludedKextCallback(CFNotificationCenterRef center, 761 void *observer, 762 CFStringRef name, 763 const void *object, 764 CFDictionaryRef userInfo) 765{ 766 if (userInfo) { 767 /* synchronize access to our plist file */ 768 CFRetain(userInfo); 769 dispatch_async(dispatch_get_main_queue(), ^ { 770 writeKextAlertPlist(userInfo, EXCLUDED_KEXT_ALERT); 771 }); 772 } 773 774 return; 775} 776 777/****************************************************************************** 778 * LoadedKextCallback() CFNotificationCenter posts from kextcache, kextload 779 * and kextutil enter here. Used for message tracing of kext loads. 780 ******************************************************************************/ 781void LoadedKextCallback(CFNotificationCenterRef center, 782 void *observer, 783 CFStringRef name, 784 const void *object, 785 CFDictionaryRef userInfo) 786{ 787 if (userInfo) { 788 CFArrayRef myValue; 789 myValue = CFDictionaryGetValue(userInfo, CFSTR("KextArrayKey")); 790 791 if (myValue && CFGetTypeID(myValue) == CFArrayGetTypeID()) { 792 /* synchronize access to our plist file */ 793 CFRetain(myValue); 794 dispatch_async(dispatch_get_main_queue(), ^ { 795 writeKextLoadPlist(myValue); 796 }); 797 } 798 } 799 800 return; 801} 802 803/****************************************************************************** 804* isBootRootActive() checks for the booter hint 805******************************************************************************/ 806bool isBootRootActive(void) 807{ 808 int result = false; 809 io_service_t chosen = 0; // must IOObjectRelease() 810 CFTypeRef bootrootProp = 0; // must CFRelease() 811 812 chosen = IORegistryEntryFromPath(kIOMasterPortDefault, 813 "IODeviceTree:/chosen"); 814 if (!chosen) { 815 goto finish; 816 } 817 818 bootrootProp = IORegistryEntryCreateCFProperty( 819 chosen, CFSTR(kBootRootActiveKey), kCFAllocatorDefault, 820 0 /* options */); 821 822 /* Mere presence of the property indicates that we are 823 * boot!=root, type and value are irrelevant. 824 */ 825 if (bootrootProp) { 826 result = true; 827 } 828 829finish: 830 if (chosen) IOObjectRelease(chosen); 831 SAFE_RELEASE(bootrootProp); 832 return result; 833} 834 835 836/******************************************************************************* 837* On receiving a SIGHUP or SIGTERM, the daemon sends a Mach message to the 838* signal port, causing the run loop handler function rescanExtensions() to be 839* called on the main thread. 840* 841* IMPORTANT: This is a UNIX signal handler, so no allocating or any other unsafe 842* calls. Sending a hand-rolled Mach message off the stack is okay. 843*******************************************************************************/ 844void handleSignal(int signum) 845{ 846 kextd_mach_msg_signal_t msg; 847 848 msg.signum = signum; 849 850 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 851 msg.header.msgh_size = sizeof(msg.header); 852 msg.header.msgh_remote_port = sKextSignalMachPortMachPort; 853 msg.header.msgh_local_port = MACH_PORT_NULL; 854 msg.header.msgh_id = 0; 855 856 (void) mach_msg( 857 &msg.header, /* msg */ 858 MACH_SEND_MSG | MACH_SEND_TIMEOUT, /* options */ 859 sizeof(msg), /* send_size */ 860 0, /* rcv_size */ 861 MACH_PORT_NULL, /* rcv_name */ 862 0, /* timeout */ 863 MACH_PORT_NULL); /* notify */ 864 865 return; 866} 867 868/******************************************************************************* 869*******************************************************************************/ 870void handleSignalInRunloop( 871 CFMachPortRef port, 872 void * msg, 873 CFIndex size, 874 void * info) 875{ 876 kextd_mach_msg_signal_t * signal_msg = (kextd_mach_msg_signal_t *)msg; 877 int signum = signal_msg->signum; 878 879 if (signum == SIGHUP) { 880 rescanExtensions(); 881 } else if (signum == SIGTERM) { 882 CFRunLoopStop(CFRunLoopGetCurrent()); 883 sKextdExitStatus = kKextdExitSigterm; 884 } else if (signum == SIGCHLD) { 885 pid_t child_pid = -1; 886 int child_status = 0; 887 888 /* Reap all spawned child processes that have exited. 889 */ 890 do { 891 child_pid = waitpid(-1 /* any child */, &child_status, WNOHANG); 892 if (child_pid == -1) { 893 if (errno != ECHILD) { 894 OSKextLog(/* kext */ NULL, 895 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 896 "Error %s waiting on child processes.", 897 strerror(errno)); 898 } 899 } else if (child_pid > 0) { 900 OSKextLogSpec logSpec; 901 902 // EX_SOFTWARE generally means kextcache called 903 // _kextmanager_unlock_volume which logs the error 904 if (WEXITSTATUS(child_status)==0 || child_status==EX_SOFTWARE) { 905 logSpec = kOSKextLogDetailLevel; 906 } else { 907 logSpec = kOSKextLogErrorLevel; 908 } 909 OSKextLog(/* kext */ NULL, logSpec, 910 "async child pid %d exited with status %d", 911 child_pid, WEXITSTATUS(child_status)); 912 } 913 } while (child_pid > 0); 914 915 } 916 917 return; 918} 919 920/******************************************************************************* 921 * This function reads the extensions if necessary. Note support for multiple 922 * extensions directories. 923 * 924 * This function does not update personalities in the kernel or update any 925 * caches other than those the OSKext library updates in the course of reading 926 * the extensions. We have a notify thread on the extensions folders that does 927 * that, with a slight delay. 928 *******************************************************************************/ 929void readExtensions(void) 930{ 931 static struct timeval lastModTime = {0,0}; 932 static struct timeval lastAccessTime = {0,0}; 933 struct timeval tempTimes[2]; 934 ExitStatus result = EX_SOFTWARE; 935 936 /* If getLatestTimesFromCFURLArray fails for any of the extensions 937 * directories we will force reading in all the kexts. Otherwise we only 938 * read in all the kexts if any of the extensions directories have been 939 * modified. The first time we're called we will save off the latest mod 940 * time and reread (which is fine since we have not read in any kexts yet). 941 */ 942 result = getLatestTimesFromCFURLArray(gRepositoryURLs, 943 tempTimes); 944 if (result != EX_OK) { 945 OSKextLog(/* kext */ NULL, 946 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 947 "Failed to stat extensions folders (%s); rereading.", 948 strerror(errno)); 949 950 /* force reading all extensions */ 951 releaseExtensions(/* timer */ NULL, /* context */ NULL); 952 } 953 954 if (result == EX_OK && timercmp(&lastModTime, &tempTimes[1], !=)) { 955 lastAccessTime.tv_sec = tempTimes[0].tv_sec; 956 lastAccessTime.tv_usec = tempTimes[0].tv_usec; 957 lastModTime.tv_sec = tempTimes[1].tv_sec; 958 lastModTime.tv_usec = tempTimes[1].tv_usec; 959 960 releaseExtensions(/* timer */ NULL, /* context */ NULL); 961 } 962 963 if (!sAllKexts && gRepositoryURLs) { 964 OSKextLog(/* kext */ NULL, 965 kOSKextLogProgressLevel | kOSKextLogGeneralFlag, 966 "Reading extensions."); 967 sAllKexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault, 968 gRepositoryURLs); 969 } 970 scheduleReleaseExtensions(); 971 return; 972} 973 974/******************************************************************************* 975*******************************************************************************/ 976void scheduleReleaseExtensions(void) 977{ 978 OSKextLog(/* kext */ NULL, 979 kOSKextLogProgressLevel | kOSKextLogGeneralFlag, 980 "%scheduling release of all kexts.", sReleaseKextsTimer ? "Res" : "S"); 981 982 if (sReleaseKextsTimer) { 983 CFRunLoopTimerInvalidate(sReleaseKextsTimer); 984 SAFE_RELEASE_NULL(sReleaseKextsTimer); 985 } 986 sReleaseKextsTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, 987 CFAbsoluteTimeGetCurrent() + kReleaseKextsDelay, /* interval */ 0, 988 /* flags */ 0, /* order */ 0, &releaseExtensions, /* context */ NULL); 989 if (!sReleaseKextsTimer) { 990 OSKextLogMemError(); 991 goto finish; 992 } 993 CFRunLoopAddTimer(CFRunLoopGetCurrent(), sReleaseKextsTimer, 994 kCFRunLoopDefaultMode); 995 996finish: 997 return; 998} 999 1000/******************************************************************************* 1001*******************************************************************************/ 1002void releaseExtensions( 1003 CFRunLoopTimerRef timer, 1004 void * context __unused) 1005{ 1006 OSKextLog(/* kext */ NULL, 1007 kOSKextLogProgressLevel | kOSKextLogGeneralFlag, 1008 "Releasing all kexts."); 1009 1010 if (timer == sReleaseKextsTimer) { 1011 SAFE_RELEASE_NULL(sReleaseKextsTimer); 1012 } 1013 SAFE_RELEASE_NULL(sAllKexts); 1014 1015 return; 1016} 1017 1018/******************************************************************************* 1019*******************************************************************************/ 1020void rescanExtensions(void) 1021{ 1022 OSKextLog(/* kext */ NULL, 1023 kOSKextLogBasicLevel | kOSKextLogGeneralFlag, 1024 "Rescanning kernel extensions."); 1025 1026#ifndef NO_CFUserNotification 1027 resetUserNotifications(/* dismissAlert */ false); 1028#endif /* ifndef NO_CFUserNotification */ 1029 1030 releaseExtensions(/* timer */ NULL, /* context */ NULL); 1031 readExtensions(); 1032 1033 // need to trigger check_rebuild (in watchvol.c) for mkext, etc 1034 // perhaps via mach message to the notification port 1035 // should we let it handle the ResetAllRepos? 1036 1037 // xxx Should we exit if this fails? 1038 sendSystemKextPersonalitiesToKernel(sAllKexts, /* reset? */ TRUE); 1039 1040 /* Update the loginwindow prop/value cache. 1041 * We just read it and don't use the values; this causes 1042 * the caches to be updated if necessary. 1043 */ 1044 readSystemKextPropertyValues(CFSTR(kOSBundleHelperKey), 1045 gKernelArchInfo, /* forceUpdate? */ true, /* values */ NULL); 1046 1047 return; 1048} 1049 1050/******************************************************************************* 1051*******************************************************************************/ 1052void usage(UsageLevel usageLevel) 1053{ 1054 fprintf(stderr, 1055 "usage: %s [-c] [-d] [-f] [-h] [-j] [-r dir] ... [-v [1-6]] [-x]\n", 1056 progname); 1057 1058 if (usageLevel == kUsageLevelBrief) { 1059 goto finish; 1060 } 1061 1062 fprintf(stderr, "\n"); 1063 1064 fprintf(stderr, "Arguments and options\n"); 1065 fprintf(stderr, "\n"); 1066 1067 fprintf(stderr, "-%s (-%c):\n" 1068 " don't use repository caches; scan repository folders\n", 1069 kOptNameNoCaches, kOptNoCaches); 1070 fprintf(stderr, "-%s (-%c):\n" 1071 " run in debug mode (log to stderr)\n", 1072 kOptNameDebug, kOptDebug); 1073 fprintf(stderr, "-%s (-%c):\n" 1074 " run as if the system is in safe boot mode\n", 1075 kOptNameSafeBoot, kOptSafeBoot); 1076 fprintf(stderr, "\n"); 1077 1078 fprintf(stderr, "-%s (-%c):\n" 1079 " quiet mode: log/print no informational or error messages\n", 1080 kOptNameQuiet, kOptQuiet); 1081 fprintf(stderr, "-%s [ 0-6 | 0x<flags> ] (-%c):\n" 1082 " verbose mode; log/print info about analysis & loading\n", 1083 kOptNameVerbose, kOptVerbose); 1084 fprintf(stderr, "\n"); 1085 1086 fprintf(stderr, "-%s (-%c): print this message and exit\n", 1087 kOptNameHelp, kOptHelp); 1088 1089finish: 1090 return; 1091} 1092