1/* 2 * Copyright (c) 2000-2007 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 29/* 30 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 31 * support for mandatory and extensible security protections. This notice 32 * is included in support of clause 2.2 (b) of the Apple Public License, 33 * Version 2.0. 34 */ 35 36#include <libkern/c++/OSContainers.h> 37#include <IOKit/IOCatalogue.h> 38#include <IOKit/IOLib.h> 39#include <libsa/kext.h> 40#include <libsa/catalogue.h> 41 42extern "C" { 43#include <mach-o/kld.h> 44#include <libsa/vers_rsrc.h> 45#include <libsa/stdlib.h> 46#include <mach/kmod.h> 47#include <vm/vm_kern.h> 48#include <mach/kern_return.h> 49#include <mach-o/fat.h> 50#include <mach_loader.h> 51 52#include "kld_patch.h" 53#include "dgraph.h" 54#include "load.h" 55}; 56 57 58extern "C" { 59extern kern_return_t 60kmod_create_internal( 61 kmod_info_t *info, 62 kmod_t *id); 63 64extern kern_return_t 65kmod_destroy_internal(kmod_t id); 66 67extern kern_return_t 68kmod_start_or_stop( 69 kmod_t id, 70 int start, 71 kmod_args_t *data, 72 mach_msg_type_number_t *dataCount); 73 74extern kern_return_t kmod_retain(kmod_t id); 75extern kern_return_t kmod_release(kmod_t id); 76 77extern Boolean kmod_load_request(const char * moduleName, Boolean make_request); 78}; 79 80extern kmod_args_t 81get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen); 82 83extern struct mac_module_data *osdict_encode(OSDictionary *dict); 84 85#define DEBUG 86#ifdef DEBUG 87#define LOG_DELAY(x) IODelay((x) * 1000000) 88#define VTYELLOW "\033[33m" 89#define VTRESET "\033[0m" 90#else 91#define LOG_DELAY(x) 92#define VTYELLOW 93#define VTRESET 94#endif /* DEBUG */ 95 96 97#define KERNEL_PREFIX "com.apple.kernel" 98#define KPI_PREFIX "com.apple.kpi" 99 100 101/********************************************************************* 102* 103*********************************************************************/ 104static 105bool getKext( 106 const char * bundleid, 107 OSDictionary ** plist, 108 unsigned char ** code, 109 unsigned long * code_size, 110 bool * caller_owns_code) 111{ 112 bool result = true; 113 OSDictionary * extensionsDict; // don't release 114 OSDictionary * extDict; // don't release 115 OSDictionary * extPlist; // don't release 116 unsigned long code_size_local; 117 118 /* Get the dictionary of startup extensions. 119 * This is keyed by module name. 120 */ 121 extensionsDict = getStartupExtensions(); 122 if (!extensionsDict) { 123 IOLog("startup extensions dictionary is missing\n"); 124 result = false; 125 goto finish; 126 } 127 128 /* Get the requested extension's dictionary entry and its property 129 * list, containing module dependencies. 130 */ 131 extDict = OSDynamicCast(OSDictionary, 132 extensionsDict->getObject(bundleid)); 133 134 if (!extDict) { 135 IOLog("extension \"%s\" cannot be found\n", 136 bundleid); 137 result = false; 138 goto finish; 139 } 140 141 if (plist) { 142 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); 143 if (!extPlist) { 144 IOLog("extension \"%s\" has no info dictionary\n", 145 bundleid); 146 result = false; 147 goto finish; 148 } 149 *plist = extPlist; 150 } 151 152 if (code) { 153 154 /* If asking for code, the caller must provide a return buffer 155 * for ownership! 156 */ 157 if (!caller_owns_code) { 158 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n"); 159 result = false; 160 goto finish; 161 } 162 163 *code = 0; 164 if (code_size) { 165 *code_size = 0; 166 } 167 *caller_owns_code = false; 168 169 *code = (unsigned char *)kld_file_getaddr(bundleid, 170 (unsigned long *)&code_size_local); 171 if (*code) { 172 if (code_size) { 173 *code_size = code_size_local; 174 } 175 } else { 176 OSData * driverCode = 0; // release only if uncompressing! 177 178 driverCode = OSDynamicCast(OSData, extDict->getObject("code")); 179 if (driverCode) { 180 *code = (unsigned char *)driverCode->getBytesNoCopy(); 181 if (code_size) { 182 *code_size = driverCode->getLength(); 183 } 184 } else { // Look for compressed code and uncompress it 185 OSData * compressedCode = 0; 186 compressedCode = OSDynamicCast(OSData, 187 extDict->getObject("compressedCode")); 188 if (compressedCode) { 189 if (!uncompressModule(compressedCode, &driverCode)) { 190 IOLog("extension \"%s\": couldn't uncompress code\n", 191 bundleid); 192 result = false; 193 goto finish; 194 } 195 *caller_owns_code = true; 196 *code = (unsigned char *)driverCode->getBytesNoCopy(); 197 if (code_size) { 198 *code_size = driverCode->getLength(); 199 } 200 driverCode->release(); 201 } 202 } 203 } 204 } 205 206finish: 207 208 return result; 209} 210 211 212/********************************************************************* 213* 214*********************************************************************/ 215static 216bool verifyCompatibility(OSString * extName, OSString * requiredVersion) 217{ 218 OSDictionary * extPlist; // don't release 219 OSString * extVersion; // don't release 220 OSString * extCompatVersion; // don't release 221 VERS_version ext_version; 222 VERS_version ext_compat_version; 223 VERS_version required_version; 224 225 if (!getKext(extName->getCStringNoCopy(), &extPlist, NULL, NULL, NULL)) { 226 return false; 227 } 228 229 extVersion = OSDynamicCast(OSString, 230 extPlist->getObject("CFBundleVersion")); 231 if (!extVersion) { 232 IOLog("verifyCompatibility(): " 233 "Extension \"%s\" has no \"CFBundleVersion\" property.\n", 234 extName->getCStringNoCopy()); 235 return false; 236 } 237 238 extCompatVersion = OSDynamicCast(OSString, 239 extPlist->getObject("OSBundleCompatibleVersion")); 240 if (!extCompatVersion) { 241 IOLog("verifyCompatibility(): " 242 "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n", 243 extName->getCStringNoCopy()); 244 return false; 245 } 246 247 required_version = VERS_parse_string(requiredVersion->getCStringNoCopy()); 248 if (required_version < 0) { 249 IOLog("verifyCompatibility(): " 250 "Can't parse required version \"%s\" of dependency %s.\n", 251 requiredVersion->getCStringNoCopy(), 252 extName->getCStringNoCopy()); 253 return false; 254 } 255 ext_version = VERS_parse_string(extVersion->getCStringNoCopy()); 256 if (ext_version < 0) { 257 IOLog("verifyCompatibility(): " 258 "Can't parse version \"%s\" of dependency %s.\n", 259 extVersion->getCStringNoCopy(), 260 extName->getCStringNoCopy()); 261 return false; 262 } 263 ext_compat_version = VERS_parse_string(extCompatVersion->getCStringNoCopy()); 264 if (ext_compat_version < 0) { 265 IOLog("verifyCompatibility(): " 266 "Can't parse compatible version \"%s\" of dependency %s.\n", 267 extCompatVersion->getCStringNoCopy(), 268 extName->getCStringNoCopy()); 269 return false; 270 } 271 272 if (required_version > ext_version || required_version < ext_compat_version) { 273 return false; 274 } 275 276 return true; 277} 278 279/********************************************************************* 280*********************************************************************/ 281static 282bool kextIsDependency(const char * kext_name, char * is_kernel) { 283 bool result = true; 284 OSDictionary * extensionsDict = 0; // don't release 285 OSDictionary * extDict = 0; // don't release 286 OSDictionary * extPlist = 0; // don't release 287 OSBoolean * isKernelResourceObj = 0; // don't release 288 OSData * driverCode = 0; // don't release 289 OSData * compressedCode = 0; // don't release 290 291 if (is_kernel) { 292 *is_kernel = 0; 293 } 294 295 /* Get the dictionary of startup extensions. 296 * This is keyed by module name. 297 */ 298 extensionsDict = getStartupExtensions(); 299 if (!extensionsDict) { 300 IOLog("startup extensions dictionary is missing\n"); 301 result = false; 302 goto finish; 303 } 304 305 /* Get the requested extension's dictionary entry and its property 306 * list, containing module dependencies. 307 */ 308 extDict = OSDynamicCast(OSDictionary, 309 extensionsDict->getObject(kext_name)); 310 311 if (!extDict) { 312 IOLog("extension \"%s\" cannot be found\n", 313 kext_name); 314 result = false; 315 goto finish; 316 } 317 318 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); 319 if (!extPlist) { 320 IOLog("extension \"%s\" has no info dictionary\n", 321 kext_name); 322 result = false; 323 goto finish; 324 } 325 326 /* A kext that is a kernel component is still a dependency, as there 327 * are fake kmod entries for them. 328 */ 329 isKernelResourceObj = OSDynamicCast(OSBoolean, 330 extPlist->getObject("OSKernelResource")); 331 if (isKernelResourceObj && isKernelResourceObj->isTrue()) { 332 if (is_kernel) { 333 *is_kernel = 1; 334 } 335 } 336 337 driverCode = OSDynamicCast(OSData, extDict->getObject("code")); 338 compressedCode = OSDynamicCast(OSData, 339 extDict->getObject("compressedCode")); 340 341 /* A kernel component that has code represents a KPI. 342 */ 343 if ((driverCode || compressedCode) && is_kernel && *is_kernel) { 344 *is_kernel = 2; 345 } 346 347 if (!driverCode && !compressedCode && !isKernelResourceObj) { 348 result = false; 349 goto finish; 350 } 351 352finish: 353 354 return result; 355} 356 357/********************************************************************* 358*********************************************************************/ 359static bool 360addDependenciesForKext(OSDictionary * kextPlist, 361 OSArray * dependencyList, 362 OSString * trueParent, 363 Boolean skipKernelDependencies) 364{ 365 bool result = true; 366 bool hasDirectKernelDependency = false; 367 bool hasKernelStyleDependency = false; 368 bool hasKPIStyleDependency = false; 369 OSString * kextName = 0; // don't release 370 OSDictionary * libraries = 0; // don't release 371 OSCollectionIterator * keyIterator = 0; // must release 372 OSString * libraryName = 0; // don't release 373 OSString * dependentName = 0; // don't release 374 375 kextName = OSDynamicCast(OSString, 376 kextPlist->getObject("CFBundleIdentifier")); 377 if (!kextName) { 378 // XXX: Add log message 379 result = false; 380 goto finish; 381 } 382 383 libraries = OSDynamicCast(OSDictionary, 384 kextPlist->getObject("OSBundleLibraries")); 385 if (!libraries) { 386 result = true; 387 goto finish; 388 } 389 390 keyIterator = OSCollectionIterator::withCollection(libraries); 391 if (!keyIterator) { 392 // XXX: Add log message 393 result = false; 394 goto finish; 395 } 396 397 dependentName = trueParent ? trueParent : kextName; 398 399 while ( (libraryName = OSDynamicCast(OSString, 400 keyIterator->getNextObject())) ) { 401 402 OSString * libraryVersion = OSDynamicCast(OSString, 403 libraries->getObject(libraryName)); 404 if (!libraryVersion) { 405 // XXX: Add log message 406 result = false; 407 goto finish; 408 } 409 if (!verifyCompatibility(libraryName, libraryVersion)) { 410 result = false; 411 goto finish; 412 } else { 413 char is_kernel_component; 414 415 if (!kextIsDependency(libraryName->getCStringNoCopy(), 416 &is_kernel_component)) { 417 418 is_kernel_component = 0; 419 } 420 421 if (!skipKernelDependencies || !is_kernel_component) { 422 dependencyList->setObject(dependentName); 423 dependencyList->setObject(libraryName); 424 } 425 if (!hasDirectKernelDependency && is_kernel_component) { 426 hasDirectKernelDependency = true; 427 } 428 429 /* We already know from the kextIsDependency() call whether 430 * the dependency *itself* is kernel- or KPI-style, but since 431 * the declaration semantic is by bundle ID, we check that here 432 * instead. 433 */ 434 if (strncmp(libraryName->getCStringNoCopy(), 435 KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0) { 436 437 hasKernelStyleDependency = true; 438 439 } else if (strncmp(libraryName->getCStringNoCopy(), 440 KPI_PREFIX, strlen(KPI_PREFIX)) == 0) { 441 442 hasKPIStyleDependency = true; 443 } 444 } 445 } 446 447 if (!hasDirectKernelDependency) { 448 const OSSymbol * kernelName = 0; 449 450 /* a kext without any kernel dependency is assumed dependent on 6.0 */ 451 dependencyList->setObject(dependentName); 452 453 kernelName = OSSymbol::withCString("com.apple.kernel.libkern"); 454 if (!kernelName) { 455 // XXX: Add log message 456 result = false; 457 goto finish; 458 } 459 dependencyList->setObject(kernelName); 460 kernelName->release(); 461 462 IOLog("Extension \"%s\" has no explicit kernel dependency; using version 6.0.\n", 463 kextName->getCStringNoCopy()); 464 465 } else if (hasKernelStyleDependency && hasKPIStyleDependency) { 466 IOLog("Extension \"%s\" has immediate dependencies " 467 "on both com.apple.kernel and com.apple.kpi components; use only one style.\n", 468 kextName->getCStringNoCopy()); 469 } 470 471finish: 472 if (keyIterator) keyIterator->release(); 473 return result; 474} 475 476/********************************************************************* 477*********************************************************************/ 478static 479bool getVersionForKext(OSDictionary * kextPlist, char ** version) 480{ 481 OSString * kextName = 0; // don't release 482 OSString * kextVersion; // don't release 483 484 kextName = OSDynamicCast(OSString, 485 kextPlist->getObject("CFBundleIdentifier")); 486 if (!kextName) { 487 // XXX: Add log message 488 return false; 489 } 490 491 kextVersion = OSDynamicCast(OSString, 492 kextPlist->getObject("CFBundleVersion")); 493 if (!kextVersion) { 494 IOLog("getVersionForKext(): " 495 "Extension \"%s\" has no \"CFBundleVersion\" property.\n", 496 kextName->getCStringNoCopy()); 497 return false; 498 } 499 500 if (version) { 501 *version = (char *)kextVersion->getCStringNoCopy(); 502 } 503 504 return true; 505} 506 507/********************************************************************* 508*********************************************************************/ 509static 510bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph) 511{ 512 bool result = true; 513 OSDictionary * kextPlist = 0; // don't release 514 unsigned int index = 0; 515 OSArray * dependencyList = 0; // must release 516 unsigned char * code = 0; 517 unsigned long code_length = 0; 518 bool code_is_kmem = false; 519 char * kmod_vers = 0; // from plist, don't free 520 char is_kernel_component = 0; 521 dgraph_entry_t * dgraph_entry = 0; // don't free 522 dgraph_entry_t * dgraph_dependency = 0; // don't free 523 bool kext_is_dependency = true; 524 525#if CONFIG_MACF_KEXT 526 kmod_args_t user_data = 0; 527 mach_msg_type_number_t user_data_length; 528#endif 529 530 /***** 531 * Set up the root kmod. 532 */ 533 if (!getKext(kmod_name, &kextPlist, &code, &code_length, 534 &code_is_kmem)) { 535 IOLog("can't find extension %s\n", kmod_name); 536 result = false; 537 goto finish; 538 } 539 540 if (!kextIsDependency(kmod_name, &is_kernel_component)) { 541 IOLog("extension %s is not loadable\n", kmod_name); 542 result = false; 543 goto finish; 544 } 545 546 if (!getVersionForKext(kextPlist, &kmod_vers)) { 547 IOLog("can't get version for extension %s\n", kmod_name); 548 result = false; 549 goto finish; 550 } 551 552#if CONFIG_MACF_KEXT 553 // check kext for module data in the plist 554 user_data = get_module_data(kextPlist, &user_data_length); 555#endif 556 557 dgraph_entry = dgraph_add_dependent(dgraph, kmod_name, 558 code, code_length, code_is_kmem, 559#if CONFIG_MACF_KEXT 560 user_data, user_data_length, 561#endif 562 kmod_name, kmod_vers, 563 0 /* load_address not yet known */, is_kernel_component); 564 if (!dgraph_entry) { 565 IOLog("can't record %s in dependency graph\n", kmod_name); 566 result = false; 567 // kmem_alloc()ed code is freed in finish: block. 568 goto finish; 569 } 570 571 // pass ownership of code to kld patcher 572 if (code) { 573 if (kload_map_entry(dgraph_entry) != kload_error_none) { 574 IOLog("can't map %s in preparation for loading\n", kmod_name); 575 result = false; 576 // kmem_alloc()ed code is freed in finish: block. 577 goto finish; 578 } 579 } 580 // clear local record of code 581 code = 0; 582 code_length = 0; 583 code_is_kmem = false; 584 585 /***** 586 * Now handle all the dependencies. 587 */ 588 dependencyList = OSArray::withCapacity(5); 589 if (!dependencyList) { 590 IOLog("memory allocation failure\n"); 591 result = false; 592 goto finish; 593 } 594 595 index = 0; 596 if (!addDependenciesForKext(kextPlist, dependencyList, NULL, false)) { 597 IOLog("can't determine immediate dependencies for extension %s\n", 598 kmod_name); 599 result = false; 600 goto finish; 601 } 602 603 /* IMPORTANT: loop condition gets list count every time through, as the 604 * array CAN change each iteration. 605 */ 606 for (index = 0; index < dependencyList->getCount(); index += 2) { 607 OSString * dependentName = 0; 608 OSString * libraryName = 0; 609 const char * dependent_name = 0; 610 const char * library_name = 0; 611 612 /* 255 is an arbitrary limit. Multiplied by 2 because the dependency 613 * list is stocked with pairs (dependent -> dependency). 614 */ 615 if (index > (2 * 255)) { 616 IOLog("extension dependency graph ridiculously long, indicating a loop\n"); 617 result = false; 618 goto finish; 619 } 620 621 dependentName = OSDynamicCast(OSString, 622 dependencyList->getObject(index)); 623 libraryName = OSDynamicCast(OSString, 624 dependencyList->getObject(index + 1)); 625 626 if (!dependentName || !libraryName) { 627 IOLog("malformed dependency list\n"); 628 result = false; 629 goto finish; 630 } 631 632 dependent_name = dependentName->getCStringNoCopy(); 633 library_name = libraryName->getCStringNoCopy(); 634 635 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) { 636 637 IOLog("can't find extension %s\n", library_name); 638 result = false; 639 goto finish; 640 } 641 642 OSString * string = OSDynamicCast(OSString, 643 kextPlist->getObject("OSBundleSharedExecutableIdentifier")); 644 if (string) { 645 library_name = string->getCStringNoCopy(); 646 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) { 647 IOLog("can't find extension %s\n", library_name); 648 result = false; 649 goto finish; 650 } 651 } 652 653 kext_is_dependency = kextIsDependency(library_name, 654 &is_kernel_component); 655 656 if (kext_is_dependency) { 657 dgraph_entry = dgraph_find_dependent(dgraph, dependent_name); 658 if (!dgraph_entry) { 659 IOLog("internal error with dependency graph\n"); 660 LOG_DELAY(1); 661 result = false; 662 goto finish; 663 } 664 665 if (!getVersionForKext(kextPlist, &kmod_vers)) { 666 IOLog("can't get version for extension %s\n", library_name); 667 result = false; 668 goto finish; 669 } 670 671 /* It's okay for code to be zero, as for a pseudokext 672 * representing a kernel component. 673 */ 674 if (!getKext(library_name, NULL /* already got it */, 675 &code, &code_length, &code_is_kmem)) { 676 IOLog("can't find extension %s\n", library_name); 677 result = false; 678 goto finish; 679 } 680 681#if CONFIG_MACF_KEXT 682 // check kext for module data in the plist 683 // XXX - is this really needed? 684 user_data = get_module_data(kextPlist, &user_data_length); 685#endif 686 dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry, 687 library_name, code, code_length, code_is_kmem, 688#if CONFIG_MACF_KEXT 689 user_data, user_data_length, 690#endif 691 library_name, kmod_vers, 692 0 /* load_address not yet known */, is_kernel_component); 693 694 if (!dgraph_dependency) { 695 IOLog("can't record dependency %s -> %s\n", dependent_name, 696 library_name); 697 result = false; 698 // kmem_alloc()ed code is freed in finish: block. 699 goto finish; 700 } 701 702 // pass ownership of code to kld patcher 703 if (code) { 704 if (kload_map_entry(dgraph_dependency) != kload_error_none) { 705 IOLog("can't map %s in preparation for loading\n", library_name); 706 result = false; 707 // kmem_alloc()ed code is freed in finish: block. 708 goto finish; 709 } 710 } 711 // clear local record of code 712 code = 0; 713 code_length = 0; 714 code_is_kmem = false; 715 } 716 717 /* Now put the library's dependencies onto the pending set. 718 */ 719 if (!addDependenciesForKext(kextPlist, dependencyList, 720 kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) { 721 722 IOLog("can't determine immediate dependencies for extension %s\n", 723 library_name); 724 result = false; 725 goto finish; 726 } 727 } 728 729finish: 730 if (code && code_is_kmem) { 731 kmem_free(kernel_map, (unsigned int)code, code_length); 732 } 733 if (dependencyList) dependencyList->release(); 734 735#if CONFIG_MACF_KEXT 736 if (user_data && !result) { 737 vm_map_copy_discard((vm_map_copy_t)user_data); 738 } 739#endif 740 741 return result; 742} 743 744/********************************************************************* 745* This is the function that IOCatalogue calls in order to load a kmod. 746* It first checks whether the kmod is already loaded. If the kmod 747* isn't loaded, this function builds a dependency list and calls 748* load_kmod() repeatedly to guarantee that each dependency is in fact 749* loaded. 750*********************************************************************/ 751__private_extern__ 752kern_return_t load_kernel_extension(char * kmod_name) 753{ 754 kern_return_t result = KERN_SUCCESS; 755 kload_error load_result = kload_error_none; 756 dgraph_t dgraph; 757 bool free_dgraph = false; 758 kmod_info_t * kmod_info; 759 760// Put this in for lots of messages about kext loading. 761#if 0 762 kload_set_log_level(kload_log_level_load_details); 763#endif 764 765 /* See if the kmod is already loaded. 766 */ 767 if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) { 768 kfree(kmod_info, sizeof(kmod_info_t)); 769 return KERN_SUCCESS; 770 } 771 772 if (dgraph_init(&dgraph) != dgraph_valid) { 773 IOLog("Can't initialize dependency graph to load %s.\n", 774 kmod_name); 775 result = KERN_FAILURE; 776 goto finish; 777 } 778 779 free_dgraph = true; 780 if (!add_dependencies_for_kmod(kmod_name, &dgraph)) { 781 IOLog("Can't determine dependencies for %s.\n", 782 kmod_name); 783 result = KERN_FAILURE; 784 goto finish; 785 } 786 787 dgraph.root = dgraph_find_root(&dgraph); 788 789 if (!dgraph.root) { 790 IOLog("Dependency graph to load %s has no root.\n", 791 kmod_name); 792 result = KERN_FAILURE; 793 goto finish; 794 } 795 796 /* A kernel component is built in and need not be loaded. 797 */ 798 if (dgraph.root->is_kernel_component) { 799 result = KERN_SUCCESS; 800 goto finish; 801 } 802 803 dgraph_establish_load_order(&dgraph); 804 805 load_result = kload_load_dgraph(&dgraph); 806 if (load_result != kload_error_none && 807 load_result != kload_error_already_loaded) { 808 809 IOLog(VTYELLOW "Failed to load extension %s.\n" VTRESET, kmod_name); 810 811 result = KERN_FAILURE; 812 goto finish; 813 } 814 815finish: 816 817 if (free_dgraph) { 818 dgraph_free(&dgraph, 0 /* don't free dgraph itself */); 819 } 820 return result; 821} 822 823#define COM_APPLE "com.apple." 824 825__private_extern__ void 826load_security_extensions (void) 827{ 828 OSDictionary * extensionsDict = NULL; // don't release 829 OSCollectionIterator* keyIterator = NULL; // must release 830 OSString * key = NULL; // don't release 831 OSDictionary * extDict; // don't release 832 OSDictionary * extPlist; // don't release 833 OSBoolean * isSec = 0; // don't release 834 Boolean ret; 835 836 extensionsDict = getStartupExtensions(); 837 if (!extensionsDict) { 838 IOLog("startup extensions dictionary is missing\n"); 839 LOG_DELAY(1); 840 return; 841 } 842 843 keyIterator = OSCollectionIterator::withCollection(extensionsDict); 844 if (!keyIterator) { 845 IOLog("Error: Failed to allocate iterator for extensions.\n"); 846 LOG_DELAY(1); 847 return; 848 } 849 850 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) { 851 852 const char * bundle_id = key->getCStringNoCopy(); 853 854 /* Skip extensions whose bundle IDs don't start with "com.apple.". 855 */ 856 if (!bundle_id || (strncmp(bundle_id, COM_APPLE, strlen(COM_APPLE)) != 0)) { 857 continue; 858 } 859 860 extDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(key)); 861 if (!extDict) { 862 IOLog("extension \"%s\" cannot be found\n", 863 key->getCStringNoCopy()); 864 continue; 865 } 866 867 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); 868 if (!extPlist) { 869 IOLog("extension \"%s\" has no info dictionary\n", 870 key->getCStringNoCopy()); 871 continue; 872 } 873 874 isSec = OSDynamicCast(OSBoolean, 875 extPlist->getObject("AppleSecurityExtension")); 876 if (isSec && isSec->isTrue()) { 877 printf("Loading security extension %s\n", key->getCStringNoCopy()); 878 ret = kmod_load_request(key->getCStringNoCopy(), false); 879 if (!ret) { 880 load_kernel_extension((char *)key->getCStringNoCopy()); 881 } 882 } 883 } 884 885 if (keyIterator) 886 keyIterator->release(); 887 888 return; 889} 890