2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSContainers.h>
29 #include <IOKit/IOCatalogue.h>
30 #include <IOKit/IOLib.h>
31 #include <libsa/kext.h>
32 #include <libsa/catalogue.h>
35 #include <mach-o/kld.h>
36 #include <libsa/vers_rsrc.h>
37 #include <libsa/stdlib.h>
38 #include <mach/kmod.h>
39 #include <vm/vm_kern.h>
40 #include <mach/kern_return.h>
41 #include <mach-o/fat.h>
42 #include <mach_loader.h>
44 #include "kld_patch.h"
57 kmod_destroy_internal(kmod_t id
);
64 mach_msg_type_number_t
*dataCount
);
66 extern kern_return_t
kmod_retain(kmod_t id
);
67 extern kern_return_t
kmod_release(kmod_t id
);
69 extern void flush_dcache(vm_offset_t addr
, unsigned cnt
, int phys
);
70 extern void invalidate_icache(vm_offset_t addr
, unsigned cnt
, int phys
);
75 #define LOG_DELAY(x) IODelay((x) * 1000000)
76 #define VTYELLOW "\033[33m"
77 #define VTRESET "\033[0m"
84 /*********************************************************************
86 *********************************************************************/
89 const char * bundleid
,
90 OSDictionary
** plist
,
91 unsigned char ** code
,
92 unsigned long * code_size
,
93 bool * caller_owns_code
)
96 OSDictionary
* extensionsDict
; // don't release
97 OSDictionary
* extDict
; // don't release
98 OSDictionary
* extPlist
; // don't release
99 unsigned long code_size_local
;
101 /* Get the dictionary of startup extensions.
102 * This is keyed by module name.
104 extensionsDict
= getStartupExtensions();
105 if (!extensionsDict
) {
106 IOLog("startup extensions dictionary is missing\n");
111 /* Get the requested extension's dictionary entry and its property
112 * list, containing module dependencies.
114 extDict
= OSDynamicCast(OSDictionary
,
115 extensionsDict
->getObject(bundleid
));
118 IOLog("extension \"%s\" cannot be found\n",
125 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
127 IOLog("extension \"%s\" has no info dictionary\n",
137 /* If asking for code, the caller must provide a return buffer
140 if (!caller_owns_code
) {
141 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
150 *caller_owns_code
= false;
152 *code
= (unsigned char *)kld_file_getaddr(bundleid
,
153 (long *)&code_size_local
);
156 *code_size
= code_size_local
;
159 OSData
* driverCode
= 0; // release only if uncompressing!
161 driverCode
= OSDynamicCast(OSData
, extDict
->getObject("code"));
163 *code
= (unsigned char *)driverCode
->getBytesNoCopy();
165 *code_size
= driverCode
->getLength();
167 } else { // Look for compressed code and uncompress it
168 OSData
* compressedCode
= 0;
169 compressedCode
= OSDynamicCast(OSData
,
170 extDict
->getObject("compressedCode"));
171 if (compressedCode
) {
172 if (!uncompressModule(compressedCode
, &driverCode
)) {
173 IOLog("extension \"%s\": couldn't uncompress code\n",
179 *caller_owns_code
= true;
180 *code
= (unsigned char *)driverCode
->getBytesNoCopy();
182 *code_size
= driverCode
->getLength();
184 driverCode
->release();
196 /*********************************************************************
198 *********************************************************************/
200 bool verifyCompatibility(OSString
* extName
, OSString
* requiredVersion
)
202 OSDictionary
* extPlist
; // don't release
203 OSString
* extVersion
; // don't release
204 OSString
* extCompatVersion
; // don't release
205 VERS_version ext_version
;
206 VERS_version ext_compat_version
;
207 VERS_version required_version
;
209 if (!getKext(extName
->getCStringNoCopy(), &extPlist
, NULL
, NULL
, NULL
)) {
213 extVersion
= OSDynamicCast(OSString
,
214 extPlist
->getObject("CFBundleVersion"));
216 IOLog("verifyCompatibility(): "
217 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
218 extName
->getCStringNoCopy());
222 extCompatVersion
= OSDynamicCast(OSString
,
223 extPlist
->getObject("OSBundleCompatibleVersion"));
224 if (!extCompatVersion
) {
225 IOLog("verifyCompatibility(): "
226 "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
227 extName
->getCStringNoCopy());
231 required_version
= VERS_parse_string(requiredVersion
->getCStringNoCopy());
232 if (required_version
< 0) {
233 IOLog("verifyCompatibility(): "
234 "Can't parse required version \"%s\" of dependency %s.\n",
235 requiredVersion
->getCStringNoCopy(),
236 extName
->getCStringNoCopy());
239 ext_version
= VERS_parse_string(extVersion
->getCStringNoCopy());
240 if (ext_version
< 0) {
241 IOLog("verifyCompatibility(): "
242 "Can't parse version \"%s\" of dependency %s.\n",
243 extVersion
->getCStringNoCopy(),
244 extName
->getCStringNoCopy());
247 ext_compat_version
= VERS_parse_string(extCompatVersion
->getCStringNoCopy());
248 if (ext_compat_version
< 0) {
249 IOLog("verifyCompatibility(): "
250 "Can't parse compatible version \"%s\" of dependency %s.\n",
251 extCompatVersion
->getCStringNoCopy(),
252 extName
->getCStringNoCopy());
256 if (required_version
> ext_version
|| required_version
< ext_compat_version
) {
263 /*********************************************************************
264 *********************************************************************/
266 bool kextIsDependency(const char * kext_name
, char * is_kernel
) {
268 OSDictionary
* extensionsDict
= 0; // don't release
269 OSDictionary
* extDict
= 0; // don't release
270 OSDictionary
* extPlist
= 0; // don't release
271 OSBoolean
* isKernelResourceObj
= 0; // don't release
272 OSData
* driverCode
= 0; // don't release
273 OSData
* compressedCode
= 0; // don't release
279 /* Get the dictionary of startup extensions.
280 * This is keyed by module name.
282 extensionsDict
= getStartupExtensions();
283 if (!extensionsDict
) {
284 IOLog("startup extensions dictionary is missing\n");
289 /* Get the requested extension's dictionary entry and its property
290 * list, containing module dependencies.
292 extDict
= OSDynamicCast(OSDictionary
,
293 extensionsDict
->getObject(kext_name
));
296 IOLog("extension \"%s\" cannot be found\n",
302 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
304 IOLog("extension \"%s\" has no info dictionary\n",
310 /* A kext that is a kernel component is still a dependency, as there
311 * are fake kmod entries for them.
313 isKernelResourceObj
= OSDynamicCast(OSBoolean
,
314 extPlist
->getObject("OSKernelResource"));
315 if (isKernelResourceObj
&& isKernelResourceObj
->isTrue()) {
321 driverCode
= OSDynamicCast(OSData
, extDict
->getObject("code"));
322 compressedCode
= OSDynamicCast(OSData
,
323 extDict
->getObject("compressedCode"));
325 if ((driverCode
|| compressedCode
) && is_kernel
&& *is_kernel
) {
329 if (!driverCode
&& !compressedCode
&& !isKernelResourceObj
) {
339 /*********************************************************************
340 *********************************************************************/
342 figureDependenciesForKext(OSDictionary
* kextPlist
,
343 OSDictionary
* dependencies
,
344 OSString
* trueParent
,
345 Boolean skipKernelDependencies
)
348 bool hasDirectKernelDependency
= false;
349 OSString
* kextName
= 0; // don't release
350 OSDictionary
* libraries
= 0; // don't release
351 OSCollectionIterator
* keyIterator
= 0; // must release
352 OSString
* libraryName
= 0; // don't release
354 kextName
= OSDynamicCast(OSString
,
355 kextPlist
->getObject("CFBundleIdentifier"));
357 // XXX: Add log message
362 libraries
= OSDynamicCast(OSDictionary
,
363 kextPlist
->getObject("OSBundleLibraries"));
369 keyIterator
= OSCollectionIterator::withCollection(libraries
);
371 // XXX: Add log message
376 while ( (libraryName
= OSDynamicCast(OSString
,
377 keyIterator
->getNextObject())) ) {
379 OSString
* libraryVersion
= OSDynamicCast(OSString
,
380 libraries
->getObject(libraryName
));
381 if (!libraryVersion
) {
382 // XXX: Add log message
386 if (!verifyCompatibility(libraryName
, libraryVersion
)) {
390 char is_kernel_component
;
392 if (!kextIsDependency(libraryName
->getCStringNoCopy(), &is_kernel_component
))
393 is_kernel_component
= false;
395 if (!skipKernelDependencies
|| !is_kernel_component
) {
396 dependencies
->setObject(libraryName
,
397 trueParent
? trueParent
: kextName
);
399 if (!hasDirectKernelDependency
&& is_kernel_component
) {
400 hasDirectKernelDependency
= true;
404 if (!hasDirectKernelDependency
) {
405 /* a kext without any kernel dependency is assumed dependent on 6.0 */
406 dependencies
->setObject("com.apple.kernel.libkern",
407 trueParent
? trueParent
: kextName
);
408 IOLog("Extension \"%s\" has no kernel dependency.\n",
409 kextName
->getCStringNoCopy());
413 if (keyIterator
) keyIterator
->release();
417 /*********************************************************************
418 *********************************************************************/
420 bool getVersionForKext(OSDictionary
* kextPlist
, char ** version
)
422 OSString
* kextName
= 0; // don't release
423 OSString
* kextVersion
; // don't release
425 kextName
= OSDynamicCast(OSString
,
426 kextPlist
->getObject("CFBundleIdentifier"));
428 // XXX: Add log message
432 kextVersion
= OSDynamicCast(OSString
,
433 kextPlist
->getObject("CFBundleVersion"));
435 IOLog("getVersionForKext(): "
436 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
437 kextName
->getCStringNoCopy());
442 *version
= (char *)kextVersion
->getCStringNoCopy();
448 /*********************************************************************
449 *********************************************************************/
451 bool add_dependencies_for_kmod(const char * kmod_name
, dgraph_t
* dgraph
)
454 OSDictionary
* kextPlist
= 0; // don't release
455 OSDictionary
* workingDependencies
= 0; // must release
456 OSDictionary
* pendingDependencies
= 0; // must release
457 OSDictionary
* swapDict
= 0; // don't release
458 OSString
* dependentName
= 0; // don't release
459 const char * dependent_name
= 0; // don't free
460 OSString
* libraryName
= 0; // don't release
461 const char * library_name
= 0; // don't free
462 OSCollectionIterator
* dependencyIterator
= 0; // must release
463 unsigned char * code
= 0;
464 unsigned long code_length
= 0;
465 bool code_is_kmem
= false;
466 char * kmod_vers
= 0; // from plist, don't free
467 char is_kernel_component
= false;
468 dgraph_entry_t
* dgraph_entry
= 0; // don't free
469 dgraph_entry_t
* dgraph_dependency
= 0; // don't free
470 unsigned int graph_depth
= 0;
471 bool kext_is_dependency
= true;
473 if (!getKext(kmod_name
, &kextPlist
, &code
, &code_length
,
475 IOLog("can't find extension %s\n", kmod_name
);
480 if (!kextIsDependency(kmod_name
, &is_kernel_component
)) {
481 IOLog("extension %s is not loadable\n", kmod_name
);
486 if (!getVersionForKext(kextPlist
, &kmod_vers
)) {
487 IOLog("can't get version for extension %s\n", kmod_name
);
492 dgraph_entry
= dgraph_add_dependent(dgraph
, kmod_name
,
493 code
, code_length
, code_is_kmem
,
494 kmod_name
, kmod_vers
,
495 0 /* load_address not yet known */, is_kernel_component
);
497 IOLog("can't record %s in dependency graph\n", kmod_name
);
499 // kmem_alloc()ed code is freed in finish: block.
503 // pass ownership of code to kld patcher
506 if (kload_map_entry(dgraph_entry
) != kload_error_none
) {
507 IOLog("can't map %s in preparation for loading\n", kmod_name
);
509 // kmem_alloc()ed code is freed in finish: block.
513 // clear local record of code
516 code_is_kmem
= false;
518 workingDependencies
= OSDictionary::withCapacity(5);
519 if (!workingDependencies
) {
520 IOLog("memory allocation failure\n");
525 pendingDependencies
= OSDictionary::withCapacity(5);
526 if (!pendingDependencies
) {
527 IOLog("memory allocation failure\n");
532 if (!figureDependenciesForKext(kextPlist
, workingDependencies
, NULL
, false)) {
533 IOLog("can't determine immediate dependencies for extension %s\n",
540 while (workingDependencies
->getCount()) {
541 if (graph_depth
> 255) {
542 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
547 if (dependencyIterator
) {
548 dependencyIterator
->release();
549 dependencyIterator
= 0;
552 dependencyIterator
= OSCollectionIterator::withCollection(
553 workingDependencies
);
554 if (!dependencyIterator
) {
555 IOLog("memory allocation failure\n");
560 while ( (libraryName
=
561 OSDynamicCast(OSString
, dependencyIterator
->getNextObject())) ) {
563 library_name
= libraryName
->getCStringNoCopy();
565 dependentName
= OSDynamicCast(OSString
,
566 workingDependencies
->getObject(libraryName
));
568 dependent_name
= dependentName
->getCStringNoCopy();
570 if (!getKext(library_name
, &kextPlist
, NULL
, NULL
, NULL
)) {
571 IOLog("can't find extension %s\n", library_name
);
577 if ((string
= OSDynamicCast(OSString
,
578 kextPlist
->getObject("OSBundleSharedExecutableIdentifier"))))
580 library_name
= string
->getCStringNoCopy();
581 if (!getKext(library_name
, &kextPlist
, NULL
, NULL
, NULL
)) {
582 IOLog("can't find extension %s\n", library_name
);
588 kext_is_dependency
= kextIsDependency(library_name
,
589 &is_kernel_component
);
591 if (!kext_is_dependency
) {
593 /* For binaryless kexts, add a new pending dependency from the
594 * original dependent onto the dependencies of the current,
595 * binaryless, dependency.
597 if (!figureDependenciesForKext(kextPlist
, pendingDependencies
,
598 dependentName
, true)) {
600 IOLog("can't determine immediate dependencies for extension %s\n",
607 dgraph_entry
= dgraph_find_dependent(dgraph
, dependent_name
);
609 IOLog("internal error with dependency graph\n");
615 if (!getVersionForKext(kextPlist
, &kmod_vers
)) {
616 IOLog("can't get version for extension %s\n", library_name
);
621 /* It's okay for code to be zero, as for a pseudokext
622 * representing a kernel component.
624 if (!getKext(library_name
, NULL
/* already got it */,
625 &code
, &code_length
, &code_is_kmem
)) {
626 IOLog("can't find extension %s\n", library_name
);
631 dgraph_dependency
= dgraph_add_dependency(dgraph
, dgraph_entry
,
632 library_name
, code
, code_length
, code_is_kmem
,
633 library_name
, kmod_vers
,
634 0 /* load_address not yet known */, is_kernel_component
);
636 if (!dgraph_dependency
) {
637 IOLog("can't record dependency %s -> %s\n", dependent_name
,
640 // kmem_alloc()ed code is freed in finish: block.
644 // pass ownership of code to kld patcher
646 if (kload_map_entry(dgraph_dependency
) != kload_error_none
) {
647 IOLog("can't map %s in preparation for loading\n", library_name
);
649 // kmem_alloc()ed code is freed in finish: block.
653 // clear local record of code
656 code_is_kmem
= false;
659 /* Now put the library's dependencies onto the pending set.
661 if (!figureDependenciesForKext(kextPlist
, pendingDependencies
,
664 IOLog("can't determine immediate dependencies for extension %s\n",
671 dependencyIterator
->release();
672 dependencyIterator
= 0;
674 workingDependencies
->flushCollection();
675 swapDict
= workingDependencies
;
676 workingDependencies
= pendingDependencies
;
677 pendingDependencies
= swapDict
;
682 if (code
&& code_is_kmem
) {
683 kmem_free(kernel_map
, (unsigned int)code
, code_length
);
685 if (workingDependencies
) workingDependencies
->release();
686 if (pendingDependencies
) pendingDependencies
->release();
687 if (dependencyIterator
) dependencyIterator
->release();
691 /*********************************************************************
692 * This is the function that IOCatalogue calls in order to load a kmod.
693 * It first checks whether the kmod is already loaded. If the kmod
694 * isn't loaded, this function builds a dependency list and calls
695 * load_kmod() repeatedly to guarantee that each dependency is in fact
697 *********************************************************************/
699 kern_return_t
load_kernel_extension(char * kmod_name
)
701 kern_return_t result
= KERN_SUCCESS
;
702 kload_error load_result
= kload_error_none
;
704 bool free_dgraph
= false;
705 kmod_info_t
* kmod_info
;
707 // Put this in for lots of messages about kext loading.
709 kload_set_log_level(kload_log_level_load_details
);
712 /* See if the kmod is already loaded.
714 if ((kmod_info
= kmod_lookupbyname_locked(kmod_name
))) {
715 kfree((vm_offset_t
) kmod_info
, sizeof(kmod_info_t
));
719 if (dgraph_init(&dgraph
) != dgraph_valid
) {
720 IOLog("Can't initialize dependency graph to load %s.\n",
722 result
= KERN_FAILURE
;
727 if (!add_dependencies_for_kmod(kmod_name
, &dgraph
)) {
728 IOLog("Can't determine dependencies for %s.\n",
730 result
= KERN_FAILURE
;
734 dgraph
.root
= dgraph_find_root(&dgraph
);
737 IOLog("Dependency graph to load %s has no root.\n",
739 result
= KERN_FAILURE
;
743 /* A kernel component is built in and need not be loaded.
745 if (dgraph
.root
->is_kernel_component
) {
746 result
= KERN_SUCCESS
;
750 dgraph_establish_load_order(&dgraph
);
752 load_result
= kload_load_dgraph(&dgraph
);
753 if (load_result
!= kload_error_none
&&
754 load_result
!= kload_error_already_loaded
) {
756 IOLog(VTYELLOW
"Failed to load extension %s.\n" VTRESET
, kmod_name
);
758 result
= KERN_FAILURE
;
765 dgraph_free(&dgraph
, 0 /* don't free dgraph itself */);